我正在开发一个应用程序,其中我有一个插件式架构,其中有多个定义API的抽象类,以及具有子类的特定实现,这些子类为抽象类上定义的属性提供方法。可以想象一个通用数据库适配器,它具有连接,表,列等抽象类,以及特定数据库的特定子类。
在尝试DRY时,我将每个抽象类的属性(使用默认值)声明为名为ATTRIBUTES
的类常量数组。由于ruby不支持真正的抽象类,因此如果在抽象类上调用异常,我会动态创建引发异常的方法。例如:
module MyApplication
class Operation
ATTRIBUTES = { name: '', parameters: [], type: :void }
ATTRIBUTES.keys.each do |a|
str = "Method '%s' called on abstract 'MyApplication::Operation' class"
define_method(a) { raise (str % a) }
define_method("#{a}=") { |x| raise (str % "#{a}=") }
end
end
end
我在消息中硬编码类名,因为我不能使用当前类的名称,因为它可能是抽象Operation
类的子类,我希望消息清楚,被调用的方法是在抽象类上。
我有一些以上的抽象类,并且我已经将几乎相同的代码复制到每个类中以创建这些存根方法(只有属性列表和类名称不同)。我已经尝试了很多方法将这些代码放入一个模块中,我可以从每个抽象类中包含(或扩展?),但是我的大脑现在正在试图理清如何获得这个的元编程细节。上班。 :)
有没有人能够将这种常见的,类级别(但是实例制作方法)代码放入模块中以避免重复使用相同的代码?
答案 0 :(得分:2)
这应该做你想要的:
module PluginHelpers
def stub_required_methods(*method_names)
method_names.each do |method_name|
define_method(method_name) do
raise NotImplementedError, "Method #{__method__} must be implemented in #{self.class}"
end
end
end
end
class A
class B
class C
extend PluginHelpers
stub_required_methods(:foo, :bar)
end
end
end
# usage
A::B::C.new.foo # => NotImplementedError: Method foo must be implemented in A::B::C