2010-11-16 14 views
0

Je suis en train d'optimiser un peu de code et je veux plutôt sur la vérification d'une valeur à chaque appel de méthode juste définir la méthode pour répondre à la vérification déjà pré-calcul, car cette vérification ne change pas sur toute la durée de vie de l'instance.Définir les méthodes singletons sur l'initialisation en utilisant les variables d'instance

J'ai décidé de définir différentes versions de la méthode pour chaque instance créée. Plus ou moins de cette façon:

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 

Ce qui se passe est que quelque chose de bizarre se passe avec les variables: les variables hors côté déclare le bloc class << self ne sont pas visibles pour les variables à l'intérieur. Tout le monde peut m'expliquer comment puis-je faire le comportement que je cherche?

Merci

+0

Je pense qu'il ya un mélange avec votre exemple. Dans la ligne d'objet, vous mentionnez des variables d'instance, mais il n'y a aucune variable d'instance nulle part dans le code que vous avez publié. –

Répondre

1

Ajout à la réponse de Jörg: define_singleton_method est Ruby 1.9+. Si vous voulez l'exécuter en pré 1.9, les travaux suivants:

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

S'il vous plaît lire la réponse @ Jörg parce que c'est la solution Ruby 1.9+. – fguillen

9

Dans Ruby, seuls les blocs peuvent être des fermetures, des organismes de classe (ainsi que les organismes de module et méthode) ne peuvent pas être fermetures. Ou pour le dire autrement: seuls les blocs créent une nouvelle portée lexicale imbriquée, tous les autres (corps de modules, corps de classes, corps de méthodes et corps de scripts) créent de nouvelles étendues de niveau supérieur.

Ainsi, vous aurez besoin d'un bloc. Normalement, cela voudrait dire en utilisant une certaine forme de eval, mais ici vous pouvez simplement utiliser define_singleton_method à la place:

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

Merci beaucoup @ Jörg, je vais accepter la réponse de @Chubas juste parce que dans ce sont vos deux réponses et je pense est important pour les personnes ayant mon même problème de lire les deux réponses. – fguillen

+1

Je suggère de changer la réponse acceptée à celui-ci - je doute que beaucoup de gens sont encore pré-1.9, donc la solution n'est pas nécessaire :) –