12

我想访问调用者的绑定。这里有什么问题?

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

为什么我无权访问给定块内的调用者实例?

4

3 回答 3

6

在块内部,您不在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"
于 2013-07-01T08:57:32.760 回答
0

试图重现它:

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

内部{ }或外部{}foo尚未定义为 amethodvarable。因此 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
于 2013-07-01T08:47:02.373 回答
0

尝试这个

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

  def foo; 'foo'; end
end
于 2013-07-01T09:44:18.910 回答