Динамически добавлять методы из модулей в конкретные экземпляры класса - PullRequest
3 голосов
/ 14 марта 2011

Вот в чем дело: мне нужно расширить определенные экземпляры класса Box с помощью некоторых методов.Методы, которые мне нужно включить, живут внутри модулей, и я хочу, чтобы экземпляр Box мог включать модули динамически.Теперь я использую крюк с eval:

class Box
  def after_initialize
    if self.injected_module.present?
      eval("class << self; include #{self.injected_module}; end")
    end
  end
end

Он работает довольно хорошо, но я действительно чувствую себя грязным, когда использую eval .Я ищу что-то вроде этого:

module_to_inject = self.injected_module
self.eigenclass.class_eval do
   include module_to_inject
end

, но я не могу заставить собственный класс запускать class_eval без монтирования патчей, например:

class Box; def eigenclass; class << self; self; end end end

Есть ли для меня красивый (и надежный) способ сделать это?

Ответы [ 2 ]

8 голосов
/ 14 марта 2011

Все, что вам нужно для добавления методов из модулей в конкретные экземпляры Box, это метод Kernel#extend:

box.extend MyModule

Кроме того, поскольку глагол «вводить» уже имеет значение в Ruby из Enumerable#inject, лучшим глаголом для описания этого является «расширить».

3 голосов
/ 14 марта 2011

Я не могу следовать твоим рассуждениям там.self.class.class_eval будет отлично работать в вашем примере, например так:

class Box
  def after_initialize
    self.class.class_eval do
      include(self.injected_module)
    end
  end
end

Редактировать: уточнение комментариев.

Используйте Object#extend для включения методов вМодуль как методы класса (как их определение в собственном классе), например:

module MyModule
    def method
        puts "called from #{self.inspect}"
    end
end

class Box
    def self.injected_module
        MyModule
    end

    def require_module
        self.class.class_eval do
            extend self.injected_module
        end
    end
end

b = Box.new
b.require_module
Box.method
# prints "called from Box"
...