RubyCocoa 今日のコミット 2013-11-04
APIドキュメント(の器)を用意した。
RubyCocoaも10年を超える時を経て、だいぶコードがカオスな感じになっている。以前からコード整理したいなあと思っていたのと、合わせてリファレンスが要るよね、ということで今日は後者の作業。ドキュメント書きながら外向けのインターフェイスを把握して、リファクタリングにも役立つんじゃないかなというもくろみ。
基本方針としては、Objective-C側とRuby側のリファレンスを別々に書くようにする。両方がでてくると邪魔だし、ふつーはRuby側しか使わない。Objective-C側はテンプレートから生成するアプリケーション初期化のあたりくらいだから、自分ではあまりコード書かない。
Objective-Cのリファレンス。こっちはたぶん完成。って言ってもヘッダファイル2個しかないしね。
Rubyのリファレンス。こっちはまだ全然。とりあえずC側のモジュール/クラスやメソッドの一覧が出るようになったレベル。
Objective-Cのドキュメントをheaderdocで書く
はじめはappledocで書くつもりだったのだけど、どうにもCの関数のドキュメントを書く方法が見つからなかった(未対応?)ので、いにしえのheaderdocを使うことに。
headerdocの使いかたは
- コード中にドキュメントを書く
- headerdoc2htmlでHTMLファイルを生成する
- gatherheaderdocでとりまとめたTOCファイルを作る
て感じ。framework/pre-doc.rbに次のようなコードを入れて、"ruby install.rb doc"または"rake doc"でdoc/objcにドキュメントが作成される。
# objective-c documents by "headerdoc" hd2html = `xcrun -f headerdoc2html`.chomp gatherhd = `xcrun -f gatherheaderdoc`.chomp if hd2html.length > 0 && file.exist?(hd2html) fileutils.rm_r('../doc/objc/', :force => true) cmd = %w(#{hd2html} -o ../doc/objc) cmd += %w(src/objc/rubycocoa.h src/objc/rbruntime.h src/objc/rbobject.h) command(cmd.join(' ')) cmd = %w(#{gatherhd} ../doc/objc rubycocoa.html) command(cmd.join(' ')) end
リファレンス見ながらてきとーに試しつつ、書いてった感じ。あんま苦労はしなかったかな。どっちかというと、appledocをあきらめるまでの試行錯誤がしんどかった。
Rubyのドキュメントをyardで書く
クリアコードのククログや雑誌なんかでも何度か見かけてたyardを使うことに。
そのままだとyardは拡張子.mのファイルをRubyスクリプトとして処理しようとしてしまうので、次のようなファイルを用意して、yardocの--loadオプションで読み込ませるようにする。
# register .m .mm file to use CParser require 'yard' YARD::Parser::SourceParser.register_parser_type(:objc, YARD::Parser::C::CParser, %w(m mm)) YARD::Handlers::Processor.register_handler_namespace(:objc, YARD::Handlers::C)
これでObjective-Cのコードも処理できるようになったのだけど、ちょっとした罠が。
- モジュール|クラスの初期化関数の関数は返り値はvoidであること。
- rb_define_module_under()やrb_define_class_under()の名前がモジュール名になっていること。
というもの。後者はrb_define_module()でのOSXモジュールの定義は1回である必要があるため、パラメータで渡したり、externしたりするんだけど、このときのコード上の変数名を見ているようで、
_kObjcID = rb_define_class_under(mOSX, "ObjcID", rb_cObject); //OK _mBundleSupport = rb_define_module_under(_mOSX, "BundleSupport"); //OK _kObjcPtr = rb_define_class_under (outer, "ObjcPtr", rb_cObject); //NG
というようになる。なんかそれで合ってるか不安だったので、あきらめてrdocにしようかとも思ったけどけっきょく関数を合わせる形で対応。
ちなみにyardの生成スクリプトはこんな感じ。(未コミット)
# TODO: Ruby documents by "yard" yardoc = `which yardoc`.chomp if yardoc.length > 0 && File.exist?(yardoc) FileUtils.rm_r('../doc/ruby/', :force => true) cmd = %W(#{yardoc} -o ../doc/ruby --markup markdown --load ./tool/yard_objc_register.rb --title "RubyCocoa\ Documentation" ) # --hide-void-return) # cmd += Dir.glob("src/ruby/**/*.rb") # cmd -= %w(src/ruby/osx/objc/cocoa.rb # src/ruby/osx/objc/oc_all.rb # src/ruby/osx/objc/foundation.rb) cmd += %w(src/objc/cls_objcid.m src/objc/cls_objcptr.m src/objc/mdl_bundle_support.m src/objc/mdl_objwrapper.m src/objc/mdl_osxobjc.m src/objc/BridgeSupport.m) command(cmd.join(' ')) end
次のリリースのときにはまだ完成してなくてもrubycocoa.sourceforge.netのほうに載せるつもり。