我正在尝试理解一些Ruby元编程概念。
我想我理解类,对象和元类。不幸的是,我对 非常不清楚包含的模块在其实例/'类'变量 方面究竟会发生什么。
这是一个人为的问题,其解决方案将回答我的问题:
假设我正在编写自己糟糕的Rails“验证”方法,但我希望它来自混合模块,而不是基类 :< / p>
module MyMixin
# Somehow validates_wordiness_of() is defined/injected here.
def valid?
# Run through all of the fields enumerated in a class that uses
# "validate_wordiness_of" and make sure they .match(/\A\w+\z/)
end
end
class MyClass
include MyMixin
# Now I can call this method in my class definition and it will
# validate the word-ness of my string fields.
validate_wordiness_of :string_field1, :string_field2, :string_field3
# Insert rest of class here...
end
# This should work.
MyMixin.new.valid?
好的,那么如何在validate_wordiness_of调用(在MyClass中)中存储该字段列表,以便它可以在有效的情况下使用?方法(来自MyMixin)?
或者我是否会出错?任何信息都会非常感激!
答案 0 :(得分:2)
所以这里有两种替代方法:
通过“直接”访问
module MyMixin
def self.included(base)
base.extend(ClassMethods)
end
def wordy?(value)
value.length > 2
end
module ClassMethods
def validates_wordiness_of(*attrs)
define_method(:valid?) do
attrs.all? do |attr|
wordy?(send(attr))
end
end
end
end
end
class MyClass
include MyMixin
validates_wordiness_of :foo, :bar
def foo
"a"
end
def bar
"asrtioenarst"
end
end
puts MyClass.new.valid?
此方法的缺点是对validates_wordiness_of
的几次连续调用将相互覆盖。
所以你不能这样做:
validates_wordiness_of :foo
validates_wordiness_of :bar
在课程中保存经过验证的属性名称
你也可以这样做:
require 'set'
module MyMixin
def self.included(base)
base.extend(ClassMethods)
end
module Validation
def valid?
self.class.wordy_attributes.all? do |attr|
wordy?(self.send(attr))
end
end
def wordy?(value)
value.length > 2
end
end
module ClassMethods
def wordy_attributes
@wordy_attributes ||= Set.new
end
def validates_wordiness_of(*attrs)
include(Validation) unless validation_included?
wordy_attributes.merge(attrs)
end
def validation_included?
ancestors.include?(Validation)
end
end
end
class MyClass
include MyMixin
validates_wordiness_of :foo, :bar
def foo
"aastrarst"
end
def bar
"asrtioenarst"
end
end
MyClass.new.valid?
# => true
在您实际添加验证之前,我选择使valid?
方法不可用。这可能是不明智的。如果没有验证,你可能会让它返回true。
如果您引入其他类型的验证,此解决方案将很快变得难以处理。在这种情况下,我将开始在验证器对象中包装验证。