dry-equalizer 0.2.2

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 68e7a5819b71d2ffd60f4424d3b06e92710404a1a83b5fb1770f36530fee537e
4
+ data.tar.gz: fbaa5d489d993948159108249b42eaec44a144163ea73285cff6c88c0cec1dd0
5
+ SHA512:
6
+ metadata.gz: 7951e751feca649d17457d9d95f18af296bac9a583ed5d3644edb9e926afcdd2187af0effec08723a580b3acadd9fbac3467bda3c90ef5863c417c14b1d9e22b
7
+ data.tar.gz: e09afaa53dcb1d775a634d453f3e3d9b015834a3d07e2ae3cfb2bedcb0cf9b37825da42e3cf8224f926c81eafd195d6b981700a2586c9e609bc9d37da331cf1f
@@ -0,0 +1,39 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## Rubinius
17
+ *.rbc
18
+ .rbx
19
+
20
+ ## PROJECT::GENERAL
21
+ *.gem
22
+ coverage
23
+ profiling
24
+ turbulence
25
+ rdoc
26
+ pkg
27
+ tmp
28
+ doc
29
+ log
30
+ .yardoc
31
+ measurements
32
+
33
+ ## BUNDLER
34
+ .bundle
35
+ Gemfile.lock
36
+ bin
37
+ bundle
38
+
39
+ ## PROJECT::SPECIFIC
data/.rspec ADDED
@@ -0,0 +1,6 @@
1
+ --backtrace
2
+ --color
3
+ --format progress
4
+ --order random
5
+ --profile
6
+ --warnings
File without changes
@@ -0,0 +1,24 @@
1
+ language: ruby
2
+ cache: bundler
3
+ bundler_args: --without benchmarks tools
4
+ after_success:
5
+ - '[ -d coverage ] && bundle exec codeclimate-test-reporter'
6
+ rvm:
7
+ - 2.2.10
8
+ - 2.3.8
9
+ - 2.4.5
10
+ - 2.5.3
11
+ - 2.6.1
12
+ - jruby-9.2.6.0
13
+ env:
14
+ global:
15
+ - COVERAGE=true
16
+ - JRUBY_OPTS='--dev -J-Xmx1024M'
17
+ notifications:
18
+ email: false
19
+ webhooks:
20
+ urls:
21
+ - https://webhooks.gitter.im/e/19098b4253a72c9796db
22
+ on_success: change # options: [always|never|change] default: always
23
+ on_failure: always # options: [always|never|change] default: always
24
+ on_start: false # default: false
@@ -0,0 +1,2 @@
1
+ ---
2
+ threshold: 100
@@ -0,0 +1,38 @@
1
+ # v0.2.2 2019-03-08
2
+
3
+ ### Added
4
+
5
+ * Generation of `#to_s` and `#inspect` can be disabled with `inspect: false` (flash-gordon)
6
+ ```ruby
7
+ class User
8
+ include Dry::Equalizer(:id, :name, :age, inspect: false)
9
+ end
10
+ ```
11
+
12
+ [Compare v0.2.1...v0.2.2](https://github.com/dry-rb/dry-equalizer/compare/v0.2.1...v0.2.2)
13
+
14
+ # v0.2.1 2018-04-26
15
+
16
+ ### Fixed
17
+
18
+ * Including equalizer module with same keys multiple times won't cause duped keys in `inspect` output (radar)
19
+
20
+ [Compare v0.2.0...v0.2.1](https://github.com/dry-rb/dry-equalizer/compare/v0.2.0...v0.2.1)
21
+
22
+ # v0.2.0 2015-11-13
23
+
24
+ Really make it work with MRI 2.0 again (it's Friday 13th OK?!)
25
+
26
+ # v0.1.1 2015-11-13
27
+
28
+ Make it work with MRI 2.0 again
29
+
30
+ # v0.1.0 2015-11-11
31
+
32
+ ## Added
33
+
34
+ - `Dry::Equalizer()` method accepting a list of keys (solnic)
35
+
36
+ ## Changed
37
+
38
+ - `eql?` no longer tries to coerce `other` with `coerce` method (solnic)
@@ -0,0 +1,29 @@
1
+ # Issue Guidelines
2
+
3
+ ## Reporting bugs
4
+
5
+ If you found a bug, report an issue and describe what's the expected behavior versus what actually happens. If the bug causes a crash, attach a full backtrace. If possible, a reproduction script showing the problem is highly appreciated.
6
+
7
+ ## Reporting feature requests
8
+
9
+ Report a feature request **only after discussing it first on [discuss.dry-rb.org](https://discuss.dry-rb.org)** where it was accepted. Please provide a concise description of the feature, don't link to a discussion thread, and instead summarize what was discussed.
10
+
11
+ ## Reporting questions, support requests, ideas, concerns etc.
12
+
13
+ **PLEASE DON'T** - use [discuss.dry-rb.org](http://discuss.dry-rb.org) instead.
14
+
15
+ # Pull Request Guidelines
16
+
17
+ A Pull Request will only be accepted if it addresses a specific issue that was reported previously, or fixes typos, mistakes in documentation etc.
18
+
19
+ Other requirements:
20
+
21
+ 1) Do not open a pull request if you can't provide tests along with it. If you have problems writing tests, ask for help in the related issue.
22
+ 2) Follow the style conventions of the surrounding code. In most cases, this is standard ruby style.
23
+ 3) Add API documentation if it's a new feature
24
+ 4) Update API documentation if it changes an existing feature
25
+ 5) Bonus points for sending a PR to [github.com/dry-rb/dry-rb.org](github.com/dry-rb/dry-rb.org) which updates user documentation and guides
26
+
27
+ # Asking for help
28
+
29
+ If these guidelines aren't helpful, and you're stuck, please post a message on [discuss.dry-rb.org](https://discuss.dry-rb.org).
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :development, :test do
6
+ gem 'bundler'
7
+ gem 'rake'
8
+ gem 'rspec', '~> 3.5'
9
+ end
10
+
11
+ group :test do
12
+ platform :mri do
13
+ gem "codeclimate-test-reporter", require: false
14
+ gem 'simplecov', require: false
15
+ end
16
+ end
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2009-2013 Dan Kubb
2
+ Copyright (c) 2012 Markus Schirp (packaging)
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,86 @@
1
+ # dry-equalizer <a href="https://gitter.im/dry-rb/chat" target="_blank">![Join the chat at https://gitter.im/dry-rb/chat](https://badges.gitter.im/Join%20Chat.svg)</a>
2
+
3
+ Module to define equality, equivalence and inspection methods
4
+
5
+ [![Gem Version](http://img.shields.io/gem/v/dry-equalizer.svg)][gem]
6
+ [![Build Status](http://img.shields.io/travis/dry-rb/dry-equalizer.svg)][travis]
7
+ [![Maintainability](https://api.codeclimate.com/v1/badges/5a9a139af1d4a80a28c4/maintainability)](https://codeclimate.com/github/dry-rb/dry-equalizer/maintainability)
8
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/5a9a139af1d4a80a28c4/test_coverage)](https://codeclimate.com/github/dry-rb/dry-equalizer/test_coverage)
9
+
10
+ [gem]: https://rubygems.org/gems/dry-equalizer
11
+ [travis]: https://travis-ci.org/dry-rb/dry-equalizer
12
+ [codeclimate]: https://codeclimate.com/github/dry-rb/dry-equalizer
13
+
14
+ Examples
15
+ --------
16
+
17
+ ``` ruby
18
+ class GeoLocation
19
+ include Dry::Equalizer(:latitude, :longitude)
20
+
21
+ attr_reader :latitude, :longitude
22
+
23
+ def initialize(latitude, longitude)
24
+ @latitude, @longitude = latitude, longitude
25
+ end
26
+ end
27
+
28
+ point_a = GeoLocation.new(1, 2)
29
+ point_b = GeoLocation.new(1, 2)
30
+ point_c = GeoLocation.new(2, 2)
31
+
32
+ point_a.inspect # => "#<GeoLocation latitude=1 longitude=2>"
33
+
34
+ point_a == point_b # => true
35
+ point_a.hash == point_b.hash # => true
36
+ point_a.eql?(point_b) # => true
37
+ point_a.equal?(point_b) # => false
38
+
39
+ point_a == point_c # => false
40
+ point_a.hash == point_c.hash # => false
41
+ point_a.eql?(point_c) # => false
42
+ point_a.equal?(point_c) # => false
43
+ ```
44
+
45
+ Supported Ruby Versions
46
+ -----------------------
47
+
48
+ This library aims to support and is [tested against][travis] the following Ruby
49
+ implementations:
50
+
51
+ * MRI 2.2+
52
+ * JRuby 9.x
53
+
54
+ If something doesn't work on one of these versions, it's a bug.
55
+
56
+ This library may inadvertently work (or seem to work) on other Ruby versions or
57
+ implementations, however support will only be provided for the implementations
58
+ listed above.
59
+
60
+ If you would like this library to support another Ruby version or
61
+ implementation, you may volunteer to be a maintainer. Being a maintainer
62
+ entails making sure all tests run and pass on that implementation. When
63
+ something breaks on your implementation, you will be responsible for providing
64
+ patches in a timely fashion. If critical issues for a particular implementation
65
+ exist at the time of a major release, support for that Ruby version may be
66
+ dropped.
67
+
68
+ Credits
69
+ -------
70
+
71
+ This is a fork of the original [equalizer](https://github.com/dkubb/equalizer).
72
+
73
+ * Dan Kubb ([dkubb](https://github.com/dkubb))
74
+ * Piotr Solnica ([solnic](https://github.com/solnic))
75
+ * Markus Schirp ([mbj](https://github.com/mbj))
76
+ * Erik Michaels-Ober ([sferik](https://github.com/sferik))
77
+
78
+ Contributing
79
+ -------------
80
+
81
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for details.
82
+
83
+ Copyright
84
+ ---------
85
+
86
+ Copyright &copy; 2009-2013 Dan Kubb. See LICENSE for details.
@@ -0,0 +1,8 @@
1
+ require 'bundler'
2
+
3
+ Bundler::GemHelper.install_tasks
4
+
5
+ require "rspec/core/rake_task"
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+ task default: [:spec]
@@ -0,0 +1,19 @@
1
+ require File.expand_path('../lib/dry/equalizer/version', __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = 'dry-equalizer'
5
+ gem.version = Dry::Equalizer::VERSION.dup
6
+ gem.authors = ['Dan Kubb', 'Markus Schirp']
7
+ gem.email = %w[dan.kubb@gmail.com mbj@schirp-dso.com]
8
+ gem.description = 'Module to define equality, equivalence and inspection methods'
9
+ gem.summary = gem.description
10
+ gem.homepage = 'https://github.com/dryrb/dry-equalizer'
11
+ gem.licenses = 'MIT'
12
+
13
+ gem.require_paths = %w[lib]
14
+ gem.files = `git ls-files`.split("\n")
15
+ gem.test_files = `git ls-files -- spec/{unit,integration}`.split("\n")
16
+ gem.extra_rdoc_files = %w[LICENSE README.md CONTRIBUTING.md]
17
+
18
+ gem.required_ruby_version = '>= 2.0.0'
19
+ end
@@ -0,0 +1 @@
1
+ require 'dry/equalizer'
@@ -0,0 +1,127 @@
1
+ module Dry
2
+ # Build an equalizer module for the inclusion in other class
3
+ #
4
+ # @api public
5
+ def self.Equalizer(*keys, **options)
6
+ Dry::Equalizer.new(*keys, **options)
7
+ end
8
+
9
+ # Define equality, equivalence and inspection methods
10
+ class Equalizer < Module
11
+ # Initialize an Equalizer with the given keys
12
+ #
13
+ # Will use the keys with which it is initialized to define #cmp?,
14
+ # #hash, and #inspect
15
+ #
16
+ # @param [Array<Symbol>] keys
17
+ #
18
+ # @return [undefined]
19
+ #
20
+ # @api private
21
+ def initialize(*keys, inspect: true)
22
+ @keys = keys.uniq
23
+ define_methods(inspect: inspect)
24
+ freeze
25
+ end
26
+
27
+ private
28
+
29
+ # Hook called when module is included
30
+ #
31
+ # @param [Module] descendant
32
+ # the module or class including Equalizer
33
+ #
34
+ # @return [self]
35
+ #
36
+ # @api private
37
+ def included(descendant)
38
+ super
39
+ descendant.send(:include, Methods)
40
+ end
41
+
42
+ # Define the equalizer methods based on #keys
43
+ #
44
+ # @return [undefined]
45
+ #
46
+ # @api private
47
+ def define_methods(inspect: true)
48
+ define_cmp_method
49
+ define_hash_method
50
+ define_inspect_method if inspect
51
+ end
52
+
53
+ # Define an #cmp? method based on the instance's values identified by #keys
54
+ #
55
+ # @return [undefined]
56
+ #
57
+ # @api private
58
+ def define_cmp_method
59
+ keys = @keys
60
+ define_method(:cmp?) do |comparator, other|
61
+ keys.all? do |key|
62
+ __send__(key).public_send(comparator, other.__send__(key))
63
+ end
64
+ end
65
+ private :cmp?
66
+ end
67
+
68
+ # Define a #hash method based on the instance's values identified by #keys
69
+ #
70
+ # @return [undefined]
71
+ #
72
+ # @api private
73
+ def define_hash_method
74
+ keys = @keys
75
+ define_method(:hash) do | |
76
+ keys.map(&method(:send)).push(self.class).hash
77
+ end
78
+ end
79
+
80
+ # Define an inspect method that reports the values of the instance's keys
81
+ #
82
+ # @return [undefined]
83
+ #
84
+ # @api private
85
+ def define_inspect_method
86
+ keys = @keys
87
+ define_method(:inspect) do | |
88
+ klass = self.class
89
+ name = klass.name || klass.inspect
90
+ "#<#{name}#{keys.map { |key| " #{key}=#{__send__(key).inspect}" }.join}>"
91
+ end
92
+ end
93
+
94
+ # The comparison methods
95
+ module Methods
96
+ # Compare the object with other object for equality
97
+ #
98
+ # @example
99
+ # object.eql?(other) # => true or false
100
+ #
101
+ # @param [Object] other
102
+ # the other object to compare with
103
+ #
104
+ # @return [Boolean]
105
+ #
106
+ # @api public
107
+ def eql?(other)
108
+ instance_of?(other.class) && cmp?(__method__, other)
109
+ end
110
+
111
+ # Compare the object with other object for equivalency
112
+ #
113
+ # @example
114
+ # object == other # => true or false
115
+ #
116
+ # @param [Object] other
117
+ # the other object to compare with
118
+ #
119
+ # @return [Boolean]
120
+ #
121
+ # @api public
122
+ def ==(other)
123
+ other.is_a?(self.class) && cmp?(__method__, other)
124
+ end
125
+ end # module Methods
126
+ end # class Equalizer
127
+ end
@@ -0,0 +1,6 @@
1
+ module Dry
2
+ class Equalizer < Module
3
+ # Gem version
4
+ VERSION = '0.2.2'.freeze
5
+ end # class Equalizer
6
+ end
@@ -0,0 +1,26 @@
1
+ if RUBY_ENGINE == 'ruby' && ENV['COVERAGE'] == 'true'
2
+ require 'yaml'
3
+ rubies = YAML.load(File.read(File.join(__dir__, '..', '.travis.yml')))['rvm']
4
+ latest_mri = rubies.select { |v| v =~ /\A\d+\.\d+.\d+\z/ }.max
5
+
6
+ if RUBY_VERSION == latest_mri
7
+ require 'simplecov'
8
+ SimpleCov.start do
9
+ add_filter '/spec/'
10
+ end
11
+ end
12
+ end
13
+
14
+ require 'dry-equalizer'
15
+
16
+ RSpec.configure do |config|
17
+ config.raise_errors_for_deprecations!
18
+
19
+ config.disable_monkey_patching!
20
+
21
+ config.expect_with :rspec do |expect_with|
22
+ expect_with.syntax = :expect
23
+ end
24
+
25
+ config.warnings = true
26
+ end
@@ -0,0 +1,3 @@
1
+ require 'rbconfig'
2
+
3
+ ::Config = RbConfig unless defined?(::Config)
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Dry::Equalizer, '#included' do
4
+ subject { descendant.instance_exec(object) { |mod| include mod } }
5
+
6
+ let(:object) { described_class.new }
7
+ let(:descendant) { Class.new }
8
+ let(:superclass) { described_class.superclass }
9
+
10
+ before do
11
+ # Prevent Module.included from being called through inheritance
12
+ allow(described_class::Methods).to receive(:included)
13
+ end
14
+
15
+ around do |example|
16
+ # Restore included method after each example
17
+ superclass.class_eval do
18
+ alias_method :original_included, :included
19
+ example.call
20
+ undef_method :included
21
+ alias_method :included, :original_included
22
+ end
23
+ end
24
+
25
+ it 'delegates to the superclass #included method' do
26
+ # This is the most succinct approach I could think of to test whether the
27
+ # superclass#included method is called. All of the built-in rspec helpers
28
+ # did not seem to work for this.
29
+ included = false
30
+
31
+ superclass.class_eval do
32
+ define_method(:included) do |_|
33
+ # Only set the flag when an Dry::Equalizer instance is included.
34
+ # Otherwise, other module includes (which get triggered internally
35
+ # in RSpec when `change` is used for the first time, since it uses
36
+ # autoloading for its matchers) will wrongly set this flag.
37
+ included = true if self.kind_of?(Dry::Equalizer)
38
+ end
39
+ end
40
+
41
+ expect { subject }.to change { included }.from(false).to(true)
42
+ end
43
+
44
+ it 'includes methods into the descendant' do
45
+ subject
46
+ expect(descendant.included_modules).to include(described_class::Methods)
47
+ end
48
+ end
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Dry::Equalizer::Methods, '#eql?' do
4
+ subject { object.eql?(other) }
5
+
6
+ let(:object) { described_class.new(true) }
7
+
8
+ let(:described_class) do
9
+ Class.new do
10
+ include Dry::Equalizer::Methods
11
+
12
+ attr_reader :boolean
13
+
14
+ def initialize(boolean)
15
+ @boolean = boolean
16
+ end
17
+
18
+ def cmp?(comparator, other)
19
+ boolean.send(comparator, other.boolean)
20
+ end
21
+ end
22
+ end
23
+
24
+ context 'with the same object' do
25
+ let(:other) { object }
26
+
27
+ it { should be(true) }
28
+
29
+ it 'is symmetric' do
30
+ should eql(other.eql?(object))
31
+ end
32
+ end
33
+
34
+ context 'with an equivalent object' do
35
+ let(:other) { object.dup }
36
+
37
+ it { should be(true) }
38
+
39
+ it 'is symmetric' do
40
+ should eql(other.eql?(object))
41
+ end
42
+ end
43
+
44
+ context 'with an equivalent object of a subclass' do
45
+ let(:other) { Class.new(described_class).new(true) }
46
+
47
+ it { should be(false) }
48
+
49
+ it 'is symmetric' do
50
+ should eql(other.eql?(object))
51
+ end
52
+ end
53
+
54
+ context 'with a different object' do
55
+ let(:other) { described_class.new(false) }
56
+
57
+ it { should be(false) }
58
+
59
+ it 'is symmetric' do
60
+ should eql(other.eql?(object))
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,86 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Dry::Equalizer::Methods, '#==' do
4
+ subject { object == other }
5
+
6
+ let(:object) { described_class.new(true) }
7
+ let(:described_class) { Class.new(super_class) }
8
+
9
+ let(:super_class) do
10
+ Class.new do
11
+ include Dry::Equalizer::Methods
12
+
13
+ attr_reader :boolean
14
+
15
+ def initialize(boolean)
16
+ @boolean = boolean
17
+ end
18
+
19
+ def cmp?(comparator, other)
20
+ boolean.send(comparator, other.boolean)
21
+ end
22
+ end
23
+ end
24
+
25
+ context 'with the same object' do
26
+ let(:other) { object }
27
+
28
+ it { should be(true) }
29
+
30
+ it 'is symmetric' do
31
+ should eql(other == object)
32
+ end
33
+ end
34
+
35
+ context 'with an equivalent object' do
36
+ let(:other) { object.dup }
37
+
38
+ it { should be(true) }
39
+
40
+ it 'is symmetric' do
41
+ should eql(other == object)
42
+ end
43
+ end
44
+
45
+ context 'with a subclass instance having equivalent obervable state' do
46
+ let(:other) { Class.new(described_class).new(true) }
47
+
48
+ it { should be(true) }
49
+
50
+ it 'is not symmetric' do
51
+ # the subclass instance should maintain substitutability with the object
52
+ # (in the LSP sense) the reverse is not true.
53
+ should_not eql(other == object)
54
+ end
55
+ end
56
+
57
+ context 'with a superclass instance having equivalent observable state' do
58
+ let(:other) { super_class.new(true) }
59
+
60
+ it { should be(false) }
61
+
62
+ it 'is not symmetric' do
63
+ should_not eql(other == object)
64
+ end
65
+ end
66
+
67
+ context 'with an object of another class' do
68
+ let(:other) { Class.new.new }
69
+
70
+ it { should be(false) }
71
+
72
+ it 'is symmetric' do
73
+ should eql(other == object)
74
+ end
75
+ end
76
+
77
+ context 'with a different object' do
78
+ let(:other) { described_class.new(false) }
79
+
80
+ it { should be(false) }
81
+
82
+ it 'is symmetric' do
83
+ should eql(other == object)
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,217 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Dry::Equalizer do
4
+ let(:name) { 'User' }
5
+ let(:klass) { ::Class.new }
6
+
7
+ context 'with no keys' do
8
+ subject { Dry::Equalizer() }
9
+
10
+ before do
11
+ # specify the class #name method
12
+ allow(klass).to receive(:name).and_return(name)
13
+ klass.include(subject)
14
+ end
15
+
16
+ let(:instance) { klass.new }
17
+
18
+ it { should be_instance_of(described_class) }
19
+
20
+ it { should be_frozen }
21
+
22
+ it 'defines #hash and #inspect methods dynamically' do
23
+ expect(subject.public_instance_methods(false).map(&:to_s).sort)
24
+ .to eql(%w[hash inspect])
25
+ end
26
+
27
+ describe '#eql?' do
28
+ context 'when the objects are similar' do
29
+ let(:other) { instance.dup }
30
+
31
+ it { expect(instance.eql?(other)).to be(true) }
32
+ end
33
+
34
+ context 'when the objects are different' do
35
+ let(:other) { double('other') }
36
+
37
+ it { expect(instance.eql?(other)).to be(false) }
38
+ end
39
+ end
40
+
41
+ describe '#==' do
42
+ context 'when the objects are similar' do
43
+ let(:other) { instance.dup }
44
+
45
+ it { expect(instance == other).to be(true) }
46
+ end
47
+
48
+ context 'when the objects are different' do
49
+ let(:other) { double('other') }
50
+
51
+ it { expect(instance == other).to be(false) }
52
+ end
53
+ end
54
+
55
+ describe '#hash' do
56
+ it 'has the expected arity' do
57
+ expect(klass.instance_method(:hash).arity).to be(0)
58
+ end
59
+
60
+ it { expect(instance.hash).to eql([klass].hash) }
61
+ end
62
+
63
+ describe '#inspect' do
64
+ it 'has the expected arity' do
65
+ expect(klass.instance_method(:inspect).arity).to be(0)
66
+ end
67
+
68
+ it { expect(instance.inspect).to eql('#<User>') }
69
+ end
70
+ end
71
+
72
+ context 'with keys' do
73
+ subject { Dry::Equalizer(*keys) }
74
+
75
+ let(:keys) { %i[firstname lastname].freeze }
76
+ let(:firstname) { 'John' }
77
+ let(:lastname) { 'Doe' }
78
+ let(:instance) { klass.new(firstname, lastname) }
79
+
80
+ let(:klass) do
81
+ ::Class.new do
82
+ attr_reader :firstname, :lastname
83
+ private :firstname, :lastname
84
+
85
+ def initialize(firstname, lastname)
86
+ @firstname = firstname
87
+ @lastname = lastname
88
+ end
89
+ end
90
+ end
91
+
92
+ before do
93
+ # specify the class #inspect method
94
+ allow(klass).to receive_messages(name: nil, inspect: name)
95
+ klass.include(subject)
96
+ end
97
+
98
+ it { should be_instance_of(described_class) }
99
+
100
+ it { should be_frozen }
101
+
102
+ it 'defines #hash and #inspect methods dynamically' do
103
+ expect(subject.public_instance_methods(false).map(&:to_s).sort)
104
+ .to eql(%w[hash inspect])
105
+ end
106
+
107
+ describe '#eql?' do
108
+ context 'when the objects are similar' do
109
+ let(:other) { instance.dup }
110
+
111
+ it { expect(instance.eql?(other)).to be(true) }
112
+ end
113
+
114
+ context 'when the objects are different' do
115
+ let(:other) { double('other') }
116
+
117
+ it { expect(instance.eql?(other)).to be(false) }
118
+ end
119
+ end
120
+
121
+ describe '#==' do
122
+ context 'when the objects are similar' do
123
+ let(:other) { instance.dup }
124
+
125
+ it { expect(instance == other).to be(true) }
126
+ end
127
+
128
+ context 'when the objects are different type' do
129
+ let(:other) { klass.new('Foo', 'Bar') }
130
+
131
+ it { expect(instance == other).to be(false) }
132
+ end
133
+
134
+ context 'when the objects are from different type' do
135
+ let(:other) { double('other') }
136
+
137
+ it { expect(instance == other).to be(false) }
138
+ end
139
+ end
140
+
141
+ describe '#hash' do
142
+ it 'returns the expected hash' do
143
+ expect(instance.hash)
144
+ .to eql([firstname, lastname, klass].hash)
145
+ end
146
+ end
147
+
148
+ describe '#inspect' do
149
+ it 'returns the expected string' do
150
+ expect(instance.inspect)
151
+ .to eql('#<User firstname="John" lastname="Doe">')
152
+ end
153
+ end
154
+ end
155
+
156
+ context 'with duplicate keys' do
157
+ subject { Dry::Equalizer(*keys) }
158
+
159
+ let(:keys) { %i[firstname firstname lastname].freeze }
160
+ let(:firstname) { 'John' }
161
+ let(:lastname) { 'Doe' }
162
+ let(:instance) { klass.new(firstname, lastname) }
163
+
164
+ let(:klass) do
165
+ ::Class.new do
166
+ attr_reader :firstname, :lastname
167
+ private :firstname, :lastname
168
+
169
+ def initialize(firstname, lastname)
170
+ @firstname = firstname
171
+ @lastname = lastname
172
+ end
173
+ end
174
+ end
175
+
176
+ before do
177
+ # specify the class #inspect method
178
+ allow(klass).to receive_messages(name: nil, inspect: name)
179
+ klass.include(subject)
180
+ end
181
+
182
+ it { should be_instance_of(described_class) }
183
+
184
+ it { should be_frozen }
185
+
186
+ describe '#inspect' do
187
+ it 'returns the expected string' do
188
+ expect(instance.inspect)
189
+ .to eql('#<User firstname="John" lastname="Doe">')
190
+ end
191
+ end
192
+ end
193
+
194
+ context 'with options' do
195
+ context 'w/o inspect' do
196
+ subject { Dry::Equalizer(*keys, inspect: false) }
197
+
198
+ let(:keys) { %i[firstname lastname].freeze }
199
+ let(:firstname) { 'John' }
200
+ let(:lastname) { 'Doe' }
201
+ let(:instance) { klass.new(firstname, lastname) }
202
+
203
+ let(:klass) do
204
+ ::Struct.new(:firstname, :lastname)
205
+ end
206
+
207
+ before { klass.include(subject) }
208
+
209
+ describe '#inspect' do
210
+ it 'returns the default string' do
211
+ expect(instance.inspect).to eql('#<struct firstname="John", lastname="Doe">')
212
+ expect(instance.to_s).to eql('#<struct firstname="John", lastname="Doe">')
213
+ end
214
+ end
215
+ end
216
+ end
217
+ end
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dry-equalizer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.2
5
+ platform: ruby
6
+ authors:
7
+ - Dan Kubb
8
+ - Markus Schirp
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2019-03-09 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Module to define equality, equivalence and inspection methods
15
+ email:
16
+ - dan.kubb@gmail.com
17
+ - mbj@schirp-dso.com
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files:
21
+ - LICENSE
22
+ - README.md
23
+ - CONTRIBUTING.md
24
+ files:
25
+ - ".gitignore"
26
+ - ".rspec"
27
+ - ".rubocop.yml"
28
+ - ".travis.yml"
29
+ - ".yardstick.yml"
30
+ - CHANGELOG.md
31
+ - CONTRIBUTING.md
32
+ - Gemfile
33
+ - LICENSE
34
+ - README.md
35
+ - Rakefile
36
+ - dry-equalizer.gemspec
37
+ - lib/dry-equalizer.rb
38
+ - lib/dry/equalizer.rb
39
+ - lib/dry/equalizer/version.rb
40
+ - spec/spec_helper.rb
41
+ - spec/support/config_alias.rb
42
+ - spec/unit/equalizer/included_spec.rb
43
+ - spec/unit/equalizer/methods/eql_predicate_spec.rb
44
+ - spec/unit/equalizer/methods/equality_operator_spec.rb
45
+ - spec/unit/equalizer/universal_spec.rb
46
+ homepage: https://github.com/dryrb/dry-equalizer
47
+ licenses:
48
+ - MIT
49
+ metadata: {}
50
+ post_install_message:
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: 2.0.0
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ requirements: []
65
+ rubygems_version: 3.0.3
66
+ signing_key:
67
+ specification_version: 4
68
+ summary: Module to define equality, equivalence and inspection methods
69
+ test_files:
70
+ - spec/unit/equalizer/included_spec.rb
71
+ - spec/unit/equalizer/methods/eql_predicate_spec.rb
72
+ - spec/unit/equalizer/methods/equality_operator_spec.rb
73
+ - spec/unit/equalizer/universal_spec.rb