Rails: динамически определять метод класса, основанный на имени родительского класса в модуле/проблема
Я хочу динамически генерировать метод класса в Mixin на основе имени класса, которое включает этот Mixin.
Вот мой текущий код:
module MyModule
extend ActiveSupport::Concern
# def some_methods
# ...
# end
module ClassMethods
# Here is where I'm stuck...
define_method "#{self.name.downcase}_status" do
# do something...
end
end
end
class MyClass < ActiveRecord::Base
include MyModule
end
# What I'm trying to achieve:
MyClass.myclass_status
Но это дает мне следующее имя метода:
MyClass.mymodule::classmethods_status
Получение имени базового класса внутри определения метода работает (self, self.name...), но я не могу заставить его работать для имени метода...
До сих пор я пробовал
define_method "#{self}"
define_method "#{self.name"
define_method "#{self.class}"
define_method "#{self.class.name}"
define_method "#{self.model_name}"
define_method "#{self.parent.name}"
Но ничто из этого не похоже на трюк:/
Есть ли способ получить имя базового класса (не уверен, что вызывать класс, который включает мой модуль). Я уже несколько часов борюсь с этой проблемой, и я не могу понять, как это сделать: (
Спасибо!
Ответы
Ответ 1
Вы не можете сделать это так - на данный момент еще не известно, какие классы (или классы) включают модуль.
Если вы определяете метод self.included
, он будет вызываться каждый раз, когда модуль включен, и предмет, выполняющий включение, будет передан в качестве аргумента. Альтернативно, поскольку вы используете AS:: Concern, вы можете сделать
included do
#code here is executed in the context of the including class
end
Ответ 2
Я нашел чистое решение: используя define_singleton_method
(доступно в ruby v1.9.3)
module MyModule
extend ActiveSupport::Concern
included do
define_singleton_method "#{self.name}_status" do
# do stuff
end
end
# def some_methods
# ...
# end
module ClassMethods
# Not needed anymore!
end
end
Ответ 3
Вы можете сделать что-то вроде этого:
module MyModule
def self.included(base)
(class << base; self; end).send(:define_method, "#{base.name.downcase}_status") do
puts "Hey!"
end
base.extend(ClassMethods)
end
module ClassMethods
def other_method
puts "Hi!"
end
end
end
class MyClass
include MyModule
end
MyClass.myclass_status
MyClass.other_method
Ответ 4
Работает для extend
:
module MyModule
def self.extended who
define_method "#{who.name.downcase}_status" do
p "Inside"
end
end
end
class MyClass
extend MyModule
end
MyClass.myclass_status