http://mrubysearch.ongaeshi.me/
RubyKokubanを作るにあたってmrubyのソースやmgem(mrubyのRubyGemsみたいなやつ)に登録されたソースコードを簡単に読めるようにしたいなあ、と思い作ってみました。
一日一回レポジトリを最新に更新してインデックスの再構築を行っています。新しいmgemが追加された時は今の所手動で対応しています(そのうち自動化したい所です)。
自分が追加した(もしくは検索したい)mgemが追加されていない!って人はリクエスト頂ければ追加するので教えて下さい。 mgemじゃなくてもmrubyに関係がありそうなソースコードでしたら追加しますので是非。
※ 個人サイトのため突然停止したりするかもしれません、ご了承下さい。
使い方の例1 - "!"付きのメソッドはどうやってバインドするの?
例えばgsub!
のような!マークのついたメソッドはどうやってバインドするのか?を知りたいとします。mrubyでは メソッド名を文字列で渡す必要があるのでそこを手がかりにします。!"
で検索してみましょう(文字列の終端に引っかかることを期待しています)。
少し下に行くとswapcase!
関数をバインドしてる箇所が見つかりました。
mruby-string-ext/src/string.c#173
mrb_str_swapcase_bang
という関数名でバインドされていますね。!は _bangという名前でバインドされているようです。
他のライブラリではどうなっているか調べてみます。
'_bang' in root - mruby search
reverse!
-> mrb_ary_reverse_bangcapitalize!
-> mrb_str_capitalize_bang
も_bangという名前になっているので、よく使われているルールだと思ってよさそうです。
使い方の例2 - Cの関数内からyieldしたいのだけど
ブロック構文を使いたくなったので調べることに。おそらくeach
という名前のメソッドはブロック構文を使っているのでそれを探してみます。
'each mrb_define_' in root - mruby search
eachだけでも探せるけどより検索精度を上げるためにmrb_define_キーワードを重ねています。いくつか関数を探してmrb_leapmotion_devicelist_each
関数を詳しく読む事に決めました。
mruby-leapmotion/src/Leap.cpp#1067
static mrb_value mrb_leapmotion_devicelist_each(mrb_state *mrb, mrb_value self) { mrb_leapmotion_devicelist_t *data = static_cast<mrb_leapmotion_devicelist_t*>(mrb_data_get_ptr(mrb, self, &mrb_leapmotion_devicelist_type)); if (data == NULL) { return mrb_nil_value(); } mrb_value block; mrb_get_args(mrb, "&", &block); std::for_each (data->obj->begin(), data->obj->end(), mrb_each_func_t<Leap::DeviceList::const_iterator::value_type>(mrb, block)); return self; }
mrb_get_args_でブロックらしきものを"&"
で取っているので間違いなさそうです。C++のコードなのでSTLを使っています。mrb_each_func_t
から始まるテンプレート関数が処理の本体のようです。mrb_each_func_tは同じファイル内にあります。
template <typename T> struct mrb_each_func_t { private: mrb_state *mrb_; mrb_value &block_; public: mrb_each_func_t(mrb_state *mrb, mrb_value &block) : mrb_(mrb), block_(block) {} ~mrb_each_func_t() {} mrb_value operator () (T const &elem) const { return mrb_yield(mrb_, block_, mrb_leapmotion_obj_make(mrb_, elem)); } };
operator ()
内にある mrb_yield がブロックを呼び出す関数のようです!長い道のりでしたが、
- mrb_get_args(mrb, "&", &block); でブロックを受け取る
- mrb_yield(mrb, block, value) で受け取ったブロックを実行
すればよいことがmurbyソースコード検索を使って分かりました!
その他の基本的な使い方はヘルプをどうぞ。
内部の話
構成
groongaがストレージエンジンも兼ねるのでMySQL等は使っていません。
groongaのCentOSへのインストール
先にgroonga-develをインストールしておくとrroongaのインストールが短く終わります。
$ yum install groonga-devel -y $ gem install rroonga
Milkodeのサーバーへのセットアップ
milkode-webを使いました、bundlerで管理出来るのでとっても便利です。
milkode-web - Milkode web application bundler template for apache passenger https://github.com/y-ken/milkode-web
くわしくはgroonga(rroonga)を利用したソースコード全文検索エンジン"Milkode"をApache Passengerで軽快に動かす方法をどうぞ。
レポジトリ一覧の取得
mrubyのレポジトリはGitHubから追加します。
$ milk add https://github.com/mruby/mruby
mgemのレポジトリ一覧は以下のようなスクリプトを使って取得しています。
# Create mgem repository list require 'yaml' mgem_dir = File.join(ENV['HOME'], '.mgem') mgem_list = Dir.glob(File.join(mgem_dir, 'mgem-list/*.gem')) repositories = mgem_list.map do |mgem| YAML.load(File.read(mgem))['repository'] end repositories.each do |repo| puts "milk add #{repo} -p git" end
コマンド文字列が生成されるので後はコピペするなりシェルスクリプトにまとめてサーバー上で実行します。
$ ruby mklist.rb milk add https://github.com/schmurfy/host-stats.git -p git milk add https://github.com/cremno/mruby-allegro.git -p git milk add https://github.com/ppibburr/mruby-allocate.git -p git . .