メタプログラミング
Rubyにはプロパティはありませんが、メソッド呼び出しに(通常は)かっこが必要でないことを利用して、プロパティをシミュレートできます。また、Rubyでは=
で終わるメソッドが特別に扱われ、セッターのように振る舞うことも利用する必要があります。
例えば、人(Person
)のクラスを次のように定義します。
irb(main):001:0> class Person irb(main):002:1> def age irb(main):003:2> @age irb(main):004:2> end irb(main):005:1> def age=(value) irb(main):006:2> @age = value irb(main):007:2> end irb(main):008:1> end => nil
こうすると、Person
のインスタンスを使って、年齢(age
)を人のプロパティのように扱うことができます。
irb(main):009:0> p = Person.new => #<Person:0x89c5678> irb(main):010:0> p.age => nil irb(main):011:0> p.age = 42 => 42 irb(main):012:0> p.age => 42
age
のデフォルト値をnil
以外にしたい場合は、initialize
メソッドで設定できます。
このコードは非常に定型的な感じがします。これがC#などの言語であれば、おそらくVisual Studioのスニペットのようなものを使うか、静的コード生成でプロパティのリーダーとライターを自動的に生成したくなるでしょう。
しかしRubyでは、メタプログラミングを使って、ほんのわずかな労力でそうしたものを作成できます。理想は次のような記述ができることです。
class Person prop :age end
Objectのクラス(静的)メソッドを定義し、自分のクラスを定義するときにそれを利用できるようにします。また、ここで初めて目にするclass_eval
というメソッドも使います。
irb(main):001:0> class Object irb(main):002:1> def self.prop *names irb(main):003:2> names.each { |name| irb(main):004:3* self.class_eval " irb(main):005:3" def #{name} irb(main):006:3" @#{name} irb(main):007:3" end" irb(main):008:3> self.class_eval " irb(main):009:3" def #{name}=(value) irb(main):010:3" @#{name} = value irb(main):011:3" end" irb(main):012:3> } irb(main):013:2> nil irb(main):014:2> end irb(main):015:1> end => nil
ここで使われているclass_eval
メソッドが、最終的にメソッドを作成することになります。このメソッドは、クラス自体のコンテキストで行ったかのように文字列を評価します。そのため、最初からクラスの中に記述してきたかのようにメソッドを記述できます。
prop
メソッドに渡されるそれぞれの名前は、新しいクラスにゲッターとセッターの2つのメソッドを追加します。できあがった文字列では、#{name}
が、prop
に渡した名前に置き換わります。
これでprop
をクラス定義で使うことができます。
irb(main):016:0> class Person irb(main):017:1> prop :age, :name irb(main):018:1> irb(main):019:1* def initialize(age, name) irb(main):020:2> @age = age irb(main):021:2> @name = name irb(main):022:2> end irb(main):023:1> end => nil irb(main):024:0> p = Person.new(36, "Brad") => #<Person:0x89c0768 @age=36, @name="Brad"> irb(main):025:0> p.age => 36 irb(main):026:0> p.name => "Brad"
このような機能を自在に使いこなすことで、作業の大部分をこうしたメタプログラミングの仕掛けに任せて、はるかに高いレベルでクラスをすばやく作成できます。エディタのスニペットやコンパイル時のコード生成に頼る必要はありません。
次のステップ
本稿では、Rubyで利用できる機能のほんのうわべをなでたにすぎません。今からRubyを習得すれば、.NETやSilverlightでRubyを利用できるようになったときの備えになります。これほど強力な動的言語を身に付けることは、プログラマにとって大きな強みになります。しかし、もっと重要なのは、それが問題と解決策を新しい方法で考えるためのきっかけになることです。
Rubyについてさらに学習したい場合は、表紙の絵から「つるはし本」とも呼ばれる、David Thomas/Andrew Hunt共著『Programming Ruby: The Pragmatic Programmer's Guide』(Addison-Wesley Professional)【邦訳:『プログラミングRuby - 達人プログラマーガイド』(ピアソンエデュケーション)】を強くお勧めします。