2010-11-16 111 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