2011-09-27 5 views
8

私はdefine_methodを使ってクラスのメソッドを動的に定義することができ、このメソッドはブロックのアリティを使用してパラメータを指定することを知っています。ブロックを取るRubyメソッドを動的に定義できますか?

オプションのパラメータとブロックの両方を受け入れるメソッドを動的に定義する必要があります。 Ruby 1.9では、ブロックをブロックに渡すことができるため、これは簡単です。

残念ながら、Rubyの1.8はこれを許可していませんので、以下では動作しません。

#Ruby 1.8 
class X 
    define_method :foo do |bar, &baz| 
    puts bar 
    baz.call if block_given? 
    end 
end 

x = X.new 
x.foo("foo") { puts "called!"} #=> LocalJumpError: no block given 

をいずれかの問題が解決しないyieldで明示的block.callを交換します。
Ruby 1.9へのアップグレードは残念ながら私の選択肢ではありません。これは難しい問題なのでしょうか、それともその周りに道がありますか?

答えて

6

これはRubyの1.8.7ではなく、1.8.6で動作します:

class X 
    define_method(:foo) do |bar, &baz| 
    puts bar 
    baz.call if baz 
    end 
end 

テストで:

X.new.foo("No block") 
X.new.foo("With block") { puts " In the block!"} 
p = proc {puts " In the proc!"} 
X.new.foo("With proc", &p) 

ができます:1.8.6で

No block 
With block 
    In the block! 
With proc 
    In the proc! 

(それsyntax error, unexpected tAMPER, expecting '|'を与える)

class X 
    define_method(:foo) do |*args, &baz| 
    if args[0] 
     bar = args[0] 
    else 
     bar = "default" 
    end 
    puts bar 
    baz.call if baz 
    end 
end 

テストと::オプションの引数としてだけでなく、ブロックをしたい場合は、あなたはこのような何かを試みることができる

X.new.foo 
X.new.foo { puts " No arg but block"} 

を与える:

default 
default 
    No arg but block 
4

class_evalには、define_methodの代わりに文字列を使用します。これの欠点は(エレガントではない点を除けば)、語彙的スコープを失うことです。しかし、これはしばしば必要ではありません。

+0

は、私は、文字列を渡す必要がありますかto class_eval?ブロックを渡すことはできませんが、スコープは維持されますか? – andrewdotnich

+2

@andrewdotnichさて、メソッドを動的に定義する方法の問題に戻ります。 –

+1

https://github.com/agrimm/zombie-chaser/blob/master/lib/zombie-chaser/chaser.rbには、ファイルの途中にあるブログ投稿へのリンクと例があります。 –

関連する問題