2012-01-25 8 views
2

これは奇妙に聞こえますか?名前が等号で終わるメソッドにブロックを渡すにはどうすればよいですか?

class Dummy 
    def foo=(value); end 
end 

Dummy.new.foo = 1 { |x| x } # => syntax error 
Dummy.new.foo=(1) { |x| x } # => syntax error 

私はすべての空白、括弧、カンマの順列を試しました。運がない。私は困惑している。私は '='で終わるメソッドが特別であると疑ったことはありません。それはバグですか?それは意図されていますか?意図されていれば、なぜですか?それは文書化されていますか?どこ?洞察力を共有してください。

ありがとう

ps ruby is 1.9.2p290(2011-07-09 revision 32553)

+1

あなたが書きたいコードを記述し、 '= 'で終わるメソッドにブロックを渡すことが理にかなっていると思った理由が役に立つかもしれません。 – Phrogz

答えて

2

=で終わるメソッドの構文砂糖は特別なものです。あなたはまだ任意のかなりや便利な方法でそのメソッドに複数の引数を渡す、またはブロックを通過しますが、ないようなことを行うことができます。

class Foo 
    def bar=(a,b=nil) 
    p [a,b] 
    if block_given? 
     yield "hi" 
    else 
     puts "No block" 
    end 
    end 
end 

f = Foo.new 
f.bar = 42 
#=> [42, nil] 
#=> No block 

f.bar = 42, 17 
#=> [[42,17], nil] 
#=> No block 

f.send(:bar=,42,17) do |x| 
    puts "x is #{x.inspect}" 
end 
#=> [42, 17] 
#=> x is "hi" 

これらの方法は、特別なされたもう一つの方法は、シンタックスシュガーで呼び出されたときにということです彼らは右手値ではなく、メソッドの戻り値を評価:

class Foo 
    def bar=(a) 
    return 17 # really explicit 
    end 
end 

f = Foo.new 

x = (f.bar = 42) 
p x 
#=> 42 

x = f.send(:bar=,42) 
p x 
#=> 17 
0

それはとてもメソッド自体が特別であることを多くのが、Rubyは(foo = barのような)の割り当てを扱う方法で行うことがよりありません。最初に右側が評価され、次に左側が評価され、適切な処置がとられます。左側がオブジェクト属性の場合、適切なセッターメソッドが呼び出されます。だからあなたの例では

Dummy.new.foo = 1 { |x| x } 

まずルビーは、構文エラーを引き起こすものである1 { |x| x }を、evalulateしようとします。

Dummy.new.foo=somethingは、実際に「foo=という名前のメソッドを呼び出す」を意味するが、実際にはより多くのevalualate something」のようなものを意味し、その後`Dummy.new.fooが何であるかを決定し、それがオブジェクト属性のように見える場合は、名前に=を追加しないとそのメソッドを呼び出す "。このため、Dummy.new.foo=Dummy.new.foo =の両方が同じように動作します。

あなたはsendを使用してこれらのメソッドを呼び出すことができ、かつこれにブロックを渡すことができます:sendで明示的に呼び出したいメソッドに名前を付けることができますので、

Dummy.new.send "foo=", 2 do 
    puts "HI" 
end 

です。

最後に、=で終わるメソッドは、あなたが知っておく必要のある「特別な」振る舞いをしているようですが、実際に何が起こっているのかを理解することは有用かもしれません。

関連する問題