equatable 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f4686bc5781675b06cad4c4479ead3c786731eeb
4
- data.tar.gz: d31b12f2ead5f8b02b4e141a379f2c47c534fad7
3
+ metadata.gz: 620108deec179ffaf691b2ff6f81495405cf0fa2
4
+ data.tar.gz: 0a5465d39e4ae3acf50061a6f98e1b4d4a19742e
5
5
  SHA512:
6
- metadata.gz: 78dff5b3c98ee0bfba57d3c96b12d5a2b5434b0c72a5168afa0713a36464e7e50bc0fdee611d2308089692f41f033a3223004fad39eb54d1cc67a0946860fde3
7
- data.tar.gz: 7d24be6e59e61d5a7a563c87d450e464c57cfbcd7731e61450990c7f2a122253fdc7501323342c16ac31bd04919da8170799e9b2ea31764e72eded6fbc573086
6
+ metadata.gz: e1d9f0e3655edc3d5dfbd85acb490ab6c8e7b13b64b626eccc7c25783a40a7b9fa54c6afbd8d8546bf316bc5e590071e0af3de40c1c0616a71671573b8942d2d
7
+ data.tar.gz: fc8e67901755723eb5d2c4d3b948d7b789f6685d414593634a837735f5d212b12dc22193ab0b2bd770a5e77dd6ded19ccd22dcfb4209d6b828366d0fc5f11b20
data/.rspec CHANGED
@@ -1,2 +1,2 @@
1
1
  --color
2
- -f s
2
+ --format documentation
data/Gemfile CHANGED
@@ -3,7 +3,7 @@ source 'https://rubygems.org'
3
3
  gemspec
4
4
 
5
5
  group :development do
6
- gem 'rake', '~> 10.1.0'
7
- gem 'rspec', '~> 2.12.0'
6
+ gem 'rake', '~> 10.3.2'
7
+ gem 'rspec', '~> 3.1.0'
8
8
  gem 'yard', '~> 0.8.7'
9
9
  end
data/README.md CHANGED
@@ -27,32 +27,63 @@ Or install it yourself as:
27
27
  It is assumed that your objects are value objects and the only values that affect equality comparison are the ones specified by your attribute readers. Each attribute reader should be a significant field in determining objects values.
28
28
 
29
29
  ```ruby
30
- class Value
30
+ class Point
31
31
  include Equatable
32
32
 
33
- attr_reader :value
33
+ attr_reader :x, :y
34
34
 
35
- def initialize(value)
36
- @value = value
35
+ def initialize(x, y)
36
+ @x, @y = x, y
37
37
  end
38
38
  end
39
39
 
40
- val1 = Value.new(11)
41
- val2 = Value.new(11)
42
- val3 = Value.new(13)
40
+ point_1 = Point.new(1, 1)
41
+ point_2 = Point.new(1, 1)
42
+ point_3 = Point.new(1, 2)
43
43
 
44
- val1 == val2 # => true
45
- val1.hash == val2.hash # => true
46
- val1 eql? val2 # => true
44
+ point_1 == point_2 # => true
45
+ point_1.hash == point_2.hash # => true
46
+ point_1.eql?(point_2) # => true
47
+ point_1.equal?(point_2) # => false
47
48
 
48
- val1 == val3 # => false
49
- val1.hash == val3.hash # => false
50
- val1 eql? val3 # => false
49
+ point_1 == point_3 # => false
50
+ point_1.hash == point_3.hash # => false
51
+ point_1.eql?(point_3) # => false
52
+ point_1.equal?(point_3) # => false
53
+
54
+ point_1.inspect # => "#<Point x=1 y=1>"
51
55
  ```
52
56
 
57
+ ## Attributes
58
+
53
59
  It is important that the attribute readers should allow for performing deterministic computations on class instances. Therefore you should avoid specifying attributes that depend on unreliable resources like IP address that require network access.
54
60
 
55
- Note that adding an extra attribute reader to a subclass will violate the equivalence contract.
61
+ ## Subtypes
62
+
63
+ **Equatable** ensures that any important property of a type holds for its subtypes. However, please note that adding an extra attribute reader to a subclass will violate the equivalence contract, namely, the superclass will be equal to the subclass but reverse won't be true. For example:
64
+
65
+ ```ruby
66
+ class ColorPoint < Point
67
+ attr_reader :color
68
+
69
+ def initialize(x, y, color)
70
+ super(x, y)
71
+ @color = color
72
+ end
73
+ end
74
+
75
+ point = Point.new(1, 1)
76
+ color_point = ColorPoint.new(1, 1, :red)
77
+
78
+ point == color_point # => true
79
+ color_point == point # => false
80
+
81
+ point.hash == color_point.hash # => false
82
+ point.eql?(color_point) # => false
83
+ point.equal?(color_point) # => false
84
+ ```
85
+
86
+ The `ColorPoint` class demonstrates that extending a class with extra value property does not preserve the `equals` contract.
56
87
 
57
88
  ## Contributing
58
89
 
data/Rakefile CHANGED
@@ -1,11 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require "bundler/gem_tasks"
4
- require "rspec/core/rake_task"
5
-
6
- RSpec::Core::RakeTask.new(:spec) do |spec|
7
- spec.pattern = FileList['spec/**/*_spec.rb']
8
- end
9
4
 
10
5
  FileList['tasks/**/*.rake'].each { |task| import task }
11
6
 
@@ -0,0 +1,48 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), '../lib')
2
+
3
+ require 'equatable'
4
+
5
+ class Point
6
+ include Equatable
7
+
8
+ attr_reader :x, :y
9
+
10
+ def initialize(x, y)
11
+ @x, @y = x, y
12
+ end
13
+ end
14
+
15
+ class ColorPoint < Point
16
+ attr_reader :color
17
+
18
+ def initialize(x, y, color)
19
+ super(x, y)
20
+ @color = color
21
+ end
22
+ end
23
+
24
+ point_1 = Point.new(1, 1)
25
+ point_2 = Point.new(1, 1)
26
+ point_3 = Point.new(2, 1)
27
+
28
+ puts point_1 == point_2
29
+ puts point_1.hash == point_2.hash
30
+ puts point_1.eql?(point_2)
31
+ puts point_1.equal?(point_2)
32
+
33
+ puts point_1 == point_3
34
+ puts point_1.hash == point_3.hash
35
+ puts point_1.eql?(point_3)
36
+ puts point_1.equal?(point_3)
37
+
38
+ puts point_1.inspect
39
+
40
+ point = Point.new(1, 1)
41
+ color_point = ColorPoint.new(1, 1, :red)
42
+
43
+ puts 'Subtypes'
44
+ puts point == color_point
45
+ puts color_point == point
46
+ puts point.hash == color_point.hash
47
+ puts point.eql?(color_point)
48
+ puts point.equal?(color_point)
@@ -16,11 +16,9 @@ module Equatable
16
16
  super
17
17
  base.extend(self)
18
18
  base.class_eval do
19
- define_comparison_attrs
20
19
  include Methods
21
20
  define_methods
22
21
  end
23
- self
24
22
  end
25
23
 
26
24
  # Holds all attributes used for comparison.
@@ -41,7 +39,7 @@ module Equatable
41
39
  # @api public
42
40
  def attr_reader(*args)
43
41
  super
44
- @comparison_attrs.concat(args)
42
+ comparison_attrs.concat(args)
45
43
  end
46
44
 
47
45
  # Copy the comparison_attrs into the subclass.
@@ -56,24 +54,25 @@ module Equatable
56
54
 
57
55
  private
58
56
 
59
- # Define class instance #comparison_attrs as an empty array.
57
+ # Define all methods needed for ensuring object's equality.
60
58
  #
61
59
  # @return [undefined]
62
60
  #
63
61
  # @api private
64
- def define_comparison_attrs
65
- instance_variable_set('@comparison_attrs', [])
62
+ def define_methods
63
+ define_comparison_attrs
64
+ define_compare
65
+ define_hash
66
+ define_inspect
66
67
  end
67
68
 
68
- # Define all methods needed for ensuring object's equality.
69
+ # Define class instance #comparison_attrs as an empty array.
69
70
  #
70
71
  # @return [undefined]
71
72
  #
72
73
  # @api private
73
- def define_methods
74
- define_compare
75
- define_hash
76
- define_inspect
74
+ def define_comparison_attrs
75
+ instance_variable_set('@comparison_attrs', [])
77
76
  end
78
77
 
79
78
  # Define a #compare? method to check if the receiver is the same
@@ -85,7 +84,7 @@ module Equatable
85
84
  def define_compare
86
85
  define_method(:compare?) do |comparator, other|
87
86
  klass = self.class
88
- attrs = klass.comparison_attrs || []
87
+ attrs = klass.comparison_attrs
89
88
  attrs.all? do |attr|
90
89
  other.respond_to?(attr) && send(attr).send(comparator, other.send(attr))
91
90
  end
@@ -99,7 +98,7 @@ module Equatable
99
98
  def define_hash
100
99
  define_method(:hash) do
101
100
  klass = self.class
102
- attrs = klass.comparison_attrs || []
101
+ attrs = klass.comparison_attrs
103
102
  ([klass] + attrs.map { |attr| send(attr) }).hash
104
103
  end
105
104
  end
@@ -113,8 +112,8 @@ module Equatable
113
112
  def define_inspect
114
113
  define_method(:inspect) do
115
114
  klass = self.class
116
- name = klass.name || klass.inspect
117
- attrs = klass.comparison_attrs || []
115
+ name = klass.name || klass.inspect
116
+ attrs = klass.comparison_attrs
118
117
  "#<#{name}#{attrs.map { |attr| " #{attr}=#{send(attr).inspect}" }.join}>"
119
118
  end
120
119
  end
@@ -144,7 +143,7 @@ module Equatable
144
143
  #
145
144
  # @api public
146
145
  def ==(other)
147
- is_a?(other.class) && compare?(__method__, other)
146
+ other.is_a?(self.class) && compare?(__method__, other)
148
147
  end
149
148
  end # Methods
150
149
  end # Equatable
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Equatable
4
- VERSION = '0.4.0'
4
+ VERSION = '0.5.0'
5
5
  end
@@ -1,4 +1,4 @@
1
- # -*- encoding: utf-8 -*-
1
+ # encoding: utf-8
2
2
 
3
3
  require 'spec_helper'
4
4
 
@@ -25,30 +25,30 @@ describe Equatable, '#eql?' do
25
25
  context 'with the same object' do
26
26
  let(:other) { object }
27
27
 
28
- it { should be_true }
28
+ it { is_expected.to eql(true) }
29
29
 
30
30
  it 'is symmetric' do
31
- should eql(other.eql?(object))
31
+ is_expected.to eql(other.eql?(object))
32
32
  end
33
33
  end
34
34
 
35
35
  context 'with an equivalent object' do
36
36
  let(:other) { object.dup }
37
37
 
38
- it { should be_true }
38
+ it { is_expected.to eql(true) }
39
39
 
40
40
  it 'is symmetric' do
41
- should eql(other.eql?(object))
41
+ is_expected.to eql(other.eql?(object))
42
42
  end
43
43
  end
44
44
 
45
45
  context 'with an equivalent object of a subclass' do
46
46
  let(:other) { ::Class.new(klass).new(value) }
47
47
 
48
- it { should be_false }
48
+ it { is_expected.to eql(false) }
49
49
 
50
50
  it 'is symmetric' do
51
- should eql(other.eql?(object))
51
+ is_expected.to eql(other.eql?(object))
52
52
  end
53
53
  end
54
54
  end
@@ -1,4 +1,4 @@
1
- # -*- encoding: utf-8 -*-
1
+ # encoding: utf-8
2
2
 
3
3
  require 'spec_helper'
4
4
 
@@ -27,56 +27,58 @@ describe Equatable, '#==' do
27
27
  context 'with the same object' do
28
28
  let(:other) { object }
29
29
 
30
- it { should be_true }
30
+ it { is_expected.to eql(true) }
31
31
 
32
32
  it 'is symmetric' do
33
- should eql(other == object)
33
+ is_expected.to eql(other == object)
34
34
  end
35
35
  end
36
36
 
37
37
  context 'with an equivalent object' do
38
38
  let(:other) { object.dup }
39
39
 
40
- it { should be_true }
40
+ it { is_expected.to eql(true) }
41
41
 
42
42
  it 'is symmetric' do
43
- should eql(other == object)
43
+ is_expected.to eql(other == object)
44
44
  end
45
45
  end
46
46
 
47
47
  context 'with an equivalent object of a subclass' do
48
48
  let(:other) { ::Class.new(klass).new(value) }
49
49
 
50
- it { should be_false }
50
+ it { is_expected.to eql(true) }
51
51
 
52
52
  it 'is not symmetric' do
53
- should_not eql(other == object)
53
+ # LSP, any equality for type should work for subtype but
54
+ # not the other way
55
+ is_expected.not_to eql(other == object)
54
56
  end
55
57
  end
56
58
 
57
59
  context 'with an equivalent object of a superclass' do
58
60
  let(:other) { super_klass.new(value) }
59
61
 
60
- it { should be_true }
62
+ it { is_expected.to eql(false) }
61
63
 
62
64
  it 'is not symmetric' do
63
- should_not eql(other == object)
65
+ is_expected.not_to eql(other == object)
64
66
  end
65
67
  end
66
68
 
67
69
  context 'with an object with a different interface' do
68
70
  let(:other) { Object.new }
69
71
 
70
- it { should be_false }
72
+ it { is_expected.to eql(false) }
71
73
  end
72
74
 
73
75
  context 'with an object of another class' do
74
76
  let(:other) { Class.new.new }
75
77
 
76
- it { should be_false }
78
+ it { is_expected.to eql(false) }
77
79
 
78
80
  it 'is symmetric' do
79
- should eql(other == object)
81
+ is_expected.to eql(other == object)
80
82
  end
81
83
  end
82
84
  end
@@ -1,9 +1,9 @@
1
- # -*- encoding: utf-8 -*-
1
+ # encoding: utf-8
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Equatable, '#include' do
6
- let(:name) { 'Value' }
6
+ let(:name) { 'Value' }
7
7
  let(:object) { described_class }
8
8
 
9
9
  context 'without attributes' do
@@ -12,33 +12,37 @@ describe Equatable, '#include' do
12
12
  subject { klass.new }
13
13
 
14
14
  before {
15
- klass.stub(:name).and_return name
15
+ allow(klass).to receive(:name).and_return(name)
16
16
  klass.send(:include, object)
17
17
  }
18
18
 
19
- it { should respond_to :compare? }
19
+ it { is_expected.to respond_to(:compare?) }
20
20
 
21
- it { should be_instance_of klass }
21
+ it { is_expected.to be_instance_of(klass) }
22
+
23
+ it 'has no attribute names' do
24
+ expect(klass.comparison_attrs).to eq([])
25
+ end
22
26
 
23
27
  describe '#inspect' do
24
- it { subject.inspect.should eql('#<Value>') }
28
+ it { expect(subject.inspect).to eql('#<Value>') }
25
29
  end
26
30
 
27
31
  describe '#hash' do
28
- it { subject.hash.should eql([klass].hash) }
32
+ it { expect(subject.hash).to eql([klass].hash) }
29
33
  end
30
34
 
31
35
  describe '#eql?' do
32
36
  context 'when objects are similar' do
33
37
  let(:other) { subject.dup }
34
38
 
35
- it { subject.eql?(other).should be_true }
39
+ it { expect(subject.eql?(other)).to eql(true) }
36
40
  end
37
41
 
38
42
  context 'when objects are different' do
39
- let(:other) { stub('other') }
43
+ let(:other) { double('other') }
40
44
 
41
- it { subject.eql?(other).should be_false }
45
+ it { expect(subject.eql?(other)).to eql(false) }
42
46
  end
43
47
  end
44
48
 
@@ -46,26 +50,26 @@ describe Equatable, '#include' do
46
50
  context 'when objects are similar' do
47
51
  let(:other) { subject.dup }
48
52
 
49
- it { (subject == other).should be_true }
53
+ it { expect(subject == other).to eql(true) }
50
54
  end
51
55
 
52
56
  context 'when objects are different' do
53
- let(:other) { stub('other') }
57
+ let(:other) { double('other') }
54
58
 
55
- it { (subject == other)}
59
+ it { expect(subject == other).to eql(false) }
56
60
  end
57
61
  end
58
62
 
59
63
  context 'equivalence relation' do
60
- let(:other) { subject.dup }
64
+ let(:other) { subject.dup }
61
65
  let(:another) { other.dup }
62
66
 
63
67
  it 'is not equal to nil reference' do
64
- expect(subject.eql?(nil)).to be_false
68
+ expect(subject.eql?(nil)).to eql(false)
65
69
  end
66
70
 
67
71
  it 'is reflexive' do
68
- expect(subject.eql?(subject)).to be_true
72
+ expect(subject.eql?(subject)).to eql(true)
69
73
  end
70
74
 
71
75
  it 'is symmetric' do
@@ -92,35 +96,37 @@ describe Equatable, '#include' do
92
96
  end
93
97
  }
94
98
 
95
- before {
96
- klass.stub(:name).and_return name
97
- }
99
+ before { allow(klass).to receive(:name).and_return(name) }
98
100
 
99
101
  subject { klass.new(value) }
100
102
 
101
103
  it 'dynamically defines #hash method' do
102
- klass.method_defined?(:hash).should be_true
104
+ expect(klass.method_defined?(:hash)).to eql(true)
103
105
  end
104
106
 
105
107
  it 'dynamically defines #inspect method' do
106
- klass.method_defined?(:inspect).should be_true
108
+ expect(klass.method_defined?(:inspect)).to eql(true)
107
109
  end
108
110
 
109
- it { should respond_to :compare? }
111
+ it { is_expected.to respond_to(:compare?) }
112
+
113
+ it { is_expected.to respond_to(:eql?) }
110
114
 
111
- it { should respond_to :eql? }
115
+ it 'has comparison attribute names' do
116
+ expect(klass.comparison_attrs).to eq([:value])
117
+ end
112
118
 
113
119
  describe '#eql?' do
114
120
  context 'when objects are similar' do
115
121
  let(:other) { subject.dup }
116
122
 
117
- it { subject.eql?(other).should be_true }
123
+ it { expect(subject.eql?(other)).to eql(true) }
118
124
  end
119
125
 
120
126
  context 'when objects are different' do
121
- let(:other) { stub('other') }
127
+ let(:other) { double('other') }
122
128
 
123
- it { subject.eql?(other).should be_false }
129
+ it { expect(subject.eql?(other)).to eql(false) }
124
130
  end
125
131
  end
126
132
 
@@ -128,34 +134,34 @@ describe Equatable, '#include' do
128
134
  context 'when objects are similar' do
129
135
  let(:other) { subject.dup }
130
136
 
131
- it { (subject == other).should be_true }
137
+ it { expect(subject == other).to eql(true) }
132
138
  end
133
139
 
134
140
  context 'when objects are different' do
135
- let(:other) { stub('other') }
141
+ let(:other) { double('other') }
136
142
 
137
- it { (subject == other).should be_false }
143
+ it { expect(subject == other).to eql(false) }
138
144
  end
139
145
  end
140
146
 
141
147
  describe '#inspect' do
142
- it { subject.inspect.should eql('#<Value value=11>') }
148
+ it { expect(subject.inspect).to eql('#<Value value=11>') }
143
149
  end
144
150
 
145
151
  describe '#hash' do
146
- it { subject.hash.should eql( ([klass] + [value]).hash) }
152
+ it { expect(subject.hash).to eql( ([klass] + [value]).hash) }
147
153
  end
148
154
 
149
155
  context 'equivalence relation' do
150
- let(:other) { subject.dup }
156
+ let(:other) { subject.dup }
151
157
  let(:another) { other.dup }
152
158
 
153
159
  it 'is not equal to nil reference' do
154
- expect(subject.eql?(nil)).to be_false
160
+ expect(subject.eql?(nil)).to eql(false)
155
161
  end
156
162
 
157
163
  it 'is reflexive' do
158
- expect(subject.eql?(subject)).to be_true
164
+ expect(subject.eql?(subject)).to eql(true)
159
165
  end
160
166
 
161
167
  it 'is symmetric' do
@@ -1,4 +1,4 @@
1
- # -*- encoding: utf-8 -*-
1
+ # encoding: utf-8
2
2
 
3
3
  require 'spec_helper'
4
4
 
@@ -20,31 +20,29 @@ describe Equatable, 'subclass' do
20
20
  }
21
21
  let(:subclass) { ::Class.new(klass) }
22
22
 
23
- before {
24
- klass.stub(:name).and_return name
25
- }
26
-
27
23
  subject { subclass.new(value) }
28
24
 
29
- it { subclass.superclass.should == klass }
25
+ before { allow(klass).to receive(:name).and_return(name) }
30
26
 
31
- it { should respond_to :value }
27
+ it { expect(subclass.superclass).to eq(klass) }
28
+
29
+ it { is_expected.to respond_to(:value) }
32
30
 
33
31
  describe '#inspect' do
34
- it { subject.inspect.should eql('#<Value value=11>') }
32
+ it { expect(subject.inspect).to eql('#<Value value=11>') }
35
33
  end
36
34
 
37
35
  describe '#eql?' do
38
36
  context 'when objects are similar' do
39
37
  let(:other) { subject.dup }
40
38
 
41
- it { subject.eql?(other).should be_true }
39
+ it { expect(subject.eql?(other)).to eql(true) }
42
40
  end
43
41
 
44
42
  context 'when objects are different' do
45
- let(:other) { stub('other') }
43
+ let(:other) { double('other') }
46
44
 
47
- it { subject.eql?(other).should be_false }
45
+ it { expect(subject.eql?(other)).to eql(false) }
48
46
  end
49
47
  end
50
48
 
@@ -52,15 +50,14 @@ describe Equatable, 'subclass' do
52
50
  context 'when objects are similar' do
53
51
  let(:other) { subject.dup }
54
52
 
55
- it { (subject == other).should be_true }
53
+ it { expect(subject == other).to eql(true) }
56
54
  end
57
55
 
58
56
  context 'when objects are different' do
59
- let(:other) { stub('other') }
57
+ let(:other) { double('other') }
60
58
 
61
- it { (subject == other)}
59
+ it { expect(subject == other).to eql(false) }
62
60
  end
63
61
  end
64
62
  end
65
-
66
63
  end
@@ -1,11 +1,10 @@
1
- require 'rubygems'
1
+ # encoding: utf-8
2
2
 
3
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
- $LOAD_PATH.unshift(File.dirname(__FILE__))
5
-
6
- require 'rspec'
7
3
  require 'equatable'
8
4
 
9
5
  RSpec.configure do |config|
10
- config.order = :rand
6
+ config.run_all_when_everything_filtered = true
7
+ config.filter_run :focus
8
+ config.order = 'random'
9
+ config.raise_errors_for_deprecations!
11
10
  end
@@ -0,0 +1,10 @@
1
+ # encoding: utf-8
2
+
3
+ begin
4
+ require "rspec/core/rake_task"
5
+ RSpec::Core::RakeTask.new(:spec) do |spec|
6
+ spec.pattern = 'spec/**{,/*/**}/*_spec.rb'
7
+ end
8
+ rescue LoadError
9
+ $stderr.puts("Cannot load rspec task.")
10
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: equatable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Murach
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-15 00:00:00.000000000 Z
11
+ date: 2014-09-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -43,6 +43,7 @@ files:
43
43
  - README.md
44
44
  - Rakefile
45
45
  - equatable.gemspec
46
+ - examples/point.rb
46
47
  - lib/equatable.rb
47
48
  - lib/equatable/version.rb
48
49
  - spec/equatable/eql_spec.rb
@@ -50,6 +51,7 @@ files:
50
51
  - spec/equatable/include_spec.rb
51
52
  - spec/equatable/subclass_spec.rb
52
53
  - spec/spec_helper.rb
54
+ - tasks/spec.rake
53
55
  homepage: http://github.com/peter-murach/equatable
54
56
  licenses: []
55
57
  metadata: {}