Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
动态添加的访问器分配不';在Ruby中通过instance_eval调用block时不起作用_Ruby_Dynamic_Dsl_Instance Eval - Fatal编程技术网

动态添加的访问器分配不';在Ruby中通过instance_eval调用block时不起作用

动态添加的访问器分配不';在Ruby中通过instance_eval调用block时不起作用,ruby,dynamic,dsl,instance-eval,Ruby,Dynamic,Dsl,Instance Eval,我有一个在运行时动态添加属性访问器的类。该类构成DSL的一部分,通过该部分,块被传递给配置方法,并使用instance_eval调用。这使得DSL在引用类的方法时可以删除对“self”的引用 然而,我发现我可以引用属性来检索它们的值,但是我无法分配它们,除非明确地引用self,如下面的代码示例所示 class Bar def add_dynamic_attribute_to_class(name) Bar.add_dynamic_attribute(name) end d

我有一个在运行时动态添加属性访问器的类。该类构成DSL的一部分,通过该部分,块被传递给配置方法,并使用instance_eval调用。这使得DSL在引用类的方法时可以删除对“self”的引用

然而,我发现我可以引用属性来检索它们的值,但是我无法分配它们,除非明确地引用self,如下面的代码示例所示

class Bar

  def add_dynamic_attribute_to_class(name)
    Bar.add_dynamic_attribute(name)
  end

  def invoke_block(&block)
    instance_eval &block
  end

  def self.add_dynamic_attribute(name)
    attr_accessor name
  end

end

b = Bar.new

b.add_dynamic_attribute_to_class 'dyn_attr'

b.dyn_attr = 'Hello World!'

# dyn_attr behaves like a local variable in this case
b.invoke_block do
  dyn_attr = 'Goodbye!'
end

# unchanged!
puts "#{b.dyn_attr} but should be 'Goodbye!'"

# works if explicitly reference self
b.invoke_block do
  self.dyn_attr = 'Goodbye!'
end

# changed...
puts "#{b.dyn_attr} = 'Goodbye!"

# using send works
b.invoke_block do
  send 'dyn_attr=', 'Hello Again'
end

# changed...
puts "#{b.dyn_attr} = 'Hello Again!"

# explain this... local variable or instance method?
b.invoke_block do

  puts "Retrieving... '#{dyn_attr}'"

  # doesn't fail... but no effect
  dyn_attr = 'Cheers'

end

# unchanged
puts "#{b.dyn_attr} should be 'Cheers'"

有人能解释一下为什么这样做没有达到预期效果吗?

这个问题与Ruby处理实例和局部变量的方式有关。发生的情况是,您正在实例评估块中设置一个局部变量,而不是使用ruby访问器

这可能有助于解释:

class Foo
  attr_accessor :bar

  def input_local
    bar = "local"
    [bar, self.bar, @bar, bar()]
  end

  def input_instance
    self.bar = "instance"
    [bar, self.bar, @bar, bar()]
  end

  def input_both
    bar = "local"
    self.bar = "instance"
    [bar, self.bar, @bar, bar()]
  end
end

foo = Foo.new
foo.input_local #["local", nil, nil, nil]
foo.input_instance #["instance", "instance", "instance", "instance"]
foo.input_both #["local", "instance", "instance", "instance"]
bocks的工作方式是区分局部变量和实例变量,但如果在调用局部变量的读取器时未定义局部变量,则该类默认为实例变量(在我的示例中,调用input_instance就是这种情况)

有三种方法可以获得你想要的行为

使用实例变量:

class Foo attr_accessor :bar def evaluate(&block) instance_eval &block end end foo = Foo.new foo.evaluate do @bar = "instance" end foo.bar #"instance" 福班 属性存取器:条 def评估(&block) 实例评估和块 结束 结束 foo=foo.new foo.do @bar=“实例” 结束 foo.bar#“实例” 使用自变量:

class Foo attr_accessor :bar def evaluate(&block) block.call(self) end end foo = Foo.new foo.evaluate do |c| c.bar = "instance" end foo.bar #"instance" 福班 属性存取器:条 def评估(&block) 阻塞呼叫(自我) 结束 结束 foo=foo.new foo.do|c| c、 bar=“实例” 结束 foo.bar#“实例” 使用setter函数:

class Foo attr_reader :bar def set_bar value @bar = value end def evaluate(&block) instance_eval &block end end foo = Foo.new foo.evaluate do set_bar "instance" end foo.bar #"instance" 福班 属性读取器:条 def设置_条值 @bar=值 结束 def评估(&block) 实例评估和块 结束 结束 foo=foo.new foo.do 设置工具栏“实例” 结束 foo.bar#“实例”
所有这些例子都将foo.bar设置为“instance”。

我不完全理解;您说ruby类区分本地变量和实例变量,但问题在于访问器方法。i、 e.酒吧!=@酒吧!=bar()!=bar=()。顺便说一句:我通过在类上实现一个名为“config”的方法来解决这个问题,该方法返回self,这样我的DSL读起来更好(即,不再使用self.*它现在有config.*)。我用更多细节更新了帖子。问题是您在不知不觉中设置了局部变量而不是实例变量。更准确地说,如果未定义名为bar的局部变量,则bar==@bar==bar()==self.bar。否则吧!=@如果定义了名为bar的局部变量,则bar==bar()==self.bar。为了安全起见,不要定义名为“bar”的局部变量,或者只使用其他方法。