2010-09-10 67 views
2

我希望能夠定義一個塊,然後從動態生成的模塊/類中評估該塊。似乎我可以用evalblock.binding以某種方式完成這個工作,但我還沒有弄明白。在Ruby中將塊傳遞給class_eval中的嵌套方法?

我有這個作爲基礎:

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 

而且我想用這樣的:

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 

有沒有辦法做這樣的事情?

+0

OK,不使用基於字符串evals,基於使用塊evals,這樣你可以關閉了'block' – horseyguy 2010-09-11 04:59:25

回答

1

這工作:

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" 

編輯:

爲什麼你不這樣做呢?簡單得多,而且它實際上是一個模塊的工作

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

雖然整個想法似乎奇怪 - 爲什麼不僅僅是'class_eval'模塊本身的塊而不是等到include?似乎你不必要地使用'included'鉤子重寫模塊的整個想法? – horseyguy 2010-09-11 06:02:58

相關問題