使用实例变量在初始化时定义单例方法

fgu*_*len 0 ruby metaprogramming

我正在尝试优化一些代码,而我想要在每个方法调用上检查一个值,只需定义方法来响应已经预先计算检查,因为这个检查不会在实例的整个实时中发生变化.

我决定为每个创建的实例定义不同版本的方法.或多或少这样:

class TestingSingletonMethodsWithVariable
  METHODS = %w(a b c d)

  def initialize(favorite_method)
    class << self
      METHODS.each do |method_name|
        if( favorite_method == method_name )
          define_method method_name do
            puts "#{method_name} its my favorite method"
          end
        else
          define_method method_name do
            puts "#{method_name} its not my favorite method"
          end
        end
      end
    end
  end
end

t = TestingSingletonMethodsWithVariable.new('b')
t.a
t.b
t.c
t.d

# $ ruby test/testing_singleton_methods_with_variable.rb 
# test/testing_singleton_methods_with_variable.rb:7:in `initialize': undefined local variable or method `favorite_method' for #<Class:#<TestingSingletonMethodsWithVariable:0x1001a77b8>> (NameError)
#   from test/testing_singleton_methods_with_variable.rb:6:in `each'
#   from test/testing_singleton_methods_with_variable.rb:6:in `initialize'
#   from test/testing_singleton_methods_with_variable.rb:21:in `new'
#   from test/testing_singleton_methods_with_variable.rb:21
Run Code Online (Sandbox Code Playgroud)

发生的事情是变量发生了一些奇怪的事情:变量声明在class << self块外面的变量对于里面的变量是不可见的.

任何人都可以解释我如何才能完成我正在寻找的行为?

谢谢

Jör*_*tag 9

在Ruby中,只有块可以是闭包,类主体(以及模块和方法主体)不能是闭包.或者换句话说:只有块创建一个新的嵌套词法范围,所有其他(模块主体,类主体,方法主体和脚本主体)创建新的顶级范围.

所以,你需要一个块.通常,这意味着使用某种形式eval,但在这里你可以使用define_singleton_method:

class TestingSingletonMethodsWithVariable
  METHODS = %w(a b c d)

  def initialize(favorite_method)
    METHODS.each do |method_name|
      if favorite_method == method_name
        define_singleton_method method_name do
          puts "#{method_name} its my favorite method"
        end
      else
        define_singleton_method method_name do
          puts "#{method_name} its not my favorite method"
        end
      end
    end
  end
end

t = TestingSingletonMethodsWithVariable.new('b')
t.a
t.b
t.c
t.d
Run Code Online (Sandbox Code Playgroud)