在编写带有大量实例变量的大类时,写==,eql?和哈希方法是一个很大的麻烦。有没有办法制作一个“模板类”来自动化这个过程?或者用其他方式。
示例:
class Template
def ==(other)
//Some way of comparing all of self's instance variables to other's.
end
def eql?(other)
self == other
end
def hash
//Some way of XORing the instance variables of self
end
end
class Test < Example
attr_reader :foo
attr_reader :bar
def initialize(foo, bar)
@foo = foo
@bar = bar
end
end
a = Test.new "123", "456"
b = Test.new "123", "456"
a == b
> true
答案 0 :(得分:2)
Test = Struct.new(:foo, :bar)
a = Test.new "123", "456"
b = Test.new "123", "456"
a == b
# => true
答案 1 :(得分:1)
您可以定义字段,以便以后能够反映它们。假设所有实例变量总是存在,并且您希望以类似的方式使用所有这些变量,Ruby已经为您提供了足够的反射,以此方式将其拉出来
class MyFineClass
attr_reader :foo, :bar # and loads of stuff
def initialize(...)
# tons of those ivars initialized
end
def ==(other)
other.is_a?(self.class) &&
# this assumes all instance variables to have attr_readers
instance_variables.all? { |ivar| send(ivar) == other.send(ivar) }
# ...and if they don't, you need instance_variable_get, like this
#instance_variables.all? { |ivar| instance_variable_get(ivar) == other.instance_variable_get(ivar) }
end
end
如果您想要更好地控制字段的处理方式,可以添加“字段”和一点元编程的概念
class MyFineClass
@fields = []
def self.fields; @fields; end
def self.fields(field_name)
attr_reader field_name
@fields << field_name
end
field :foo
field :bar
# and loads more
def initialize(...)
# again, tons of those ivars initialized
end
def ==(other)
other.is_a?(self.class) && self.class.fields.all? { |f| send(f) == other.send(f) }
end
end
接下来,您当然会将fields
内容和==
分开并分配给MyFineClass
。知道了吗?进一步开发该模块,它可能会开始看起来像ActiveModel
或DataMapper
中的某些位。 : - )
答案 2 :(得分:0)
Ruby Facets提供Equitable模块,它几乎可以提供您正在寻找的内容。
你的例子将成为:
class Test
include Equitable(:foo, :bar)
end
如果你不想使用整个宝石,你可以抓住the source - 它很轻。