@m_seki の

I like ruby tooから引っ越し

forkしたら回収されるオブジェクトが欲しい

forkしたあと、DRbのコネクションプールが残ってる(つながったまま)のは嫌そう

execしてくれれば閉じられるけど...

いただいたPRは次のdRubyのメソッド呼び出しをトリガーにしてpidを見てcloseするものでした。dRubyRMIしないとずっと残ったままなので、それは多分ダメ。

fork後のThreadの仕様

たしかサブスレッド(forkしたスレッド以外?)はすべて終了する。これを使えば、fork時に回収されるようになりそう。

アクターがマイブームのころにスレッドをオブジェクト風にする素振りをしていたけど、まさか実用品として復活することになるとは!
今回は即座に(同期して)メソッドの結果が欲しいので、そのような同期メカニズムを書いて、その中にスレッドを作るようにした。
(つまり今回は並行性ではなく、forkのタイミングで消えてもらう情報を管理するためにスレッドを使う)

class ThreadObject
    include MonitorMixin

    def initialize(&blk)
      super()
      @wait_ev = new_cond
      @req_ev = new_cond
      @res_ev = new_cond
      @status = :wait
      @req = nil
      @res = nil
      @thread = Thread.new(self, &blk)
    end

    def alive?
      @thread.alive?
    end

    def method_missing(msg, *arg, &blk)
      synchronize do
        @wait_ev.wait_until { @status == :wait }
        @req = [msg] + arg
        @status = :req
        @req_ev.broadcast
        @res_ev.wait_until { @status == :res }
        value = @res
        @req = @res = nil
        @status = :wait
        @wait_ev.broadcast
        return value
      end
    end

    def _execute()
      synchronize do
        @req_ev.wait_until { @status == :req }
        @res = yield(@req)
        @status = :res
        @res_ev.signal
      end   
    end
  end

サーバーに相当する処理をブロックで渡す。method_missingの情報が渡るので、それっぽっく処理する。
スレッドにHashを管理してもらって、そこにFileオブジェクトを預ける。forkするとGCのタイミングでcloseされるようになる。

  proxy = ThreadObject.new do |queue|
    dict = {}
    while true
      queue._execute do |message|
        case(message[0])
        when :[]= then
          dict[message[1]] = message[2]
        when :[] then
          dict[message[1]]
        when :size
          dict.size
        else
          nil
        end
      end
    end
  end

  20.times do |n|
    Thread.new(n) do |x|
      proxy[x] = File.open("rdv.rb")
    end
  end

  sleep 0.01
  p proxy.size

  system("lsof -p #{$$} | wc -l")

  fork {
    system("lsof -p #{$$} | wc -l")
    GC.start # ここでcloseされて減る
    system("lsof -p #{$$} | wc -l")
  }

  sleep 10

drb.rb中のプールの管理はこんな感じ。take(uri)とstore(conn)の二つのメソッドを提供する。fork後にはGCされる。

    def self.make_pool
      ThreadObject.new do |queue|
        pool = []
        while true
          queue._execute do |message|
            case(message[0])
            when :take then
              remote_uri = message[1]
              conn = nil
              new_pool = []
              pool.each do |c|
                if conn.nil? and c.uri == remote_uri
                  conn = c if c.alive?
                else
                  new_pool.push c
                end
              end
              pool = new_pool
              conn
            when :store then
              conn = message[1]
              pool.unshift(conn)
              pool.pop.close while pool.size > POOL_SIZE
              conn
            else
              nil
            end
          end
        end
      end
    end
    @pool_proxy = make_pool

fork後にFDがどれくらい残るか確かめるgist

ThreadObjectを入れる前後でFDの増減の様子を調べたときのスクリプト。今日もらったPRはdRubyRMIするタイミングでcloseできるようになった。ThreadObject版はRMIしない場合でもGCが起こればcloseされるようになったので、ちょっとまし。

gist.github.com

ポケカのカードブロックが変更になるとのこと

ポケカのカードブロックが変更になり[A]のカードがレギュ落ちするぞ

www.pokemon-card.com

それはいいけど[A]のカードっていうのはどれなのさ!(公式サイトではまだそういう単位の検索ができないのだ)

どうする?

しょうがない。画像処理を使って、[A][B][C]を判定するのを作ろう!

GitHub - seki/pcg_abcd: Pokemon Card Game card block classifier

機械学習が流行っているので、それは使わずOpenCVのテンプレートマッチで実装することにしよう。

準備(追記)

パッケージ化する前に試したこと。

OpenCVのテンプレートマッチの誤差を比較して一番確からしいものを選ぶ作戦。

  1. カードの画像から[A][B][C]を切り出して正規化(色とかサイズとか)したものをテンプレートにする。(github見てね)
  2. 指定されたURLから画像をカードのダウンロードして、三種類のテンプレートとマッチさせる。
  3. 実験してみたところ、どのテンプレートもカードの同じ場所とマッチするが、スコア(デフォルトのアルゴリズムでは小さい方がより似ている)は正解のテンプレートと正解でないものの差がとても大きいこと確かめた。
  4. スコア順にソートして最小のものを採用することとする。
  5. なお、XYなどのマークのないカードはスコアがとても大きいので、大きすぎるものは例外とすることにした。
私の環境の問題...

OpenCVのテンプレートマッチを使えばできそう!
でもmacOSOpenCVのgem作るのめんどくさい...そういえばば前にそういうDockerイメージを作ってたぞ。なんという幸運。

https://cloud.docker.com/repository/docker/mseki/ruby-opencv

そういう問題がない人は...普通にRubyとGemでやればできるぞ。出来上がったのはこれ。

require 'opencv'
require 'drb'
require 'open-uri'

class ABCandD
  def initialize
    @template = %w(A B C).map {|a| [a, OpenCV::IplImage.load("/data/#{a}.png")]}
  end

  def zap(uri)
    img = load_img(uri)
    result = @template.map { |pair|
      [img.match_template(pair[1]).min_max_loc[0], pair[0]]
    }.sort_by {|ary| ary.first}
    result[0]
  end

  def classify(uri)
    score, klass = zap(uri)
    raise "Error too large #{score}" if score > 5000000.0
    klass
  end

  def load_img(uri)
    data = URI.open(uri).read
    OpenCV::IplImage.decode(data)
  end
end

if __FILE__ == $0
  if uri = ARGV.shift
    DRb.start_service(uri, ABCandD.new)
    DRb.thread.join
  end
end

Dockerの場合はビルドしてから実行。

$ docker build -t mseki/pcg-abcd:0.1 .
$ docker run -p 50151:50151 mseki/pcg-abcd:0.1

ポート番号の50151はdRubyのサービスのポートだよ。

別の端末からirbなどで質問すれば答えてくれる。カードの画像のURLを渡そう。

$ irb -r drb
irb(main):001:0> sorter = DRbObject.new_with_uri 'druby://localhost:50151'
irb(main):002:0> sorter.classify "https://www.pokemon-card.com/assets/images/card_images/large/SM12/037304_P_REKKUUZAGX.jpg"
=> "B"
サンムーン世代のトレーナーズのカードブロック一覧だよ

手持ちのメモ(mysqlにメモしてある。もしかしたら抜けがあるかも)にあったトレーナーズを判定させてみた。

irb(main):038:0> pp it; nil
[["あなぬけのヒモ", "グッズ", "A"],
 ["いちゃもんスプレー", "グッズ", "A"],
 ["おおきいマラサダ", "グッズ", "A"],
 ["きずぐすり", "グッズ", "A"],
 ["のぞきみレッドカード", "グッズ", "A"],
 ["ふしぎなアメ", "グッズ", "A"],
 ["まんたんのくすり", "グッズ", "A"],
 ["むしよけスプレー", "グッズ", "A"],
 ["アクアパッチ", "グッズ", "A"],
 ["エネくじ", "グッズ", "A"],
 ["エネルギーつけかえ", "グッズ", "A"],
 ["エネルギーリサイクル", "グッズ", "A"],
 ["エネルギー回収", "グッズ", "A"],
 ["カウンターキャッチャー", "グッズ", "A"],
 ["クラッシュハンマー", "グッズ", "A"],
 ["スーパーボール", "グッズ", "A"],
 ["スーパーポケモン回収", "グッズ", "A"],
 ["タイマーボール", "グッズ", "A"],
 ["ダメージムーバー", "グッズ", "A"],
 ["ネストボール", "グッズ", "A"],
 ["ハイパーボール", "グッズ", "A"],
 ["フィールドブロアー", "グッズ", "A"],
 ["ポケモンいれかえ", "グッズ", "A"],
 ["ポケモンキャッチャー", "グッズ", "A"],
 ["マルチつけかえ", "グッズ", "A"],
 ["モンスターボール", "グッズ", "A"],
 ["レスキュータンカ", "グッズ", "A"],
 ["ロトム図鑑", "グッズ", "A"],
 ["ロトム図鑑 ポケファインダーモード", "グッズ", "A"],
 ["勝利の勲章", "グッズ", "A"],
 ["改造ハンマー", "グッズ", "A"],
 ["殿堂の書", "グッズ", "A"],
 ["やまおとこ", "サポート", "A"],
 ["アセロラ", "サポート", "A"],
 ["イリマ", "サポート", "A"],
 ["カキ", "サポート", "A"],
 ["ククイ博士", "サポート", "A"],
 ["グズマ", "サポート", "A"],
 ["グラジオ", "サポート", "A"],
 ["サトシのゆうじょう", "サポート", "A"],
 ["スイレン", "サポート", "A"],
 ["スカル団のしたっぱ", "サポート", "A"],
 ["ハウ", "サポート", "A"],
 ["ハラ", "サポート", "A"],
 ["ビッケ", "サポート", "A"],
 ["プルメリ", "サポート", "A"],
 ["ポケモンブリーダー", "サポート", "A"],
 ["マオ", "サポート", "A"],
 ["マーマネ", "サポート", "A"],
 ["ライチ", "サポート", "A"],
 ["リーリエ", "サポート", "A"],
 ["ルザミーネ", "サポート", "A"],
 ["ロイヤルマスク", "サポート", "A"],
 ["ロケット団のいやがらせ", "サポート", "A"],
 ["せせらぎの丘", "スタジアム", "A"],
 ["エーテルパラダイス保護区", "スタジアム", "A"],
 ["チャンピオンズフェスティバル", "スタジアム", "A"],
 ["ポータウン", "スタジアム", "A"],
 ["ラナキラマウンテン", "スタジアム", "A"],
 ["喰いつくされた原野", "スタジアム", "A"],
 ["日輪の祭壇", "スタジアム", "A"],
 ["月輪の祭壇", "スタジアム", "A"],
 ["虚ろの海", "スタジアム", "A"],
 ["こだわりハチマキ", "ポケモンのどうぐ", "A"],
 ["じゃくてんほけん", "ポケモンのどうぐ", "A"],
 ["どくバリ", "ポケモンのどうぐ", "A"],
 ["ねがいのバトン", "ポケモンのどうぐ", "A"],
 ["エレクトロメモリ", "ポケモンのどうぐ", "A"],
 ["サイキックメモリ", "ポケモンのどうぐ", "A"],
 ["ダッシュポーチ", "ポケモンのどうぐ", "A"],
 ["ファイトメモリ", "ポケモンのどうぐ", "A"],
 ["ファイヤーメモリ", "ポケモンのどうぐ", "A"],
 ["ムキムキダンベル", "ポケモンのどうぐ", "A"],
 ["古代のクリスタル", "ポケモンのどうぐ", "A"],
 ["学習装置", "ポケモンのどうぐ", "A"],
 ["あとだしハンマー", "グッズ", "B"],
 ["いれかえフロート", "グッズ", "B"],
 ["おとりよせパッド", "グッズ", "B"],
 ["ともだちてちょう", "グッズ", "B"],
 ["ふっかつそう", "グッズ", "B"],
 ["ぼうけんのカバン", "グッズ", "B"],
 ["ウルトラボール", "グッズ", "B"],
 ["エスケープボード", "グッズ", "B"],
 ["エネポーター", "グッズ", "B"],
 ["エネルギースピナー", "グッズ", "B"],
 ["エネルギー循環装置", "グッズ", "B"],
 ["エレキチャージャー", "グッズ", "B"],
 ["エレキパワー", "グッズ", "B"],
 ["カスタムキャッチャー", "グッズ", "B"],
 ["ギリギリポーション", "グッズ", "B"],
 ["ダートじてんしゃ", "グッズ", "B"],
 ["デンジャラスドリル", "グッズ", "B"],
 ["ネットボール", "グッズ", "B"],
 ["ハンサムホイッスル", "グッズ", "B"],
 ["ビーストリング", "グッズ", "B"],
 ["フレンドボール", "グッズ", "B"],
 ["ポケナビ", "グッズ", "B"],
 ["ミステリートレジャー", "グッズ", "B"],
 ["ミックスハーブ", "グッズ", "B"],
 ["ミッシングクローバー", "グッズ", "B"],
 ["モーモーミルク", "グッズ", "B"],
 ["リターンラベル", "グッズ", "B"],
 ["ルアーボール", "グッズ", "B"],
 ["レインボーブラシ", "グッズ", "B"],
 ["ロストミキサー", "グッズ", "B"],
 ["化石発掘マップ", "グッズ", "B"],
 ["火打石", "グッズ", "B"],
 ["TVレポーター", "サポート", "B"],
 ["おじょうさま", "サポート", "B"],
 ["かんこうきゃく", "サポート", "B"],
 ["ぼんぐり職人", "サポート", "B"],
 ["アカギ", "サポート", "B"],
 ["アカネ", "サポート", "B"],
 ["ウツギ博士のレクチャー", "サポート", "B"],
 ["ウルトラ調査隊", "サポート", "B"],
 ["エーテル財団職員", "サポート", "B"],
 ["カツラの一発勝負", "サポート", "B"],
 ["カヒリ", "サポート", "B"],
 ["カルネ", "サポート", "B"],
 ["クチナシ", "サポート", "B"],
 ["ザオボー", "サポート", "B"],
 ["シロナ", "サポート", "B"],
 ["ジャッジマン", "サポート", "B"],
 ["ダイゴの決断", "サポート", "B"],
 ["デンジ", "サポート", "B"],
 ["ナタネ", "サポート", "B"],
 ["ナリヤ・オーキド", "サポート", "B"],
 ["ノボリとクダリ", "サポート", "B"],
 ["ハンサム", "サポート", "B"],
 ["ヒガナ", "サポート", "B"],
 ["フウとラン", "サポート", "B"],
 ["フラダリ", "サポート", "B"],
 ["ポケモンだいすきクラブ", "サポート", "B"],
 ["マキシ", "サポート", "B"],
 ["マサキのメンテナンス", "サポート", "B"],
 ["マツバ", "サポート", "B"],
 ["マツリカ", "サポート", "B"],
 ["マーズ", "サポート", "B"],
 ["ミカン", "サポート", "B"],
 ["モノマネむすめ", "サポート", "B"],
 ["ユリーカ", "サポート", "B"],
 ["ラジュルネ", "サポート", "B"],
 ["ラニュイ", "サポート", "B"],
 ["ルザミーネ", "サポート", "B"],
 ["ルスワール", "サポート", "B"],
 ["ルチア", "サポート", "B"],
 ["ルミタン", "サポート", "B"],
 ["ワタル", "サポート", "B"],
 ["地底探険隊", "サポート", "B"],
 ["釣り人", "サポート", "B"],
 ["そらのはしら", "スタジアム", "B"],
 ["ウルトラスペース", "スタジアム", "B"],
 ["サンダーマウンテン", "スタジアム", "B"],
 ["テンガン山", "スタジアム", "B"],
 ["ヒートファクトリー", "スタジアム", "B"],
 ["フラダリラボ", "スタジアム", "B"],
 ["ブラックマーケット", "スタジアム", "B"],
 ["プレイヤーズセレモニー", "スタジアム", "B"],
 ["ライフフォレスト", "スタジアム", "B"],
 ["ワンダーラビリンス", "スタジアム", "B"],
 ["ヴェラ火山公園", "スタジアム", "B"],
 ["戒めの祠", "スタジアム", "B"],
 ["こだわりメット", "ポケモンのどうぐ", "B"],
 ["のろいのおふだ", "ポケモンのどうぐ", "B"],
 ["ウォーターメモリ", "ポケモンのどうぐ", "B"],
 ["エスケープボード", "ポケモンのどうぐ", "B"],
 ["カウンターゲイン", "ポケモンのどうぐ", "B"],
 ["グラスメモリ", "ポケモンのどうぐ", "B"],
 ["ハッスルベルト", "ポケモンのどうぐ", "B"],
 ["フェアリーチャーム UB", "ポケモンのどうぐ", "B"],
 ["フェアリーチャームドラゴン", "ポケモンのどうぐ", "B"],
 ["フェアリーチャーム草", "ポケモンのどうぐ", "B"],
 ["フェアリーチャーム超", "ポケモンのどうぐ", "B"],
 ["フェアリーチャーム闘", "ポケモンのどうぐ", "B"],
 ["メタルゴーグル", "ポケモンのどうぐ", "B"],
 ["竜の鉤爪", "ポケモンのどうぐ", "B"],
 ["鋼鉄のフライパン", "ポケモンのどうぐ", "B"],
 ["びっくりボックス", "グッズ", "C"],
 ["やみのいし", "グッズ", "C"],
 ["グレートキャッチャー", "グッズ", "C"],
 ["グレートポーション", "グッズ", "C"],
 ["ザクザクピッケル", "グッズ", "C"],
 ["ジャッジマンホイッスル", "グッズ", "C"],
 ["スイレンのつりざお", "グッズ", "C"],
 ["スタジアムナビ", "グッズ", "C"],
 ["タッグコール", "グッズ", "C"],
 ["タッグスイッチ", "グッズ", "C"],
 ["プレシャスボール", "グッズ", "C"],
 ["ポケギア3.0", "グッズ", "C"],
 ["ポケモン通信", "グッズ", "C"],
 ["リセットスタンプ", "グッズ", "C"],
 ["炎の結晶", "グッズ", "C"],
 ["退化スプレーZ", "グッズ", "C"],
 ["電磁レーダー", "グッズ", "C"],
 ["Nの覚悟", "サポート", "C"],
 ["あばれる君", "サポート", "C"],
 ["かいじゅうマニア", "サポート", "C"],
 ["きとうし", "サポート", "C"],
 ["むしとりしょうねん", "サポート", "C"],
 ["アローラの仲間たち", "サポート", "C"],
 ["アンズ", "サポート", "C"],
 ["イツキ", "サポート", "C"],
 ["ウルトラフォレストのかみつかい", "サポート", "C"],
 ["エリカ", "サポート", "C"],
 ["エリカのおもてなし", "サポート", "C"],
 ["オーキド博士のセッティング", "サポート", "C"],
 ["カスミ&カンナ", "サポート", "C"],
 ["カスミのおねがい", "サポート", "C"],
 ["カスミのやる気", "サポート", "C"],
 ["カスミの水さばき", "サポート", "C"],
 ["カツラのクイズショー", "サポート", "C"],
 ["キョウの罠", "サポート", "C"],
 ["ギーマ", "サポート", "C"],
 ["グズマ&ハラ", "サポート", "C"],
 ["グリーンの戦略", "サポート", "C"],
 ["コーチトレーナー", "サポート", "C"],
 ["サカキの追放", "サポート", "C"],
 ["シロナ&カトレア", "サポート", "C"],
 ["ジュジュベ&ハチクマン", "サポート", "C"],
 ["タケシのガッツ", "サポート", "C"],
 ["タケシのトレーニング", "サポート", "C"],
 ["ナツメの暗示", "サポート", "C"],
 ["ハプウ", "サポート", "C"],
 ["ブルーの探索", "サポート", "C"],
 ["ホミカ", "サポート", "C"],
 ["ポケモンセンターのお姉さん", "サポート", "C"],
 ["マオ&スイレン", "サポート", "C"],
 ["マサキの解析", "サポート", "C"],
 ["マチスの作戦", "サポート", "C"],
 ["マーレイン", "サポート", "C"],
 ["ムサシとコジロウ", "サポート", "C"],
 ["メイ", "サポート", "C"],
 ["ヤーコン", "サポート", "C"],
 ["リーリエの全力", "サポート", "C"],
 ["レッド&グリーン", "サポート", "C"],
 ["レッドの挑戦", "サポート", "C"],
 ["ローラースケーター", "サポート", "C"],
 ["溶接工", "サポート", "C"],
 ["まどろみの森", "スタジアム", "C"],
 ["カスミのハナダシティジム", "スタジアム", "C"],
 ["シオンタウン", "スタジアム", "C"],
 ["タケシのニビシティジム", "スタジアム", "C"],
 ["ダストアイランド", "スタジアム", "C"],
 ["チャンピオンズフェスティバル", "スタジアム", "C"],
 ["トキワの森", "スタジアム", "C"],
 ["ナイトシティ", "スタジアム", "C"],
 ["ブリザードタウン", "スタジアム", "C"],
 ["ポケモンけんきゅうじょ", "スタジアム", "C"],
 ["巨大なカマド", "スタジアム", "C"],
 ["格闘道場", "スタジアム", "C"],
 ["混沌のうねり", "スタジアム", "C"],
 ["無人発電所", "スタジアム", "C"],
 ["Uターンボード", "ポケモンのどうぐ", "C"],
 ["くろおび", "ポケモンのどうぐ", "C"],
 ["しまめぐりのあかし", "ポケモンのどうぐ", "C"],
 ["にじいろのはな", "ポケモンのどうぐ", "C"],
 ["みみなりベル", "ポケモンのどうぐ", "C"],
 ["ジャイアントボム", "ポケモンのどうぐ", "C"],
 ["ドラゴンZ ドラゴンクロー", "ポケモンのどうぐ", "C"],
 ["ノーマルZ たいあたり", "ポケモンのどうぐ", "C"],
 ["ヒコウZ エアスラッシュ", "ポケモンのどうぐ", "C"],
 ["ビーストナイト", "ポケモンのどうぐ", "C"],
 ["ビーストブリンガー", "ポケモンのどうぐ", "C"],
 ["フェアリーチャーム 特性", "ポケモンのどうぐ", "C"],
 ["フェアリーチャーム 雷", "ポケモンのどうぐ", "C"],
 ["ムキムキパッド", "ポケモンのどうぐ", "C"],
 ["メタルコアバリア", "ポケモンのどうぐ", "C"],
 ["隠密フード", "ポケモンのどうぐ", "C"]]
あわせて買いたい

WiringPi-Ruby gemを動くようにした話(誰か引き取って

WiringPi-Ruby gemが3B+で動かなかったんだよ!

Raspberry Pi 3B+でWiringPi-Rubyが動かなかったので調べたんだが呪われていた。

おきたこと

環境はStretchってやつの最新にした3B+です。RubyでGPIO、SPIを利用した方のでwiringpi gemをインストール。
とあるAPI(wiringPiSetupGpio)を実行するとエラーでプロセスが終了してしまう。

期待した動き。

$ irb -r wiringpi
irb(main):001::0> Wiringpi.wiringPiSetupGpio
=> 0


実際の動き。

$ irb -r wiringpi
irb(main):001::0> Wiringpi.wiringPiSetupGpio
Unable to determine hardware version. I see: Hardware : BCM2835
- expecting BCM2708 or BCM2709.
..

調べた

検索するとライブラリの方を新しくすればいい(aptで新しいの入れろとかそういうの)とか、OSを古くすればいい、とか情報があったがどうも違う感じがする。
実際、wiriingPi(オリジナルのライブラリの方ね)のバージョンも新しい。しかもソースコードと違う文面のエラーが出てる。なんだこれ...。

んで、これはライブラリじゃなくてgemがおかしい気がする、と想像して調査。gem unpack wiringpiしてextconf.rbを見たところ、古いライブラリのソースコードが同梱されてた。うはー。なんで共有ライブラリをリンクしないんだよ。

それから、wiringPiのサイト読んでたらさー、今月初めの記事に「wiringPi – deprecated…」ってあったよ。

wiringPi – deprecated… | Wiring Pi

このgemも原因の一つになってたんじゃないか...

初fork、extconf.rb

数年間メンテナンスされてないみたいなので、forkしてみました。

https://github.com/seki/WiringPi-Ruby

extconf.rbを勘で修正して、ライブラリをリンクするようにしました。あと、SPIのところのバグ(RWでバッファの長さをstrlenしてるバグ)も直してcommitしてあります。
だれか引き取ってくれないかなあ。

あと、オリジナルのライブラリに入れ忘れている(ことがある)APIがあるそうなので、その場合にはその関数を呼ばないようにしてあります。

require 'mkmf'

$srcs = ['wiringpi_wrap.c']
$objs = $srcs.map{ |file| file.sub('.c','.o') }

have_library("rt", "shm_open")
have_library("wiringPi", "pinMode")
have_library("wiringPiDev", "lcd128x64clear")
if have_library("wiringPiDev", "softServoWrite")
  $defs << "-DHAVE_softServoWrite"
end

create_makefile('wiringpi/wiringpi')    

入れ方

git cloneしてから、

$ sudo gem uninstall wiringpi
$ gem build wiringpi
$ sudo gem install --local wiringpi-2.32.0.gem