【问题标题】:Passing blocks into nested method within class_eval in Ruby?将块传递给Ruby中class_eval中的嵌套方法?
【发布时间】:2010-09-10 16:18:11
【问题描述】:

我希望能够定义一个块,然后在动态生成的模块/类中评估该块。似乎我可以使用evalblock.binding 以某种方式完成此操作,但我还没有弄清楚。

我以此为基础:

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

有什么办法可以做这样的事情吗?

【问题讨论】:

  • 好的,不要使用基于字符串的评估,使用基于块的评估,这样你就可以关闭block

标签: ruby metaprogramming eval


【解决方案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"

编辑:

你为什么不直接这样做呢?简单得多,它实际上是一个模块的job

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

【讨论】:

  • 虽然整个想法看起来很奇怪——为什么不只是 class_eval 模块本身的块而不是等到 include ?似乎您使用 included 钩子不必要地重写了模块的整个想法???
猜你喜欢
  • 2014-01-05
  • 1970-01-01
  • 1970-01-01
  • 2014-11-26
  • 2012-06-10
  • 1970-01-01
  • 1970-01-01
  • 2012-03-15
  • 2011-04-03
相关资源
最近更新 更多