Class :: new block

时间:2018-02-13 19:27:58

标签: ruby

我试图在Ruby中使用元编程来创建类:Dynamically define named classes in Ruby。一切进展顺利,除了在Class.new区块中似乎无法引用奇怪的参考方法参数。

我有这个

class A; end

module B
  def self.class_with_method(class_name, method_return)
    klass = Class.new(A) do
      def example
        method_return
      end
    end
    B.const_set class_name, klass
  end
end

但是当我有上述内容然后用

进行测试时
B.class_with_method 'ExampleClass', 23
B::ExampleClass.new.example

给我

  

未定义的局部变量或方法`method_return' for#< B :: ExampleClass:0x00007ff1d7130d00> (NameError)

这很奇怪,因为如果我要做的话

def add_number(number)
  [1, 2, 3, 4].map {|i| i + number}
end

add_number(2)
# => [3, 4, 5, 6]

很明显,块可以采用方法参数。

有没有办法在块中将method_return传递给def example

3 个答案:

答案 0 :(得分:1)

由于method_return是一个变量,除非您在另一个上下文中使用它,否则无法将其传播到example方法。您可以在类级变量中捕获它:

klass = Class.new(A) do
  @@method_return = method_return

  def example
    @@method_return
  end
end

您还可以动态定义方法,以便块捕获method_return变量作为闭包:

klass = Class.new(A) do
  define_method(:example) do
    method_return
  end
end

使用def example时,块范围会发生变化并变得完全不同。

答案 1 :(得分:1)

这根本不奇怪,它是方法定义的常规行为:

class A
  x = 3
  def foo
    x
  end
end

A.new.foo # NameError: undefined local variable or method `x'

方法定义不会从外部范围捕获局部变量。这通常很好:通常你不希望方法的结果依赖于定义时存在的一些随机状态,你希望它依赖于你调用它的对象!

当然例外是你进行元编程。在这种情况下,捕获局部变量非常有用,因此您显式使用您在其他地方使用的相同机制来捕获它们:块。

define_method :example do
  method_return
end

答案 2 :(得分:0)

def结构缩小了范围。局部变量无法超越这一点。要做你想做的事,请改用define_method