Rubyによるメタプログラミング

文:Steve Hayes(Builder AU) 翻訳校正:石橋啓一郎
2007-12-13 09:00:00
  • このエントリーをはてなブックマークに追加

 最初のコラムでは、Rubyの構文は柔軟であり、ドメイン固有言語(DSL)を作るのに非常に適していると述べた。

 さて、これからはRubyのメソッドの定義方法と呼び出し方法について詳しく述べる。さらに、Rubyのメタプログラミングによって、DSLにコードの実行中に新しいクラスを作成させる方法について説明する。これを読めば、DSLの作成に必要なツールの大半を知ることができる。

 われわれは既に、Rubyではあるクラスにnewメソッドを送ることでオブジェクトが生成されることを学んでいる。

book = Book.new

 クラスがnewメソッドを受け取ると、新しいオブジェクトのスペースに割り当て、もしinitializeインスタンスメソッドが存在すればそれを呼び出し、新しいオブジェクトを有効な状態にする。newメソッドに渡される引数は、自動的にinitializeに渡される。例えば次のようになる。

class Book

def initialize(title, author, isbn)
@title = title
@author = author
@isbn = isbn
end

end

book = Book.new(‘War and Peace’, ‘Tolstoy’, ‘0375760644’)

 この実装では、本に関するオブジェクトを生成する際には、必ず毎回本のタイトルと著者とISBNを入力しなければならず、詳細を知らない場合でも何らかの値を与えなくてはならない。例えば、私がタイトルだけしか知らない場合、次のような形にしなくてはならない。

book = Book.new(‘To Serve Them All My Days’, ‘Unknown’, ‘’)

 これは少し煩わしいし、値が分からない場合にそれをどうコード化するかは、それぞれの開発者の気まぐれに任せてしまうことになる。知らないパラメータについてはデフォルト値が設定されるようになれば便利であり、Rubyにはその方法が用意されている。次のクラス定義の例では、タイトルの値は必ず入力しなくてはならないが、著者とISBNについてはデフォルト値が設定される。

class Book

def initialize(title, author=’Unknown’, isbn=nil)
@title = title
@author = author
@isbn = isbn
end

end

 メソッドがパラメタに与えるデフォルト値を持っている場合、それに対応するパラメタは省略することができる。パラメタは位置で指定されることから、もしあるパラメタにデフォルト値を使う場合、それ以降のパラメタはすべてデフォルト値を使わなくてはならない。

book = Book.new(‘War and Peace’, ‘Tolstoy’, ‘0375760644’)  #valid
book = Book.new(‘War and Peace’, ‘Tolstoy’)    #valid
book = Book.new(‘War and Peace’)               #valid
book = Book.new(‘War and Peace’, ‘0375760644’) #valid syntax, but bad semantics

 最後の例は構文は合っており実行もできるが、名前が"0375760644"でISBNがnilの本のオブジェクトを生成してしまう。これはおそらく意図していることとは違っているだろう。

 では、本のオブジェクトを生成する際に、その本を所有している人のリストも作りたいと思っており、そのリストは任意の長さである場合を考えてみよう。明らかな方法の1つは、所有者を行列として渡すことだ。例えば次のようになる。

class Book

def initialize(title, author=’Unknown’, isbn=nil, owners=[])
@title = title
@author = author
@isbn = isbn
@owners = owners
end

end

book = Book.new(‘War and Peace’, ‘Tolstoy’, ‘0375760644’, [‘Steve’, ‘Amanda’, ‘Marty’])

 確かにこれでも正しく動くのだが、Rubyではもっと簡単な方法がある。次の例は、前の例と意味的に等価なものだ。

class Book

def initialize(title, author=’Unknown’, isbn=nil, *owners)
@title = title
@author = author
@isbn = isbn
@owners = owners
end

end

book = Book.new(‘War and Peace’, ‘Tolstoy’, ‘0375760644’, ‘Steve’, ‘Amanda’, ‘Marty’)
このサイトでは、利用状況の把握や広告配信などのために、Cookieなどを使用してアクセスデータを取得・利用しています。 これ以降ページを遷移した場合、Cookieなどの設定や使用に同意したことになります。
Cookieなどの設定や使用の詳細、オプトアウトについては詳細をご覧ください。
[ 閉じる ]