2010-11-16 54 views
0

我试图优化一些代码定义上初始化单的方法,我想上,而不是在检查每一个方法调用一定的价值,定义方法与检查已经预先计算响应,因为这个检查在实例的整个生命中不会改变。使用实例变量

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

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块是不是里面的变量是可见的。

任何人都可以解释我怎么做我正在寻找的行为?

由于

+0

我认为有一些与你的例子混淆。在主题行中提到了实例变量,但是您发布的代码中没有任何实例变量。 – 2010-11-16 17:56:40

回答

1

添加到约克的回答是:define_singleton_method是红宝石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 
+0

请阅读@Jörg答案,因为它是Ruby 1.9+解决方案。 – fguillen 2010-11-18 10:07:46

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 
+0

非常感谢@Jörg,我会接受@Chubas的回答,因为在这里你是两个答案,我认为对于有同样问题的人来说,阅读两个答案都很重要。 – fguillen 2010-11-18 10:06:56

+1

我会建议改变这个接受的答案 - 我怀疑很多人是1.9前仍然,所以解决方法是不必要的:) – 2013-10-30 19:54:55