twitter-status-bot/.gems/gems/equalizer-0.0.9/lib/equalizer.rb

123 lines
2.6 KiB
Ruby

# encoding: utf-8
# Define equality, equivalence and inspection methods
class Equalizer < Module
# Initialize an Equalizer with the given keys
#
# Will use the keys with which it is initialized to define #cmp?,
# #hash, and #inspect
#
# @param [Array<Symbol>] keys
#
# @return [undefined]
#
# @api private
def initialize(*keys)
@keys = keys
define_methods
freeze
end
private
# Hook called when module is included
#
# @param [Module] descendant
# the module or class including Equalizer
#
# @return [self]
#
# @api private
def included(descendant)
super
descendant.module_eval { include Methods }
end
# Define the equalizer methods based on #keys
#
# @return [undefined]
#
# @api private
def define_methods
define_cmp_method
define_hash_method
define_inspect_method
end
# Define an #cmp? method based on the instance's values identified by #keys
#
# @return [undefined]
#
# @api private
def define_cmp_method
keys = @keys
define_method(:cmp?) do |comparator, other|
keys.all? { |key| send(key).send(comparator, other.send(key)) }
end
private :cmp?
end
# Define a #hash method based on the instance's values identified by #keys
#
# @return [undefined]
#
# @api private
def define_hash_method
keys = @keys
define_method(:hash) do ||
keys.map(&method(:send)).push(self.class).hash
end
end
# Define an inspect method that reports the values of the instance's keys
#
# @return [undefined]
#
# @api private
def define_inspect_method
keys = @keys
define_method(:inspect) do ||
klass = self.class
name = klass.name || klass.inspect
"#<#{name}#{keys.map { |key| " #{key}=#{send(key).inspect}" }.join}>"
end
end
# The comparison methods
module Methods
# Compare the object with other object for equality
#
# @example
# object.eql?(other) # => true or false
#
# @param [Object] other
# the other object to compare with
#
# @return [Boolean]
#
# @api public
def eql?(other)
instance_of?(other.class) && cmp?(__method__, other)
end
# Compare the object with other object for equivalency
#
# @example
# object == other # => true or false
#
# @param [Object] other
# the other object to compare with
#
# @return [Boolean]
#
# @api public
def ==(other)
other = coerce(other) if respond_to?(:coerce, true)
other.kind_of?(self.class) && cmp?(__method__, other)
end
end # module Methods
end # class Equalizer