我想仅使用模块的名称来访问我的子类。
module MyModule
class UselessName
include OtherModel
# only self method
def self.x
end
end
# No other class
end
我想写MyModule.x
而不是MyModule::UselessName.x
我可以在课堂上转换我的模块,但是我使用RoR Helpers,我希望MyModule仍然是一个模块,而不是一个类。
有办法做到这一点吗? 谢谢;)
答案 0 :(得分:1)
好的,我发现了一种非常糟糕的方式来实现我的意思:
module MyModule
class UselessName
include OtherModule
# have whatever you want here
end
def self.x
# whatever
end
end
所以在你的代码中你可以做到的,我再说一遍,这非常非常糟糕!
MyModule.methods(false).each do |m|
# m = method
# now you can redefine it in your class
# as an instance method. Not sure if this
# is what you want though
MyModule::UselessName.send(:define_method, :m) do
# in this NEW (it's not the same) method you can
# call the method from the module to get the same
# behaviour
MyModule.send(m)
end
end
我不知道如果它在之前的类中覆盖了一个具有相同名称的实例方法,或者如果它抛出异常,那么你必须尝试。
在我看来,你应该过度思考你的应用程序设计,因为这不是应该的样子,但是你去了......
答案 1 :(得分:1)
好的,让我们将问题分成两部分 - 获取此类方法的列表并在模块中创建代理。
获取列表可能有点棘手:
MyModule::UselessName.public_methods(false) - MyModule::UselessName.superclass.public_methods(false)
这里我们从所有公共类方法的列表开始,并从中减去所有超类的公共类方法的列表。
现在,假设我们知道方法的名称,我们需要制作代理方法。
metaclass = class << MyModule; self; end
metaclass.send(:define_method, :x) do |*args, &block|
MyModule::UselessName.send(:x, *args, &block)
end
此代码将在运行时等效于以下定义。
module MyModule
def x(*args, &block)
MyModule::UselessName.send(:x, *args, &block)
end
end
所以让我们把它放在简单的功能中。
def make_proxies(mod, cls)
methods = cls.public_methods(false) - cls.superclass.public_methods(false)
metaclass = class << mod; self; end
methods.each do |method|
metaclass.send(:define_method, method) do |*args, &block|
cls.send(method, *args, &block)
end
end
end
所以现在你只需要为所需的模块和类调用它。请注意,“destination”模块可以与拥有该类的“source”模块不同,因此您可以将所有方法(假设它们具有不同的名称或者您将使用类名称作为前缀)添加到一个模块中。例如。对于你的情况,只需拨打以下电话。
make_proxies(MyModule, MyModule::UselessName)