代码之家  ›  专栏  ›  技术社区  ›  fguillen

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

  •  0
  • fguillen  · 技术社区  · 14 年前

    我正在尝试优化一些代码,我想 而是检查每个方法调用的值 只需定义用 检查已预先计算 ,因为此检查不会在实例的整个活动中更改。

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

    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
    

    正在发生的是,变量发生了一些奇怪的事情:变量声明了 class << self 块对于内部变量不可见。

    有谁能解释我该怎么做我想要的行为?

    谢谢

    2 回复  |  直到 14 年前
        1
  •  1
  •   Chubas    14 年前

    加上JÃ《rg的答案:define_singleton_method是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
    
        2
  •  9
  •   Jörg W Mittag    11 年前

    在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