Наличие одиночного модуля, расширяющего класс

У меня есть одно приложение в моем приложении, которое повторно используется в разных приложениях. Я хочу, чтобы этот синглтон получал некоторые методы по умолчанию из моего класса, но также и имел возможность настраивать модуль / собственный класс. Больше всего я не хочу звонить instance при каждом вызове утилита синглтон.

Вот пример. Допустим, мой класс по умолчанию Universe::Earth, Тогда я хочу Earth модуль в моем приложении, который "расширяет" этот класс.

module Universe
  class Earth
    def self.grow!
      @grown = true
    end
  end
end

module Earth
  class < Universe::Earth << self; end

  grow!
end

Когда это запустить, grow! это NoMethodError,

Пробовал эти подходы:

Class.new(Goodluck::Contest) << self
class < Universe::Earth << self; end
extend Universe::Earth

Как мне заставить это работать?

1 ответ

Это то, что вы ищете?

module Universe
  class Earth
    def self.grow!
      @grown = true
    end
  end
end

module Earth
  Universe::Earth.class_eval do
    define_method(:instance_howdy) do
      puts "instance_howdy!"
    end
  end
  def (Universe::Earth).class_howdy
    puts "class_howdy!"
  end
end

Universe::Earth.methods(false)          #=> [:grow!, :class_howdy]
Universe::Earth.instance_methods(false) #=> [:instance_howdy]
Universe::Earth.new.instance_howdy      #=> instance_howdy!
Universe::Earth.class_howdy             #=> class_howdy!

[Редактировать: если вы просто хотите установить @grown => trueи получить его значение, вам просто нужно:

module Earth
  Universe::Earth.grow! #=> true
end

Убедитесь, что:

Universe::Earth.instance_variable_get("@grown") #=> true

Если вы также хотите добавить метод доступа к переменной экземпляра класса, вы можете сделать это:

def add_class_accessor(c, accessor, var)  
  c.singleton_class.class_eval("#{accessor} :#{var}")
end

Universe::Earth.methods(false)
  #=> [:grow!]

module Earth
  Universe::Earth.grow! #=> true
  add_class_accessor(Universe::Earth, "attr_accessor", "grown")
end

Universe::Earth.methods(false)
  #=> [:grow!, :grown, :grown=]

Universe::Earth.grown
  #=> true
Universe::Earth.grown = "cat"
  #=> "cat"
Universe::Earth.grown
  #=> "cat"

Объект #singleton_class был добавлен в Ruby 1.9.2. Для более ранних версий вы можете сделать это:

def add_class_accessor(c, accessor, var)
  eigenclass = class << c; self; end
  eigenclass.class_eval("#{accessor} :#{var}")
end

Вы могли бы рассмотреть вопрос о add_class_accessor в модуле, который будет включен по мере необходимости. Другие методы, которые вы можете добавить в тот же модуль:

add_instance_method(klass, method, &block)
add_class_method(klass, method, &block)
add_instance_accessor(klass, accessor, var)

: Tide

Другие вопросы по тегам