将块传递到 Ruby 中的 class_eval 内的嵌套方法中?

发布于 2024-09-18 18:52:07 字数 1030 浏览 6 评论 0原文

我希望能够定义一个块,然后从动态生成的模块/类中评估该块。似乎我可以使用 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

有什么方法可以做类似的事情吗?

I want to be able to define a block, and later evaluate that block from within a dynamically generated module/class. It seems like I could accomplish this somehow using eval and block.binding, but I haven't figured it out.

I have this as the 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

And I want to use it like this:

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

Is there any way to do something like that?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

半﹌身腐败 2024-09-25 18:52:07

这有效:

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

This works:

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:

Why don't you just do this instead? Much simpler, and it's actually the job of a module:

def add_module(name, &block)
    define_module(name).class_eval(&block)
end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文