メタプログラミング Ruby 3章を読んだ。
ブロックの章。2-3回読んだ気がする。
タイトルで想像していたものより,内容の深いものであった。
ブロックで、変数のスコープをうまくコントロールする妙技がこの章のキーの一つになる。
さわりだけ解説。
times = 3 [1, 2, 3].map{ |n| n * times }
timesがスコープ内なので、mapのブロック内でも参照できる。
ブロックの特徴の1つである。
times = 3 def my_times value value * times # NameError: undefined local variable or method `times' end puts my_times 4
上記だと、defのスコープゲートで、timesはスコープ外となり実行できない。
times = 3 Kernel.send :define_method, :my_times do |value| value * times end my_times 4
上記は、defの代わりに、define_methodのプロックを使ってメソッド定義している。
なので、times が参照可能となる。
- クラス定義を class の代わりに Class.new
- モジュール定義を module の代わりに Module.new
- メソッド定義を def の代わりに define_method
と置き換えるとブロックが使えて、変数のスコープが変わり、プログラミングスタイルの幅が広がる。
そのあと、instance_evalと ブロックを組み合わせた技の説明に入っていく。
最後のDSLの説明の箇所はなるほどねぇと感心する。
- 変数のスコープ限定を lambdaで
- 何か JavaScriptっぽい書き方
- 変数の共有を Kernel.send :define_methodで
- ブロックをいったん配列に格納し
- まとめて評価
- 実行順序を制御
- 条件の合うやつだけを実行
- ブロックで記述された設定ファイルのような Ruby Code(DSL)の実行を load & instance_evalで
読んでいて、DSLsのObject Scopingの章のRubyサンプルと類似/相違点が頭に浮かんだ。
DSLsのObject Scopingのサンプルコードの場合は、lambda & define_method ブロックの妙技を使わず、
Builderクラス内のインスタンス変数の共有、self.load & instance_eval を使っていた。
- 作者: Paolo Perrotta,角征典
- 出版社/メーカー: KADOKAWA/アスキー・メディアワークス
- 発売日: 2010/08/28
- メディア: 大型本
- 購入: 18人 クリック: 533回
- この商品を含むブログ (125件) を見る
Domain-Specific Languages (Addison-Wesley Signature Series (Fowler))
- 作者: Martin Fowler
- 出版社/メーカー: Addison-Wesley Professional
- 発売日: 2010/09/23
- メディア: ハードカバー
- 購入: 1人 クリック: 55回
- この商品を含むブログ (10件) を見る