dry-equalizer 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.codeclimate.yml +12 -0
- data/.github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md +10 -0
- data/.github/ISSUE_TEMPLATE/---bug-report.md +34 -0
- data/.github/ISSUE_TEMPLATE/---feature-request.md +18 -0
- data/.github/workflows/docsite.yml +34 -0
- data/.github/workflows/sync_configs.yml +34 -0
- data/.rspec +2 -4
- data/.rubocop.yml +89 -0
- data/CHANGELOG.md +46 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/CONTRIBUTING.md +29 -11
- data/Gemfile +12 -4
- data/LICENSE +17 -18
- data/README.md +23 -29
- data/Rakefile +5 -2
- data/docsite/source/index.html.md +86 -0
- data/dry-equalizer.gemspec +2 -6
- data/lib/dry/equalizer.rb +34 -20
- data/lib/dry/equalizer/version.rb +2 -4
- data/spec/spec_helper.rb +5 -11
- data/spec/support/config_alias.rb +0 -2
- data/spec/unit/equalizer/included_spec.rb +1 -3
- data/spec/unit/equalizer/methods/eql_predicate_spec.rb +1 -3
- data/spec/unit/equalizer/methods/equality_operator_spec.rb +1 -3
- data/spec/unit/equalizer/universal_spec.rb +88 -8
- metadata +14 -36
- data/.travis.yml +0 -22
- data/config/devtools.yml +0 -2
- data/config/flay.yml +0 -4
- data/config/flog.yml +0 -3
- data/config/mutant.yml +0 -2
- data/config/reek.yml +0 -105
- data/config/rubocop.yml +0 -115
- data/config/yardstick.yml +0 -34
data/Rakefile
CHANGED
@@ -0,0 +1,86 @@
|
|
1
|
+
---
|
2
|
+
title: Introduction & Usage
|
3
|
+
description: Simple mixin providing equality, equivalence and inspection methods
|
4
|
+
layout: gem-single
|
5
|
+
order: 5
|
6
|
+
type: gem
|
7
|
+
name: dry-equalizer
|
8
|
+
---
|
9
|
+
|
10
|
+
`dry-equalizer` is a simple mixin that can be used to add instance variable based equality, equivalence and inspection methods to your objects.
|
11
|
+
|
12
|
+
### Usage
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
require 'dry-equalizer'
|
16
|
+
|
17
|
+
class GeoLocation
|
18
|
+
include Dry::Equalizer(:latitude, :longitude)
|
19
|
+
|
20
|
+
attr_reader :latitude, :longitude
|
21
|
+
|
22
|
+
def initialize(latitude, longitude)
|
23
|
+
@latitude, @longitude = latitude, longitude
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
point_a = GeoLocation.new(1, 2)
|
28
|
+
point_b = GeoLocation.new(1, 2)
|
29
|
+
point_c = GeoLocation.new(2, 2)
|
30
|
+
|
31
|
+
point_a.inspect # => "#<GeoLocation latitude=1 longitude=2>"
|
32
|
+
|
33
|
+
point_a == point_b # => true
|
34
|
+
point_a.hash == point_b.hash # => true
|
35
|
+
point_a.eql?(point_b) # => true
|
36
|
+
point_a.equal?(point_b) # => false
|
37
|
+
|
38
|
+
point_a == point_c # => false
|
39
|
+
point_a.hash == point_c.hash # => false
|
40
|
+
point_a.eql?(point_c) # => false
|
41
|
+
point_a.equal?(point_c) # => false
|
42
|
+
```
|
43
|
+
|
44
|
+
### Configuration options
|
45
|
+
|
46
|
+
#### `inspect`
|
47
|
+
|
48
|
+
Use `inspect` option to skip `#inspect` method overloading:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
class Foo
|
52
|
+
include Dry::Equalizer(:a, inspect: false)
|
53
|
+
|
54
|
+
attr_reader :a, :b
|
55
|
+
|
56
|
+
def initialize(a, b)
|
57
|
+
@a, @b = a, b
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
Foo.new(1, 2).inspect
|
62
|
+
# => "#<Foo:0x00007fbc9c0487f0 @a=1, @b=2>"
|
63
|
+
```
|
64
|
+
|
65
|
+
#### `immutable`
|
66
|
+
|
67
|
+
For objects that are immutable it doesn't make sense to calculate `#hash` every time it's called. To memoize hash use `immutable` option:
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
class ImmutableHash
|
71
|
+
include Dry::Equalizer(:foo, :bar, immutable: true)
|
72
|
+
|
73
|
+
attr_accessor :foo, :bar
|
74
|
+
|
75
|
+
def initialize(foo, bar)
|
76
|
+
@foo, @bar = foo, bar
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
obj = ImmutableHash.new('foo', 'bar')
|
81
|
+
old_hash = obj.hash
|
82
|
+
obj.foo = 'changed'
|
83
|
+
old_hash == obj.hash
|
84
|
+
# => true
|
85
|
+
```
|
86
|
+
|
data/dry-equalizer.gemspec
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
require File.expand_path('../lib/dry/equalizer/version', __FILE__)
|
4
2
|
|
5
3
|
Gem::Specification.new do |gem|
|
@@ -9,7 +7,7 @@ Gem::Specification.new do |gem|
|
|
9
7
|
gem.email = %w[dan.kubb@gmail.com mbj@schirp-dso.com]
|
10
8
|
gem.description = 'Module to define equality, equivalence and inspection methods'
|
11
9
|
gem.summary = gem.description
|
12
|
-
gem.homepage = 'https://github.com/
|
10
|
+
gem.homepage = 'https://github.com/dry-rb/dry-equalizer'
|
13
11
|
gem.licenses = 'MIT'
|
14
12
|
|
15
13
|
gem.require_paths = %w[lib]
|
@@ -17,7 +15,5 @@ Gem::Specification.new do |gem|
|
|
17
15
|
gem.test_files = `git ls-files -- spec/{unit,integration}`.split("\n")
|
18
16
|
gem.extra_rdoc_files = %w[LICENSE README.md CONTRIBUTING.md]
|
19
17
|
|
20
|
-
gem.required_ruby_version = '>= 2.
|
21
|
-
|
22
|
-
gem.add_development_dependency('bundler', '~> 1.3', '>= 1.3.5')
|
18
|
+
gem.required_ruby_version = '>= 2.4.0'
|
23
19
|
end
|
data/lib/dry/equalizer.rb
CHANGED
@@ -1,11 +1,9 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module Dry
|
4
2
|
# Build an equalizer module for the inclusion in other class
|
5
3
|
#
|
6
4
|
# @api public
|
7
|
-
def self.Equalizer(*keys)
|
8
|
-
Dry::Equalizer.new(*keys)
|
5
|
+
def self.Equalizer(*keys, **options)
|
6
|
+
Dry::Equalizer.new(*keys, **options)
|
9
7
|
end
|
10
8
|
|
11
9
|
# Define equality, equivalence and inspection methods
|
@@ -16,13 +14,16 @@ module Dry
|
|
16
14
|
# #hash, and #inspect
|
17
15
|
#
|
18
16
|
# @param [Array<Symbol>] keys
|
17
|
+
# @param [Hash] options
|
18
|
+
# @option options [Boolean] :inspect whether to define #inspect method
|
19
|
+
# @option options [Boolean] :immutable whether to memoize #hash method
|
19
20
|
#
|
20
21
|
# @return [undefined]
|
21
22
|
#
|
22
23
|
# @api private
|
23
|
-
def initialize(*keys)
|
24
|
-
@keys = keys
|
25
|
-
define_methods
|
24
|
+
def initialize(*keys, **options)
|
25
|
+
@keys = keys.uniq
|
26
|
+
define_methods(**options)
|
26
27
|
freeze
|
27
28
|
end
|
28
29
|
|
@@ -43,13 +44,16 @@ module Dry
|
|
43
44
|
|
44
45
|
# Define the equalizer methods based on #keys
|
45
46
|
#
|
47
|
+
# @param [Boolean] inspect whether to define #inspect method
|
48
|
+
# @param [Boolean] immutable whether to memoize #hash method
|
49
|
+
#
|
46
50
|
# @return [undefined]
|
47
51
|
#
|
48
52
|
# @api private
|
49
|
-
def define_methods
|
53
|
+
def define_methods(inspect: true, immutable: false)
|
50
54
|
define_cmp_method
|
51
|
-
define_hash_method
|
52
|
-
define_inspect_method
|
55
|
+
define_hash_method(immutable: immutable)
|
56
|
+
define_inspect_method if inspect
|
53
57
|
end
|
54
58
|
|
55
59
|
# Define an #cmp? method based on the instance's values identified by #keys
|
@@ -72,10 +76,20 @@ module Dry
|
|
72
76
|
# @return [undefined]
|
73
77
|
#
|
74
78
|
# @api private
|
75
|
-
def define_hash_method
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
+
def define_hash_method(immutable:)
|
80
|
+
calculate_hash = ->(obj) { @keys.map { |key| obj.__send__(key) }.push(obj.class).hash }
|
81
|
+
if immutable
|
82
|
+
define_method(:hash) do
|
83
|
+
@__hash__ ||= calculate_hash.call(self)
|
84
|
+
end
|
85
|
+
define_method(:freeze) do
|
86
|
+
hash
|
87
|
+
super()
|
88
|
+
end
|
89
|
+
else
|
90
|
+
define_method(:hash) do
|
91
|
+
calculate_hash.call(self)
|
92
|
+
end
|
79
93
|
end
|
80
94
|
end
|
81
95
|
|
@@ -86,10 +100,10 @@ module Dry
|
|
86
100
|
# @api private
|
87
101
|
def define_inspect_method
|
88
102
|
keys = @keys
|
89
|
-
define_method(:inspect) do
|
103
|
+
define_method(:inspect) do
|
90
104
|
klass = self.class
|
91
|
-
|
92
|
-
|
105
|
+
name = klass.name || klass.inspect
|
106
|
+
"#<#{name}#{keys.map { |key| " #{key}=#{__send__(key).inspect}" }.join}>"
|
93
107
|
end
|
94
108
|
end
|
95
109
|
|
@@ -122,8 +136,8 @@ module Dry
|
|
122
136
|
#
|
123
137
|
# @api public
|
124
138
|
def ==(other)
|
125
|
-
other.
|
139
|
+
other.is_a?(self.class) && cmp?(__method__, other)
|
126
140
|
end
|
127
|
-
end
|
128
|
-
end
|
141
|
+
end
|
142
|
+
end
|
129
143
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,26 +1,20 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
if ENV['COVERAGE'] == 'true'
|
4
2
|
require 'simplecov'
|
5
|
-
|
6
3
|
SimpleCov.start do
|
7
|
-
|
8
|
-
|
9
|
-
add_filter 'config'
|
10
|
-
add_filter 'spec'
|
11
|
-
add_filter 'vendor'
|
12
|
-
|
13
|
-
minimum_coverage 100
|
4
|
+
add_filter '/spec/'
|
14
5
|
end
|
15
6
|
end
|
16
7
|
|
17
|
-
require 'devtools/spec_helper'
|
18
8
|
require 'dry-equalizer'
|
19
9
|
|
20
10
|
RSpec.configure do |config|
|
21
11
|
config.raise_errors_for_deprecations!
|
22
12
|
|
13
|
+
config.disable_monkey_patching!
|
14
|
+
|
23
15
|
config.expect_with :rspec do |expect_with|
|
24
16
|
expect_with.syntax = :expect
|
25
17
|
end
|
18
|
+
|
19
|
+
config.warnings = true
|
26
20
|
end
|
@@ -1,9 +1,6 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
require 'spec_helper'
|
4
2
|
|
5
|
-
describe Dry::Equalizer do
|
6
|
-
let(:object) { described_class }
|
3
|
+
RSpec.describe Dry::Equalizer do
|
7
4
|
let(:name) { 'User' }
|
8
5
|
let(:klass) { ::Class.new }
|
9
6
|
|
@@ -13,12 +10,12 @@ describe Dry::Equalizer do
|
|
13
10
|
before do
|
14
11
|
# specify the class #name method
|
15
12
|
allow(klass).to receive(:name).and_return(name)
|
16
|
-
klass.
|
13
|
+
klass.include(subject)
|
17
14
|
end
|
18
15
|
|
19
16
|
let(:instance) { klass.new }
|
20
17
|
|
21
|
-
it { should be_instance_of(
|
18
|
+
it { should be_instance_of(described_class) }
|
22
19
|
|
23
20
|
it { should be_frozen }
|
24
21
|
|
@@ -83,6 +80,7 @@ describe Dry::Equalizer do
|
|
83
80
|
let(:klass) do
|
84
81
|
::Class.new do
|
85
82
|
attr_reader :firstname, :lastname
|
83
|
+
attr_writer :firstname
|
86
84
|
private :firstname, :lastname
|
87
85
|
|
88
86
|
def initialize(firstname, lastname)
|
@@ -95,10 +93,10 @@ describe Dry::Equalizer do
|
|
95
93
|
before do
|
96
94
|
# specify the class #inspect method
|
97
95
|
allow(klass).to receive_messages(name: nil, inspect: name)
|
98
|
-
klass.
|
96
|
+
klass.include(subject)
|
99
97
|
end
|
100
98
|
|
101
|
-
it { should be_instance_of(
|
99
|
+
it { should be_instance_of(described_class) }
|
102
100
|
|
103
101
|
it { should be_frozen }
|
104
102
|
|
@@ -154,5 +152,87 @@ describe Dry::Equalizer do
|
|
154
152
|
.to eql('#<User firstname="John" lastname="Doe">')
|
155
153
|
end
|
156
154
|
end
|
155
|
+
|
156
|
+
context 'when immutable' do
|
157
|
+
describe '#hash' do
|
158
|
+
|
159
|
+
subject { Dry::Equalizer(*keys, immutable: true) }
|
160
|
+
|
161
|
+
it 'returns memoized hash' do
|
162
|
+
expect { instance.firstname = 'Changed' }.not_to(change { instance.hash })
|
163
|
+
end
|
164
|
+
|
165
|
+
context 'when frozen' do
|
166
|
+
it 'returns memoized hash' do
|
167
|
+
instance.freeze
|
168
|
+
|
169
|
+
expect(instance.hash)
|
170
|
+
.to eql([firstname, lastname, klass].hash)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
context 'with duplicate keys' do
|
178
|
+
subject { Dry::Equalizer(*keys) }
|
179
|
+
|
180
|
+
let(:keys) { %i[firstname firstname lastname].freeze }
|
181
|
+
let(:firstname) { 'John' }
|
182
|
+
let(:lastname) { 'Doe' }
|
183
|
+
let(:instance) { klass.new(firstname, lastname) }
|
184
|
+
|
185
|
+
let(:klass) do
|
186
|
+
::Class.new do
|
187
|
+
attr_reader :firstname, :lastname
|
188
|
+
private :firstname, :lastname
|
189
|
+
|
190
|
+
def initialize(firstname, lastname)
|
191
|
+
@firstname = firstname
|
192
|
+
@lastname = lastname
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
before do
|
198
|
+
# specify the class #inspect method
|
199
|
+
allow(klass).to receive_messages(name: nil, inspect: name)
|
200
|
+
klass.include(subject)
|
201
|
+
end
|
202
|
+
|
203
|
+
it { should be_instance_of(described_class) }
|
204
|
+
|
205
|
+
it { should be_frozen }
|
206
|
+
|
207
|
+
describe '#inspect' do
|
208
|
+
it 'returns the expected string' do
|
209
|
+
expect(instance.inspect)
|
210
|
+
.to eql('#<User firstname="John" lastname="Doe">')
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
context 'with options' do
|
216
|
+
context 'w/o inspect' do
|
217
|
+
subject { Dry::Equalizer(*keys, inspect: false) }
|
218
|
+
|
219
|
+
let(:keys) { %i[firstname lastname].freeze }
|
220
|
+
let(:firstname) { 'John' }
|
221
|
+
let(:lastname) { 'Doe' }
|
222
|
+
let(:instance) { klass.new(firstname, lastname) }
|
223
|
+
|
224
|
+
let(:klass) do
|
225
|
+
::Struct.new(:firstname, :lastname)
|
226
|
+
end
|
227
|
+
|
228
|
+
before { klass.include(subject) }
|
229
|
+
|
230
|
+
describe '#inspect' do
|
231
|
+
it 'returns the default string' do
|
232
|
+
expect(instance.inspect).to eql('#<struct firstname="John", lastname="Doe">')
|
233
|
+
expect(instance.to_s).to eql('#<struct firstname="John", lastname="Doe">')
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
157
237
|
end
|
158
238
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dry-equalizer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dan Kubb
|
@@ -9,28 +9,8 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
13
|
-
dependencies:
|
14
|
-
- !ruby/object:Gem::Dependency
|
15
|
-
name: bundler
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
17
|
-
requirements:
|
18
|
-
- - "~>"
|
19
|
-
- !ruby/object:Gem::Version
|
20
|
-
version: '1.3'
|
21
|
-
- - ">="
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: 1.3.5
|
24
|
-
type: :development
|
25
|
-
prerelease: false
|
26
|
-
version_requirements: !ruby/object:Gem::Requirement
|
27
|
-
requirements:
|
28
|
-
- - "~>"
|
29
|
-
- !ruby/object:Gem::Version
|
30
|
-
version: '1.3'
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 1.3.5
|
12
|
+
date: 2019-11-07 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
34
14
|
description: Module to define equality, equivalence and inspection methods
|
35
15
|
email:
|
36
16
|
- dan.kubb@gmail.com
|
@@ -42,24 +22,24 @@ extra_rdoc_files:
|
|
42
22
|
- README.md
|
43
23
|
- CONTRIBUTING.md
|
44
24
|
files:
|
25
|
+
- ".codeclimate.yml"
|
26
|
+
- ".github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md"
|
27
|
+
- ".github/ISSUE_TEMPLATE/---bug-report.md"
|
28
|
+
- ".github/ISSUE_TEMPLATE/---feature-request.md"
|
29
|
+
- ".github/workflows/docsite.yml"
|
30
|
+
- ".github/workflows/sync_configs.yml"
|
45
31
|
- ".gitignore"
|
46
32
|
- ".rspec"
|
47
33
|
- ".rubocop.yml"
|
48
|
-
- ".travis.yml"
|
49
34
|
- ".yardstick.yml"
|
50
35
|
- CHANGELOG.md
|
36
|
+
- CODE_OF_CONDUCT.md
|
51
37
|
- CONTRIBUTING.md
|
52
38
|
- Gemfile
|
53
39
|
- LICENSE
|
54
40
|
- README.md
|
55
41
|
- Rakefile
|
56
|
-
-
|
57
|
-
- config/flay.yml
|
58
|
-
- config/flog.yml
|
59
|
-
- config/mutant.yml
|
60
|
-
- config/reek.yml
|
61
|
-
- config/rubocop.yml
|
62
|
-
- config/yardstick.yml
|
42
|
+
- docsite/source/index.html.md
|
63
43
|
- dry-equalizer.gemspec
|
64
44
|
- lib/dry-equalizer.rb
|
65
45
|
- lib/dry/equalizer.rb
|
@@ -70,7 +50,7 @@ files:
|
|
70
50
|
- spec/unit/equalizer/methods/eql_predicate_spec.rb
|
71
51
|
- spec/unit/equalizer/methods/equality_operator_spec.rb
|
72
52
|
- spec/unit/equalizer/universal_spec.rb
|
73
|
-
homepage: https://github.com/
|
53
|
+
homepage: https://github.com/dry-rb/dry-equalizer
|
74
54
|
licenses:
|
75
55
|
- MIT
|
76
56
|
metadata: {}
|
@@ -82,15 +62,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
82
62
|
requirements:
|
83
63
|
- - ">="
|
84
64
|
- !ruby/object:Gem::Version
|
85
|
-
version: 2.
|
65
|
+
version: 2.4.0
|
86
66
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
67
|
requirements:
|
88
68
|
- - ">="
|
89
69
|
- !ruby/object:Gem::Version
|
90
70
|
version: '0'
|
91
71
|
requirements: []
|
92
|
-
|
93
|
-
rubygems_version: 2.4.5
|
72
|
+
rubygems_version: 3.0.6
|
94
73
|
signing_key:
|
95
74
|
specification_version: 4
|
96
75
|
summary: Module to define equality, equivalence and inspection methods
|
@@ -99,4 +78,3 @@ test_files:
|
|
99
78
|
- spec/unit/equalizer/methods/eql_predicate_spec.rb
|
100
79
|
- spec/unit/equalizer/methods/equality_operator_spec.rb
|
101
80
|
- spec/unit/equalizer/universal_spec.rb
|
102
|
-
has_rdoc:
|