2010-05-29 5 views
3

Je suis en train d'écrire un DSL qui me permet de faireRuby Métaprogrammation

Policy.name do 
author "Foo" 
reviewed_by "Bar" 
end 

Le code suivant peut presque le traiter:

class Policy 
    include Singleton 
    def self.method_missing(name,&block) 
     puts name 
     puts "#{yield}" 
    end 
    def self.author(name) 
    puts name 
    end 
    def self.reviewed_by(name) 
    puts name 
    end 
end 

Définir ma méthode que les méthodes de classe (self.method_name) je peux y accéder en utilisant la syntaxe suivante:

Policy.name do 
Policy.author "Foo" 
Policy.reviewed_by "Bar" 
end 

Si je supprime le "self" des noms de méthodes, et essaie de utiliser ma syntaxe désirée, puis je reçois une erreur "Méthode non trouvée" dans le Main afin qu'elle ne trouve pas ma fonction avant le module Kernel. C'est ok, je comprends l'erreur. Mais comment puis-je le réparer? Comment puis-je réparer ma classe pour qu'elle fonctionne avec ma syntaxe désirée?

Répondre

4

Afin de contrôler ce que self est dans la portée du bloc (puisque author se résout à self.author), vous pouvez utiliser instance_eval.

class Policy 
    def self.name(&block) 
    PolicyNameScope.new(block) 
    end 

    class PolicyNameScope 
    def initialize(block) 
     instance_eval(&block)  
    end 

    def author(author) 
     @author = author 
    end 

    def reviewed_by(reviewed_by) 
     @reviewed_by = reviewed_by 
    end 
    end 
end 

policy = Policy.name do 
    author "Dawg" 
    reviewed_by "Dude" 
end 

p policy 
# => #<Policy::PolicyNameScope:0x7fb81ef9f910 @reviewed_by="Dude", @author="Dawg"> 

La classe PolicyNameScope a les méthodes d'instance qui sont autorisés dans le bloc name. C'est ainsi que les méthodes de Policy ne sont pas disponibles à l'intérieur du bloc, rendant le DSL beaucoup plus serré.

Comme votre exemple est hors contexte, je ne peux pas vous aider davantage - ce code en lui-même ne semble pas très utile.

+0

salut Août, je joue avec la métaprogrammation ruby ​​et votre exemple + explication m'a beaucoup aidé. StackOverflow Règles !! –

1

La réponse ci-dessus suggérée en août est correcte. Cependant, si vous souhaitez utiliser votre constructeur à d'autres fins, la méthode ci-dessus échoue. Par conséquent, dans cette situation, vous devez utiliser une autre méthode que celle décrite ci-dessus. Voici la solution que j'ai préparée sans utiliser le constructeur de classe.

class Policy 

    def self.method_missing(name,&block) 
    self.class_eval(&block) 
    end 
    def self.author(name) 
    p name 
    end 
    def self.reviewed_by(name) 
    p name 
    end 

end 

Policy.name do 
    author "Foo" 
    reviewed_by "Bar" 
end 

Ceci n'est pas une solution optimisée mais une solution à votre problème.

Questions connexes