不从块调用动态定义的setter方法

时间:2014-04-10 06:07:11

标签: ruby lambda metaprogramming dsl

我一直在编写DSL,我试图让一个动态定义的方法可以从lambda中访问。除非你尝试做一个setter something=,否则这种方法很好。在这种情况下,lambda调用只会设置一个局部变量。

简化示例:

class Caller
  attr_accessor :cmd
  def callme
    self.class.send(:define_method, "something") { puts "Retrieve Something" }
    self.class.send(:define_method, "something=") {|val| puts "Set Something = #{val}" }
    instance_exec &cmd
  end
end

c = Caller.new
c.cmd = lambda { something = 1 }
c.callme

如果我使用self.something=,这也可以正常工作。然而,在DSL的情况下,这并不理想。

是否可以在方法前面没有self.的情况下使其工作?

1 个答案:

答案 0 :(得分:2)

这与块或动态定义的方法完全无关。它只是简单的基本Ruby语法:

foo = bar

是局部变量赋值。总是

self.foo = bar

是方法调用。

  

是否可以在方法前面没有self.的情况下使其工作?

没有

这只是基本的Ruby语法。 define_method元编程,instance_exec,代码示例中的块只是一个红色的鲱鱼,问题可以用很多更简单的例子来证明:

def foo=(*)
  puts 'I was called!'
end

foo=('bar') # even removing spaces and adding parentheses won't help!

self.foo = 'bar'
# I was called!

另请注意,foo=private,但实际上是使用显式接收方调用的(private方法不合法)。对于private方法的规则中的setter方法来说,这是一个特殊的例外,因为它们根本无法被调用,正是因为它们总是被解释为局部变量赋值。