Use dkubb/equalizer and remove vendored version
This commit is contained in:
parent
3de69d832d
commit
933364b800
9 changed files with 7 additions and 400 deletions
1
Gemfile
1
Gemfile
|
@ -5,6 +5,7 @@ gemspec
|
|||
gem 'immutable', :git => 'https://github.com/dkubb/immutable.git', :branch => :experimental
|
||||
gem 'descendants_tracker', :git => 'https://github.com/dkubb/descendants_tracker.git'
|
||||
gem 'abstract_class', :git => 'https://github.com/dkubb/abstract_class.git'
|
||||
gem 'equalizer', :git => 'https://github.com/dkubb/equalizer.git'
|
||||
gem 'to_source', :git => 'https://github.com/mbj/to_source.git'
|
||||
|
||||
group :development do
|
||||
|
|
|
@ -3,20 +3,19 @@ require 'ice_nine'
|
|||
require 'abstract_class'
|
||||
require 'descendants_tracker'
|
||||
require 'securerandom'
|
||||
require 'equalizer'
|
||||
require 'to_source'
|
||||
require 'ice_nine'
|
||||
require 'ice_nine/core_ext/object'
|
||||
require 'backports'
|
||||
require 'diff/lcs'
|
||||
require 'diff/lcs/hunk'
|
||||
require 'pp'
|
||||
|
||||
# Library namespace
|
||||
module Mutant
|
||||
end
|
||||
|
||||
require 'mutant/support/method_object'
|
||||
require 'mutant/support/equalizer'
|
||||
require 'mutant/helper'
|
||||
require 'mutant/random'
|
||||
require 'mutant/mutator'
|
||||
|
|
|
@ -1,125 +0,0 @@
|
|||
# encoding: utf-8
|
||||
|
||||
module Mutant
|
||||
|
||||
# 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 = Immutable.freeze_object(keys)
|
||||
define_methods
|
||||
include_comparison_methods
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# 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 { |key| send(key).hash }.reduce(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
|
||||
|
||||
# Include the #eql? and #== methods
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
def include_comparison_methods
|
||||
module_eval do
|
||||
include Methods, Immutable
|
||||
memoize :hash
|
||||
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) and 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)
|
||||
return false unless self.class <=> other.class
|
||||
cmp?(__method__, other)
|
||||
end
|
||||
|
||||
end # module Methods
|
||||
end # class Equalizer
|
||||
end # module Mutant
|
|
@ -21,6 +21,7 @@ Gem::Specification.new do |gem|
|
|||
gem.add_runtime_dependency('descendants_tracker', '~> 0.0.1')
|
||||
gem.add_runtime_dependency('backports', '~> 2.6')
|
||||
gem.add_runtime_dependency('immutable', '~> 0.0.1')
|
||||
gem.add_runtime_dependency('equalizer', '~> 0.0.1')
|
||||
gem.add_runtime_dependency('abstract_class', '~> 0.0.1')
|
||||
gem.add_runtime_dependency('diff-lcs', '~> 1.1.3')
|
||||
end
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Mutant, 'runner' do
|
||||
before do
|
||||
pending
|
||||
end
|
||||
|
||||
around do |example|
|
||||
Dir.chdir(TestApp.root) do
|
||||
example.run
|
||||
|
|
|
@ -1,138 +0,0 @@
|
|||
# encoding: utf-8
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Mutant::Equalizer, '.new' do
|
||||
let(:object) { described_class }
|
||||
let(:name) { 'User' }
|
||||
let(:klass) { ::Class.new }
|
||||
|
||||
context 'with no keys' do
|
||||
subject { object.new }
|
||||
|
||||
before do
|
||||
# specify the class #name method
|
||||
klass.stub(:name).and_return(name)
|
||||
klass.send(:include, subject)
|
||||
end
|
||||
|
||||
let(:instance) { klass.new }
|
||||
|
||||
it { should be_instance_of(object) }
|
||||
|
||||
it 'defines #hash and #inspect methods dynamically' do
|
||||
subject.public_instance_methods(false).map(&:to_s).should =~ %w[ hash inspect ]
|
||||
end
|
||||
|
||||
describe '#eql?' do
|
||||
context 'when the objects are similar' do
|
||||
let(:other) { instance.dup }
|
||||
|
||||
it { instance.eql?(other).should be(true) }
|
||||
end
|
||||
|
||||
context 'when the objects are different' do
|
||||
let(:other) { stub('other') }
|
||||
|
||||
it { instance.eql?(other).should be(false) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#==' do
|
||||
context 'when the objects are similar' do
|
||||
let(:other) { instance.dup }
|
||||
|
||||
it { (instance == other).should be(true) }
|
||||
end
|
||||
|
||||
context 'when the objects are different' do
|
||||
let(:other) { stub('other') }
|
||||
|
||||
it { (instance == other).should be(false) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#hash' do
|
||||
it { instance.hash.should eql(klass.hash) }
|
||||
|
||||
it 'memoizes the hash code' do
|
||||
instance.hash.should eql(instance.memoized(:hash))
|
||||
end
|
||||
end
|
||||
|
||||
describe '#inspect' do
|
||||
it { instance.inspect.should eql('#<User>') }
|
||||
end
|
||||
end
|
||||
|
||||
context 'with keys' do
|
||||
subject { object.new(*keys) }
|
||||
|
||||
let(:keys) { [ :first_name ].freeze }
|
||||
let(:first_name) { 'John' }
|
||||
let(:instance) { klass.new(first_name) }
|
||||
|
||||
let(:klass) do
|
||||
::Class.new do
|
||||
attr_reader :first_name
|
||||
|
||||
def initialize(first_name)
|
||||
@first_name = first_name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
# specify the class #inspect method
|
||||
klass.stub(:name).and_return(nil)
|
||||
klass.stub(:inspect).and_return(name)
|
||||
klass.send(:include, subject)
|
||||
end
|
||||
|
||||
it { should be_instance_of(object) }
|
||||
|
||||
it 'defines #hash and #inspect methods dynamically' do
|
||||
subject.public_instance_methods(false).map(&:to_s).should =~ %w[ hash inspect ]
|
||||
end
|
||||
|
||||
describe '#eql?' do
|
||||
context 'when the objects are similar' do
|
||||
let(:other) { instance.dup }
|
||||
|
||||
it { instance.eql?(other).should be(true) }
|
||||
end
|
||||
|
||||
context 'when the objects are different' do
|
||||
let(:other) { stub('other') }
|
||||
|
||||
it { instance.eql?(other).should be(false) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#==' do
|
||||
context 'when the objects are similar' do
|
||||
let(:other) { instance.dup }
|
||||
|
||||
it { (instance == other).should be(true) }
|
||||
end
|
||||
|
||||
context 'when the objects are different' do
|
||||
let(:other) { stub('other') }
|
||||
|
||||
it { (instance == other).should be(false) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#hash' do
|
||||
it { instance.hash.should eql(klass.hash ^ first_name.hash) }
|
||||
|
||||
it 'memoizes the hash code' do
|
||||
instance.hash.should eql(instance.memoized(:hash))
|
||||
end
|
||||
end
|
||||
|
||||
describe '#inspect' do
|
||||
it { instance.inspect.should eql('#<User first_name="John">') }
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,49 +0,0 @@
|
|||
# encoding: utf-8
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Mutant::Equalizer::Methods, '#eql?' do
|
||||
subject { object.eql?(other) }
|
||||
|
||||
let(:object) { described_class.new }
|
||||
|
||||
let(:described_class) do
|
||||
Class.new do
|
||||
include Mutant::Equalizer::Methods
|
||||
|
||||
def cmp?(comparator, other)
|
||||
!!(comparator and other)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with the same object' do
|
||||
let(:other) { object }
|
||||
|
||||
it { should be(true) }
|
||||
|
||||
it 'is symmetric' do
|
||||
should eql(other.eql?(object))
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an equivalent object' do
|
||||
let(:other) { object.dup }
|
||||
|
||||
it { should be(true) }
|
||||
|
||||
it 'is symmetric' do
|
||||
should eql(other.eql?(object))
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an equivalent object of a subclass' do
|
||||
let(:other) { Class.new(described_class).new }
|
||||
|
||||
it { should be(false) }
|
||||
|
||||
it 'is symmetric' do
|
||||
should eql(other.eql?(object))
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,85 +0,0 @@
|
|||
# encoding: utf-8
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe Mutant::Equalizer::Methods, '#==' do
|
||||
subject { object == other }
|
||||
|
||||
let(:object) { described_class.new(true) }
|
||||
|
||||
let(:described_class) do
|
||||
Class.new do
|
||||
include Mutant::Equalizer::Methods
|
||||
|
||||
attr_reader :boolean
|
||||
|
||||
def initialize(boolean)
|
||||
@boolean = boolean
|
||||
end
|
||||
|
||||
def cmp?(comparator, other)
|
||||
boolean.send(comparator, other.boolean)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with the same object' do
|
||||
let(:other) { object }
|
||||
|
||||
it { should be(true) }
|
||||
|
||||
it 'is symmetric' do
|
||||
should eql(other == object)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an equivalent object' do
|
||||
let(:other) { object.dup }
|
||||
|
||||
it { should be(true) }
|
||||
|
||||
it 'is symmetric' do
|
||||
should eql(other == object)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an equivalent object of a subclass' do
|
||||
let(:other) { Class.new(described_class).new(true) }
|
||||
|
||||
it { should be(true) }
|
||||
|
||||
it 'is symmetric' do
|
||||
should eql(other == object)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an object of another class' do
|
||||
let(:other) { Class.new.new }
|
||||
|
||||
it { should be(false) }
|
||||
|
||||
it 'is symmetric' do
|
||||
should eql(other == object)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an equivalent object after coercion' do
|
||||
let(:other) { Object.new }
|
||||
|
||||
before do
|
||||
# declare a private #coerce method
|
||||
described_class.class_eval do
|
||||
def coerce(other)
|
||||
self.class.new(!!other)
|
||||
end
|
||||
private :coerce
|
||||
end
|
||||
end
|
||||
|
||||
it { should be(true) }
|
||||
|
||||
it 'is not symmetric' do
|
||||
should_not eql(other == object)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -25,7 +25,6 @@ describe Mutant::Matcher::ObjectSpace, '#each' do
|
|||
|
||||
it_should_behave_like 'an #each method'
|
||||
|
||||
|
||||
it 'should yield subjects' do
|
||||
expect { subject }.to change { yields }.from([]).to([subject_a, subject_b])
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue