我想在模块中放入一些代码,如果没有定义某个方法,则抛出错误。 此模块依赖于此方法的外部定义,因为此方法的实现对所有类都不同。这段代码可以帮助开发人员早日知道他们忘记实现该方法,而不是在他们尝试使用模块的功能时。
module MyModule
def self.included(klass)
raise "MyModule: please `def my_method` on #{klass}" unless klass.respond_to?(:my_method)
end
end
如果没有定义方法,我可以很容易地在模块的包含定义中引发错误,但是由于大多数模块都包含在文件的顶部,所以我的必需方法可能是在类中定义的,但不是在我的模块包括在内。
class MyClass
include MyModule
def self.my_method
# ...
end
end
这仍会引发错误:(
只有在类定义中没有定义方法时才可能引发错误吗?几乎需要一个class.onload回调的排序。如果没有,关于如何减少程序员可能包含我们模块的可能性而没有定义这种所需方法的任何其他想法?
答案 0 :(得分:6)
听起来您想要使用method_missing
和define_method
。
如果您使用method_missing
,请不要忘记:
super
。respond_to?
方法查看this question,加上this和that。
更新:
听起来我的目标是像Java或c ++那样进行静态方法检查。这在红宝石中并没有多大意义: - (
因为在红宝石中:
Foo
在类加载时没有方法是没有意义的。关于“on class on load”:真正执行了类定义。试试这个:
class Foo
p "Hi"
end
第一次使用Foo时,您将看到“Hi”。这就是devise之类的东西可以用来做他们的魔法。
class User < ActiveRecord::Base
# **CALL 'devise' method**
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
# **CALL attr_accessible method**
attr_accessible :email, :password, :password_confirmation
end
所以也许通过私有约定,开发人员可以在相关类的底部添加check_class
方法调用?
我理解这个意图,但似乎正在与ruby的设计方式作斗争。
作为一个主要是Java的人,我很欣赏这种挫败感。让我猜一下:重复的代码案例被推到生产中,缺少方法? :-P
<强> UPDATE2:强>
wrt onload
在红宝石中禁止使用冻结类,一直定义新的方法。 (或者一个实例可以获得仅为该实例定义的新方法。)因此检查方法的不存在只是一个快照检查,而不是像静态语言带来的那样确定的检查。这是ruby自己的Halting problem
答案 1 :(得分:4)
如何使用该名称声明一个只会引发错误的方法,以确保用户重新定义该方法?
module MyModule
def my_method
raise "Please implement me"
end
end
class MyClass
include MyModule
def my_method
# do something
end
end
答案 2 :(得分:2)
假设您的程序在启动时需要所有文件而不使用任何autoload
等,您可以在需要所有内容后立即使用以下内容,但在程序实际启动之前:
classes_to_check = Object.constants.find_all do |const|
klass = Object.const_get(c)
klass.ancestors.include?(MyModule) if klass.kind_of?(Module)
end
classes_to_check.each do |klass|
raise "MyModule: please `def my_method` on #{klass}" \
unless klass.respond_to?(:my_method)
end
但是,我个人总是使用Dogbert的解决方案。