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

Ruby 使用实例变量在初始化时定义单例方法,ruby,metaprogramming,Ruby,Metaprogramming,我正在尝试优化一些代码,我想在每个方法调用上检查一个值,只需定义一个方法来响应预先计算的检查,因为这种检查在实例的整个活动中不会改变 我决定为创建的每个实例定义不同版本的方法。大致是这样的: class TestingSingletonMethodsWithVariable METHODS = %w(a b c d) def initialize(favorite_method) class << self METHODS.each do |method

我正在尝试优化一些代码,我想在每个方法调用上检查一个值,只需定义一个方法来响应预先计算的检查,因为这种检查在实例的整个活动中不会改变

我决定为创建的每个实例定义不同版本的方法。大致是这样的:

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
类TestingSingletonMethodsWithVariable
方法=%w(a b c d)
def初始化(常用的方法)

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

所以,你需要一个街区。通常,这意味着使用某种形式的
eval
,但在这里,您可以使用
define\u singleton\u 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

给Jörg的答案增加一点:define_singleton_方法是Ruby 1.9+。如果要在1.9之前的版本中运行,请执行以下操作:

class Object
  def metaclass
    class << self; self; end
  end
end
class TestingSingletonMethodsWithVariable
  METHODS = %w(a b c d)

  def initialize(favorite_method)
    METHODS.each do |method_name|
      if( favorite_method == method_name )
        metaclass.send(:define_method, method_name, Proc.new do
          puts "#{method_name} its my favorite method"
        end)
      else
        metaclass.send(:define_method, method_name, Proc.new 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
类对象
def元类

同学们,我觉得你们的例子有些混乱。在主题行中,您提到了实例变量,但您发布的代码中没有实例变量。非常感谢@Jörg,我会接受@Chubas的答案,因为这是你的两个答案,我认为阅读这两个答案对我有同样问题的人来说很重要。我建议将接受的答案改为这一个-我怀疑很多人仍然在1.9之前,因此解决方法是不必要的:)请阅读@Jörg答案,因为其中包含Ruby 1.9+解决方案。