ruby 是否可以覆盖块中的值

c7rzv4ha  于 2023-01-30  发布在  Ruby
关注(0)|答案(1)|浏览(118)

新的Ruby所以道歉提前如果这是一个愚蠢的问题。我有一个需要提供一个值给一个块,但不想更新任何地方调用。
假设我有下面的代码块:

{ base.call_my_test }

它被传递给一个函数,我想把它 Package 在另一个块中,但是要给它提供其他块的值,比如:

def test(&block)
    MyTest.with_base_object do |base|
        #neither of these work
        block.instance_variable_set(:@base, base) # Doesn't work
        block.define_singleton_method(:hi) do
            return base
        end

        block.call <---- Is it possible to define base here? 
    end
end

在上面的例子中,是否可以在块上定义base而不传递参数?我尝试了instance_variable_setdefine_singleton_method,但似乎无法定义任何内容,因为它总是说base未定义。
不知道这是否可能,但我想我应该问一下。

eqoofvh9

eqoofvh91#

首先,Ruby中的块是非刚性的Proc对象,这意味着你可以传递额外的参数,任何不期望参数的人都会默默地忽略它们。

def test(&block)
  base = Object.new
  block.call(base)
end

test { |x| puts "Works with an object #{x}." }
test { puts "Works without an object as well!" }

因此,如果你控制了需要定义base的代码块,那么你可以简单地添加参数,test函数的任何其他使用都会忽略额外的参数,即使它们没有声明接受一个参数。
但是这是假设你可以控制任何一个块,听起来你有一些块是你不能改变的,你想自动地把名字base注入到它们的作用域中,你可以通过把块传递给instance_eval来改变调用块的类示例。

**买家注意:**这将完全改变self。如果有问题的块试图查看self或调用它所包围的对象上的任何其他方法(它认为),它将失败。

class HasBase
  attr_reader :base

  def initialize(base)
    @base = base
  end

end

def test(&block)
  base = Object.new
  HasBase.new(base).instance_eval(&block)
end

test { puts "I can see my #{base} from here!" }

根据您的具体需要,您可以开始扩展它以满足调用者的任何需要。例如,您可以使用write method_missing to fall back to the proc's original binding。但这会变得非常神奇,您可能不想在生产中使用这个玩具枪太长时间。

相关问题