Передача блоков во вложенный метод внутри class_eval в Ruby? - PullRequest
2 голосов
/ 10 сентября 2010

Я хочу иметь возможность определить блок, а затем оценить этот блок из динамически сгенерированного модуля / класса.Кажется, что я мог бы сделать это как-то, используя eval и block.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

Есть ли способ сделать что-то подобное?

1 Ответ

1 голос
/ 11 сентября 2010

Это работает:

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:

Почему бы тебе просто не сделать это вместо этого? Гораздо проще, и это на самом деле работа модуля:

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