2010-09-10 6 views
2

Je veux pouvoir définir un bloc, puis évaluer ce bloc à l'intérieur d'un module/classe généré dynamiquement. Il semble que je pourrais accomplir cela en utilisant eval et block.binding, mais je ne l'ai pas compris.Passer des blocs dans une méthode imbriquée dans class_eval dans Ruby?

J'ai ce que la base:

def define_module(name, &block) 
    name = name.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase } 
    parts = name.split("::") 
    parts.each_with_index do |part, index| 
    sub_name = parts[0..index].join("::") 
    eval("module #{sub_name}; end") 
    end 
    clazz = eval(name) 
    clazz.class_eval(&block) if block_given? 
    clazz 
end 

def add_module(name, &block) 
    module_block = block 
    define_module(name).class_eval <<-EOF 
    def self.included(base) 
     base.class_eval do 
     # something like this, I'm stuck 
     instance_eval(&#{module_block}) 
     end 
    end 
    EOF 
end 

Et je veux l'utiliser comme ceci:

add_module("My::Library") do 
    def a_method 
    "added 'a_method'" 
    end 
end 

class ::User 
    include My::Library 
end 

user = ::User.new 

assert_equal "added 'a_method'", user.a_method 

Est-il possible de faire quelque chose comme ça?

+0

ok, ne si l'idée de cette façon vous pouvez fermer pas utiliser evals à base de chaîne, bloc utilisation evals base, sur 'block' – horseyguy

Répondre

1

Cela fonctionne:

def add_module(name, &block) 
    define_module(name).class_eval do 
     class << self; self; end.send(:define_method, :included) { |base| 
      base.class_eval(&block) 
     } 
    end 
end 

add_module("My::Library") do 
    def a_method 
     "added 'a_method'" 
    end 
end 

class ::User 
    include My::Library 
end 

user = ::User.new 
user.a_method #=> "added a_method" 

EDIT:

Pourquoi ne pas simplement faire ce lieu? Beaucoup plus simple, et il est en fait le travail d'un module:

def add_module(name, &block) 
    define_module(name).class_eval(&block) 
end 
+0

semble bizarre - pourquoi ne pas juste class_eval le bloc sur le module lui-même plutôt que d'attendre le 'include'? On dirait que vous réécrivez inutilement toute l'idée d'un module en utilisant le crochet 'inclus'? – horseyguy