Наличие одиночного модуля, расширяющего класс
У меня есть одно приложение в моем приложении, которое повторно используется в разных приложениях. Я хочу, чтобы этот синглтон получал некоторые методы по умолчанию из моего класса, но также и имел возможность настраивать модуль / собственный класс. Больше всего я не хочу звонить 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