2008-12-07Ruby で DSL
■ [Ruby][DSL]Rubyで言語内DSLを実現するための参考文献へのリンクをまとめてみる。

「DSLってなんだ?」っていう人は、まつもとさんの記事を読むと少しわかるかもしれない。
「まつもと直伝 プログラミングのオキテ 第6回 メタプログラミング」
http://itpro.nikkeibp.co.jp/article/COLUMN/20070604/273453/?ST=oss
Rubyはメタプログラミング機能が優れているってって話。
どのような点で優れているかっていうと、Rubyでは、Classクラス(Moduleクラスのサブクラス)のメソッドを駆使して、動的にクラス定義を生成できる。
(いや、Javaとかでも同じことはできるんで、優れているというのは間違っているともいえるけど。)
また、動的にクラス定義を変更することも可能(変数、定数、メソッドの「一覧参照・追加・変更・削除」が可能)
詳しくは、Rubyのリファレンスを参照。
Moduleクラス
http://www.ruby-lang.org/ja/man/html/Module.html
Classクラス
http://www.ruby-lang.org/ja/man/html/Class.html
なお、Classクラスは、Moduleクラスのサブクラスとして実装されている。
Methodクラス
http://www.ruby-lang.org/ja/man/html/Method.html
Symbolクラス
http://www.ruby-lang.org/ja/man/html/Symbol.html
Rubyの実行系では、クラス、メソッドを特定するために、Symbolクラスを利用する。
なお、String <-> Symbolの相互変換が可能。なので、これをうまく使えば、設定ファイルから、動的にクラス定義を生成することが可能。
蛇足だけれど、以下のページによると、Symbolクラスの値は、即値らしい。
http://www.ruby-lang.org/ja/man/html/Ruby_A4C7BBC8A4EFA4ECA4EBB5ADB9E6A4CEB0D5CCA3.html#a.2a
「機能別索引」
Rubyにおいて、変数・メソッドを定義する、一覧取得する、削除する方法が調べられる。
「FAQ:ブロック付きメソッド呼び出し」
あと、DSLを実装するときには、いかにブロックを使いこなすか、ということが重要だと思う。
たとえば、Rakeなんかも、taskを表現するときにはブロックを使ってる。
で、そのブロックの実装には「yield」とか使う、はず。(よくわかんないけど)
http://www.ruby-lang.org/ja/man/html/_A5E1A5BDA5C3A5C9B8C6A4D3BDD0A4B7.html#yield
それに関連して、ブロックを渡すときには、&を使うらしい。
http://www.ruby-lang.org/ja/man/html/Ruby_A4C7BBC8A4EFA4ECA4EBB5ADB9E6A4CEB0D5CCA3.html#a.26
それから、単項演算子の再定義には@を使う。
http://www.ruby-lang.org/ja/man/html/Ruby_A4C7BBC8A4EFA4ECA4EBB5ADB9E6A4CEB0D5CCA3.html#a.40
これくらいを知っていると、DSLに関する記事を読んでも、なんとなくイメージがわくんじゃないかと。
たとえば、InfoQにいい記事があったので紹介。
http://www.infoq.com/jp/articles/properties-metaprogramming
あと、こことか。
http://techno.hippy.jp/rorwiki/?An+Exercise+in+Metaprogramming+with+Ruby