2013-07-01 12 views
9

呼び出し元のバインディングにアクセスしたいと思っています。ここで何が間違っていますか?ruby​​ブロックを呼び出して呼び出し元のバインディングにアクセスする方法

require 'test/unit' 

class BlocksTest < Test::Unit::TestCase 

    class Blocks 
    def initialize(&block); @block = block; end 
    def run; instance_eval { @block.call }; end 

    def foo; 'foo'; end 
    end 

    def test_say_foo_via_string 
    assert_equal('foo', Blocks.new{ 'foo' }.run) 
    end 
    # => successful 

    def test_say_foo_via_caller_method 
    assert_equal('foo', Blocks.new{ foo }.run) 
    end 
    # => NameError: undefined local variable or method `foo' 

end 

なぜ特定のブロック内の呼び出し側インスタンスにアクセスできないのですか?

+0

親愛なるを試してみてくださいダウンホッター!私はここでは比較的新しいです、そして、私の質問が役に立たないなら、いくつかのアドバイスを得ることはうれしいでしょう。 :-)質問コードを完全なテストクラス 'BlocksTest'に変更しました。私は 'run'メソッドのブロック呼び出しを' @ block.call'から 'instance_eval {@ block.call}'に変更しました。これは同じエラーを発生させます。 – sschmeck

答えて

4

あなたがBlocksインスタンスのスコープではありませんので、fooが表示されていません。あなたは、あなたがそれにアクセスできるようにしたい場合はブロックにオブジェクトを渡す必要があり:

class Blocks 
    # ... 
    def run 
    @block.call(self) 
    end 
    # ... 
end 

blk = Blocks.new { |b| b.foo } 
blk.run 
# => "foo" 

代わりにあなたがinstance_evalにブロックを渡すことができます。

class Blocks 
    # ... 
    def run 
    instance_eval(&@block) 
    end 
    # ... 
end 

blk = Blocks.new { foo } 
blk.run 
# => "foo" 
+0

procとブロックの違いについては、[this](http://www.robertsosinski.com/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/)と[this](http ://net.tutsplus.com/tutorials/ruby/ruby-on-rails-study-guide-blocks-procs-and-lambdas/)。 – toro2k

+0

ありがとう!私は質問をする前に2番目の解決策を試しましたが、 '&'演算子は使用しませんでした。 'instance_eval {@ block.call};'は同じエラーを発生させます。ブロックとProcの構文の違いは何ですか? – sschmeck

+0

リンクをありがとう。私は 'instance_eval(&block)'と 'instance_eval {block.call} 'の違いについては説明しませんでした。最初の方法はProcをブロックに変換し、2番目の方法は新しいブロックを作成してProcを実行します。私はまだ、アプローチのバインディング/スコープが異なる理由は分かりません。 : - / – sschmeck

0

はそれを再現してみました:{}{ }や内外

3.times.map{ foo } 
#~> undefined local variable or method `foo' for main:Object (NameError) 

を、foomethodまたはvarableとして定義されていません。したがって、Rubyパーサーは混乱してエラーをスローします。

今参照してください。

foo = 12 
3.times.map{ foo } 
# => [12, 12, 12] 

は試してみてください。ブロック内の

test "say method_foo" do 
    assert_equal('foo', Blocks.new{|i| i.foo }.run) 
end 
0

この

class Blocks 
    def initialize(&block); @block = block; end 
    def run; instance_eval &@block; end 

    def foo; 'foo'; end 
end 
関連する問題