dry-equalizer 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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