sinclair 1.8.0 → 1.9.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0c06e4b7038a22a311b6ee13f1b8fd2df24211d8953982035df626dba8fb66c5
4
- data.tar.gz: b19227562faa97bca59e76d997998917068ccb2d230a0b90dfa76140f2032209
3
+ metadata.gz: 23c4aa7f5d3c743f783dc6196e0799bbef94fa2c4f42825379c4cc61aad8e9ec
4
+ data.tar.gz: 4aa6481202521cc4c0cf8b0210e798a8d56344a43c42e41157ae7a3121ea67a4
5
5
  SHA512:
6
- metadata.gz: 87daf64f9e084ef37bb47efee4fb6ff174e70cfdf5005e506acdff45647fd4ad502b348b23c6a3bbb1cce09676c14d7be52cc816b493fdbb4c92d23b94b33ecf
7
- data.tar.gz: 3d02e09271942cd50dc21eb9e9578b63db0374196e084b3ce9b54e3d816206731a88f8cb470581d791ecaf5a0f7a5435d2489ecf7465fa446b56d8f8c8b6dd24
6
+ metadata.gz: 3b07675d7768ea9db9e858498863fec96959e209b2bf9596f78e4f57ff2134f286723d8d7d3c42b9be5f8efc907602dee83dc3d0914473cc73c163a65362e84f
7
+ data.tar.gz: 8f596032dfad280158eeeb5a4a74400386f960010b86480608864d81d9c017ad6fdcd8fcabf01d97ef9987a333719561f59d883840514fc707d076872760d195
data/.circleci/config.yml CHANGED
@@ -7,8 +7,12 @@ workflows:
7
7
  filters:
8
8
  tags:
9
9
  only: /.*/
10
+ - checks:
11
+ filters:
12
+ tags:
13
+ only: /.*/
10
14
  - build-and-release:
11
- requires: [test]
15
+ requires: [test, checks]
12
16
  filters:
13
17
  tags:
14
18
  only: /\d+\.\d+\.\d+/
@@ -18,7 +22,7 @@ workflows:
18
22
  jobs:
19
23
  test:
20
24
  docker:
21
- - image: darthjee/circleci_ruby_270:1.1.0
25
+ - image: darthjee/circleci_ruby_270:1.2.0
22
26
  environment:
23
27
  PROJECT: sinclair
24
28
  steps:
@@ -32,12 +36,22 @@ jobs:
32
36
  - run:
33
37
  name: RSpec
34
38
  command: bundle exec rspec
35
- - run:
36
- name: Rubocop
37
- command: rubocop
38
39
  - run:
39
40
  name: Coverage Test Report
40
41
  command: cc-test-reporter after-build --exit-code $?
42
+ checks:
43
+ docker:
44
+ - image: darthjee/circleci_ruby_270:1.2.0
45
+ environment:
46
+ PROJECT: sinclair
47
+ steps:
48
+ - checkout
49
+ - run:
50
+ name: Bundle Install
51
+ command: bundle install
52
+ - run:
53
+ name: Rubocop
54
+ command: rubocop
41
55
  - run:
42
56
  name: Yardstick coverage check
43
57
  command: bundle exec rake verify_measurements
@@ -52,7 +66,7 @@ jobs:
52
66
  command: check_specs
53
67
  build-and-release:
54
68
  docker:
55
- - image: darthjee/circleci_ruby_270:1.1.0
69
+ - image: darthjee/circleci_ruby_270:1.2.0
56
70
  environment:
57
71
  PROJECT: sinclair
58
72
  steps:
data/.rubocop.yml CHANGED
@@ -10,7 +10,7 @@ Metrics/BlockLength:
10
10
  - 'spec/support/**/*.rb'
11
11
  - '*.gemspec'
12
12
 
13
- Metrics/LineLength:
13
+ Layout/LineLength:
14
14
  Max: 100
15
15
 
16
16
  Lint/AmbiguousBlockAssociation:
@@ -20,6 +20,9 @@ Lint/AmbiguousBlockAssociation:
20
20
  RSpec/AlignLeftLetBrace:
21
21
  Enabled: true
22
22
 
23
+ RSpec/PredicateMatcher:
24
+ Exclude:
25
+ - 'spec/integration/yard/**/*_spec.rb'
23
26
 
24
27
  RSpec/DescribedClass:
25
28
  Exclude:
data/Dockerfile CHANGED
@@ -1,6 +1,6 @@
1
1
  FROM darthjee/scripts:0.3.1 as scripts
2
2
 
3
- FROM darthjee/ruby_270:1.1.0 as base
3
+ FROM darthjee/ruby_270:1.2.0 as base
4
4
 
5
5
  COPY --chown=app:app ./ /home/app/app/
6
6
 
data/README.md CHANGED
@@ -13,9 +13,11 @@ This gem helps the creation of complex gems/concerns
13
13
  that enables creation of methods on the fly through class
14
14
  methods
15
15
 
16
+ Next release: [1.10.0](https://github.com/darthjee/sinclair/compare/1.9.0...master)
17
+
16
18
  Yard Documentation
17
19
  -------------------
18
- [https://www.rubydoc.info/gems/sinclair/1.8.0](https://www.rubydoc.info/gems/sinclair/1.8.0)
20
+ [https://www.rubydoc.info/gems/sinclair/1.9.0](https://www.rubydoc.info/gems/sinclair/1.9.0)
19
21
 
20
22
  Installation
21
23
  ---------------
@@ -475,6 +477,28 @@ Options allows projects to have an easy to configure option object
475
477
  ConnectionOptions.new(invalid: 10) # raises Sinclair::Exception::InvalidOptions
476
478
  ```
477
479
 
480
+ ### Sinclair::Comparable
481
+ Comparable allows a class to implement quickly a `==` method comparing given attributes
482
+
483
+ ```ruby
484
+ class SampleModel
485
+ include Sinclair::Comparable
486
+
487
+ comparable_by :name
488
+ attr_reader :name, :age
489
+
490
+ def initialize(name: nil, age: nil)
491
+ @name = name
492
+ @age = age
493
+ end
494
+ end
495
+
496
+ model1 = model_class.new(name: 'jack', age: 21)
497
+ model2 = model_class.new(name: 'jack', age: 23)
498
+
499
+ model1 == model2 # returns true
500
+ ```
501
+
478
502
  RSspec matcher
479
503
  ---------------
480
504
 
@@ -1,4 +1,5 @@
1
1
  ignore:
2
+ - lib/sinclair/comparable/class_methods.rb
2
3
  - lib/sinclair/matchers/add_method_to.rb
3
4
  - lib/sinclair/matchers/add_method.rb
4
5
  - lib/sinclair/version.rb
data/config/yardstick.yml CHANGED
@@ -19,6 +19,7 @@ rules:
19
19
  - Sinclair::Configurable#config
20
20
  - Sinclair::Configurable#reset_config
21
21
  - Sinclair::Configurable#configure
22
+ - Sinclair::EqualsChecker#initialize
22
23
  - Sinclair::Options#==
23
24
  - Sinclair::OptionsParser#options
24
25
  - Sinclair::OptionsParser#options_object
@@ -37,6 +38,7 @@ rules:
37
38
  - Sinclair::ConfigFactory#initialize
38
39
  - Sinclair::EnvSettable::Builder#initialize
39
40
  - Sinclair::Exception::InvalidOptions#initialize
41
+ - Sinclair::EqualsChecker#initialize
40
42
  - Sinclair::InputHash#initialize
41
43
  - Sinclair::Matchers::AddInstanceMethodTo#initialize
42
44
  - Sinclair::Matchers::AddClassMethodTo#initialize
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Sinclair
4
+ module Comparable
5
+ # @api public
6
+ # @author darthjee
7
+ #
8
+ # Class methods of {Sinclair::Comparable}
9
+ #
10
+ # @example (see Sinclair::Comparable)
11
+ module ClassMethods
12
+ # Adds fields to the comparison algorythim
13
+ #
14
+ # @param attributes [Array<Symbol>] attributes to be added to comparison
15
+ #
16
+ # @see Sinclair::EqualsChecker
17
+ # @return (see Sinclair::EqualsChecker#add)
18
+ # @example (see Sinclair::Comparable)
19
+ def comparable_by(*attributes)
20
+ equals_checker.add(*attributes)
21
+ end
22
+
23
+ # @api private
24
+ #
25
+ # Returns a comparable configured for the class
26
+ #
27
+ # @return [Sinclair::EqualsChecker]
28
+ def equals_checker
29
+ @equals_checker ||= Sinclair::EqualsChecker.new
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sinclair/comparable/class_methods'
4
+
5
+ class Sinclair
6
+ # @api public
7
+ # @author darthjee
8
+ #
9
+ # Concern to be added on classes for easy +==+ comparison
10
+ #
11
+ # @example
12
+ # class SampleModel
13
+ # include Sinclair::Comparable
14
+ #
15
+ # comparable_by :name
16
+ # attr_reader :name, :age
17
+ #
18
+ # def initialize(name: nil, age: nil)
19
+ # @name = name
20
+ # @age = age
21
+ # end
22
+ # end
23
+ #
24
+ # model1 = model_class.new(name: 'jack', age: 21)
25
+ # model2 = model_class.new(name: 'jack', age: 23)
26
+ #
27
+ # model1 == model2 # returns true
28
+ module Comparable
29
+ extend ActiveSupport::Concern
30
+
31
+ # Checks if an instance of a comparable is equals another
32
+ #
33
+ # @param other [Object] an object that should be equal to comparable
34
+ #
35
+ # @return [Boolean]
36
+ # @example (see Sinclair::Comparable)
37
+ def ==(other)
38
+ klass = self.class
39
+ superklass = klass.superclass
40
+
41
+ return false unless klass.equals_checker.match?(self, other)
42
+ return true unless superklass.include?(Sinclair::Comparable)
43
+
44
+ superklass.equals_checker.match?(self, other)
45
+ end
46
+ end
47
+ end
@@ -75,9 +75,11 @@ class Sinclair
75
75
  # @todo get rid of @config_attributes when only
76
76
  # Sinclair::ConfigClass are accepted
77
77
  def method_included?(method_name)
78
+ klass = @config.class
79
+
78
80
  @config_attributes.include?(method_name) ||
79
- @config.class.is_a?(Sinclair::ConfigClass) &&
80
- @config.class.config_attributes.include?(method_name)
81
+ klass.is_a?(Sinclair::ConfigClass) &&
82
+ klass.config_attributes.include?(method_name)
81
83
  end
82
84
  end
83
85
  end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Sinclair
4
+ # @api public
5
+ # @author darthjee
6
+ #
7
+ # Class responsible for checking if two instances of a class are the equals
8
+ #
9
+ # @example regular usage
10
+ # class SampleModel
11
+ # def initialize(name: nil, age: nil)
12
+ # @name = name
13
+ # @age = age
14
+ # end
15
+ #
16
+ # protected
17
+ #
18
+ # attr_reader :name
19
+ #
20
+ # private
21
+ #
22
+ # attr_reader :age
23
+ # end
24
+ #
25
+ # class OtherModel < SampleModel
26
+ # end
27
+ #
28
+ # checker = Sinclair::EqualsChecker.new(:name, :age)
29
+ #
30
+ # model1 = SampleModel.new(name: 'jack', age: 21)
31
+ # model2 = SampleModel.new(name: 'rose', age: 23)
32
+ #
33
+ # checker.match?(model1, model2) # returns false
34
+ #
35
+ # @example similar models
36
+ # checker = Sinclair::EqualsChecker.new(:name, :age)
37
+ #
38
+ # model1 = SampleModel.new(name: 'jack', age: 21)
39
+ # model2 = SampleModel.new(name: 'jack', age: 21)
40
+ #
41
+ # checker.match?(model1, model2) # returns true
42
+ #
43
+ # @example different classes
44
+ # checker = Sinclair::EqualsChecker.new(:name, :age)
45
+ #
46
+ # model1 = SampleModel.new(name: 'jack', age: 21)
47
+ # model2 = OtherModel.new(name: 'jack', age: 21)
48
+ #
49
+ # checker.match?(model1, model2) # returns false
50
+ class EqualsChecker
51
+ # @param attributes [Array<Symbol,String>] list of relevant attributes
52
+ def initialize(*attributes)
53
+ @attributes = Set.new(attributes.flatten)
54
+ end
55
+
56
+ # Adds new fields to equals checker
57
+ #
58
+ # @param attributes [Array<Symbol,String>] list of relevant attributes
59
+ #
60
+ # @return [Set<Symbol,String>]
61
+ #
62
+ # @example adding fields to equal checker
63
+ # checker = Sinclair::EqualsChecker.new(:name)
64
+ #
65
+ # model1 = SampleModel.new(name: 'jack', age: 21)
66
+ # model2 = SampleModel.new(name: 'jack', age: 22)
67
+ #
68
+ # checker.match?(model1, model2) # returns true
69
+ #
70
+ # checker.add(:age)
71
+ #
72
+ # checker.match?(model1, model2) # returns false
73
+ def add(*attributes)
74
+ @attributes += Set.new(attributes.flatten)
75
+ end
76
+
77
+ # Returns if 2 objects are equals
78
+ #
79
+ # The check takes into consideration:
80
+ # - They should be instances of the same class
81
+ # - Their attributes (method calls) should return the same value,
82
+ # for the configured attributes
83
+ # - Public and private attributes are checked
84
+ #
85
+ # @example (see Sinclair::EqualsChecker)
86
+ #
87
+ # @return [TrueClass,FalseClass]
88
+ def match?(model, other)
89
+ return false unless model.class == other.class
90
+
91
+ attributes.all? do |attr|
92
+ model.send(attr) == other.send(attr)
93
+ end
94
+ end
95
+
96
+ private
97
+
98
+ attr_reader :attributes
99
+
100
+ # @private
101
+ # @api private
102
+ # @method attributes
103
+ #
104
+ # attributes relevant for checking difference
105
+ #
106
+ # @return [Set<Symbol,String>]
107
+ end
108
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Sinclair
4
- VERSION = '1.8.0'
4
+ VERSION = '1.9.0'
5
5
  end
data/lib/sinclair.rb CHANGED
@@ -88,8 +88,10 @@ class Sinclair
88
88
  autoload :ConfigClass, 'sinclair/config_class'
89
89
  autoload :ConfigFactory, 'sinclair/config_factory'
90
90
  autoload :Configurable, 'sinclair/configurable'
91
+ autoload :Comparable, 'sinclair/comparable'
91
92
  autoload :EnvSettable, 'sinclair/env_settable'
92
93
  autoload :Exception, 'sinclair/exception'
94
+ autoload :EqualsChecker, 'sinclair/equals_checker'
93
95
  autoload :InputHash, 'sinclair/input_hash'
94
96
  autoload :MethodBuilder, 'sinclair/method_builder'
95
97
  autoload :MethodDefinition, 'sinclair/method_definition'
data/sinclair.gemspec CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |gem|
21
21
 
22
22
  gem.add_runtime_dependency 'activesupport', '~> 5.2.0'
23
23
 
24
- gem.add_development_dependency 'bundler', '2.3.20'
24
+ gem.add_development_dependency 'bundler', '2.3.25'
25
25
  gem.add_development_dependency 'pry', '0.14.1'
26
26
  gem.add_development_dependency 'pry-nav', '1.0.0'
27
27
  gem.add_development_dependency 'rake', '13.0.1'
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Sinclair::Comparable do
6
+ describe '#readme' do
7
+ describe '.comparable_by?' do
8
+ let(:model_class) do
9
+ Class.new(SampleModel) do
10
+ include Sinclair::Comparable
11
+
12
+ comparable_by :name
13
+ end
14
+ end
15
+
16
+ it 'regular usage' do
17
+ model1 = model_class.new(name: 'jack', age: 21)
18
+ model2 = model_class.new(name: 'jack', age: 23)
19
+
20
+ expect(model1 == model2).to be_truthy
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Sinclair::Comparable do
6
+ describe '#yard' do
7
+ describe '.comparable_by?' do
8
+ let(:model_class) do
9
+ Class.new(SampleModel) do
10
+ include Sinclair::Comparable
11
+
12
+ comparable_by :name
13
+ end
14
+ end
15
+
16
+ it 'regular usage' do
17
+ model1 = model_class.new(name: 'jack', age: 21)
18
+ model2 = model_class.new(name: 'jack', age: 23)
19
+
20
+ expect(model1 == model2).to be_truthy
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Sinclair::EqualsChecker do
6
+ describe '#yard' do
7
+ describe '#match?' do
8
+ it 'regular usage' do
9
+ checker = Sinclair::EqualsChecker.new(:name, :age)
10
+
11
+ model1 = SampleModel.new(name: 'jack', age: 21)
12
+ model2 = SampleModel.new(name: 'rose', age: 23)
13
+
14
+ expect(checker.match?(model1, model2)).to be_falsey
15
+ end
16
+
17
+ it 'similar models' do
18
+ checker = Sinclair::EqualsChecker.new(:name, :age)
19
+
20
+ model1 = SampleModel.new(name: 'jack', age: 21)
21
+ model2 = SampleModel.new(name: 'jack', age: 21)
22
+
23
+ expect(checker.match?(model1, model2)).to be_truthy
24
+ end
25
+
26
+ it 'different classes' do
27
+ checker = Sinclair::EqualsChecker.new(:name, :age)
28
+
29
+ model1 = SampleModel.new(name: 'jack', age: 21)
30
+ model2 = OtherModel.new(name: 'jack', age: 21)
31
+
32
+ expect(checker.match?(model1, model2)).to be_falsey
33
+ end
34
+ end
35
+
36
+ describe '#add' do
37
+ it 'adding fields to equal checker' do
38
+ checker = Sinclair::EqualsChecker.new(:name)
39
+
40
+ model1 = SampleModel.new(name: 'jack', age: 21)
41
+ model2 = SampleModel.new(name: 'jack', age: 22)
42
+
43
+ expect(checker.match?(model1, model2)).to be_truthy
44
+
45
+ checker.add(:age)
46
+
47
+ expect(checker.match?(model1, model2)).to be_falsey
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,202 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Sinclair::Comparable do
6
+ let(:model_class) do
7
+ Class.new(SampleModel) do
8
+ include Sinclair::Comparable
9
+ end
10
+ end
11
+
12
+ let(:attributes) { %i[] }
13
+ let(:model1_class) { model_class }
14
+ let(:model2_class) { model_class }
15
+ let(:model1) { model1_class.new(**model1_attributes) }
16
+ let(:model2) { model2_class.new(**model2_attributes) }
17
+
18
+ let(:model1_attributes) { { name: name1, age: age1 } }
19
+ let(:model2_attributes) { { name: name2, age: age2 } }
20
+ let(:name1) { SecureRandom.hex(10) }
21
+ let(:name2) { SecureRandom.hex(10) }
22
+ let(:age1) { Random.rand(10..20) }
23
+ let(:age2) { Random.rand(21..50) }
24
+
25
+ describe '.comparable_by' do
26
+ let(:model2_class) { model1_class }
27
+
28
+ context 'when no field was present' do
29
+ it 'adds the field for comparison' do
30
+ expect { model1_class.comparable_by(:name) }
31
+ .to change { model1 == model2 }
32
+ .from(true).to(false)
33
+ end
34
+ end
35
+
36
+ context 'when there was a field present' do
37
+ let(:name2) { name1 }
38
+
39
+ before { model1_class.comparable_by(:name) }
40
+
41
+ it 'adds the field for comparison' do
42
+ expect { model1_class.comparable_by(:age) }
43
+ .to change { model1 == model2 }
44
+ .from(true).to(false)
45
+ end
46
+ end
47
+
48
+ context 'when there was a field present and it made a non match' do
49
+ let(:age2) { age1 }
50
+
51
+ before { model1_class.comparable_by(:name) }
52
+
53
+ it 'adds the field for comparison without forgeting the previous' do
54
+ expect { model1_class.comparable_by(:age) }
55
+ .not_to change { model1 == model2 }
56
+ .from(false)
57
+ end
58
+ end
59
+
60
+ context 'when the class parent class adds a field' do
61
+ let(:model1_class) { Class.new(model_class) }
62
+ let(:model2_class) { model1_class }
63
+
64
+ it 'takes the field into consideration' do
65
+ expect { model_class.comparable_by(:name) }
66
+ .to change { model1 == model2 }
67
+ .from(true).to(false)
68
+ end
69
+
70
+ context 'when we add a field to the class itself' do
71
+ let(:name2) { name1 }
72
+
73
+ before { model_class.comparable_by(:name) }
74
+
75
+ it 'takes all fields into consideration' do
76
+ expect { model1_class.comparable_by(:age) }
77
+ .to change { model1 == model2 }
78
+ .from(true).to(false)
79
+ end
80
+ end
81
+
82
+ context 'when we add a field to the parent class after' do
83
+ let(:name2) { name1 }
84
+
85
+ before { model1_class.comparable_by(:name) }
86
+
87
+ it 'takes all fields into consideration' do
88
+ expect { model_class.comparable_by(:age) }
89
+ .to change { model1 == model2 }
90
+ .from(true).to(false)
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ describe '#==' do
97
+ before do
98
+ model1_class.comparable_by(attributes)
99
+ model2_class.comparable_by(attributes)
100
+ end
101
+
102
+ context 'when the attributes is empty' do
103
+ context 'when they are different classes and attributes are the same' do
104
+ let(:model2_class) { Class.new(model1_class) }
105
+ let(:name2) { name1 }
106
+ let(:age2) { age1 }
107
+
108
+ it do
109
+ expect(model1).not_to eq(model2)
110
+ end
111
+ end
112
+
113
+ context 'when the models have the same attributes' do
114
+ let(:name2) { name1 }
115
+ let(:age2) { age1 }
116
+
117
+ it do
118
+ expect(model1).to eq(model2)
119
+ end
120
+ end
121
+
122
+ context 'when the models have very different attributes' do
123
+ it do
124
+ expect(model1).to eq(model2)
125
+ end
126
+ end
127
+ end
128
+
129
+ context 'when the attributes is missing just one attribute' do
130
+ let(:attributes) { %i[name] }
131
+
132
+ context 'when they are different classes and attributes are the same' do
133
+ let(:model2_class) { Class.new(model1_class) }
134
+ let(:name2) { name1 }
135
+ let(:age2) { age1 }
136
+
137
+ it do
138
+ expect(model1).not_to eq(model2)
139
+ end
140
+ end
141
+
142
+ context 'when the models have a non listed different attribute' do
143
+ let(:name2) { name1 }
144
+
145
+ it do
146
+ expect(model1).to eq(model2)
147
+ end
148
+ end
149
+
150
+ context 'when the models have a listed different attribute' do
151
+ let(:age2) { age1 }
152
+
153
+ it do
154
+ expect(model1).not_to eq(model2)
155
+ end
156
+ end
157
+
158
+ context 'when the models have very different attributes' do
159
+ it do
160
+ expect(model1).not_to eq(model2)
161
+ end
162
+ end
163
+ end
164
+
165
+ context 'when all attributes are included' do
166
+ let(:attributes) { %i[name age] }
167
+
168
+ context 'when they are different classes and attributes are the same' do
169
+ let(:model2_class) { Class.new(model1_class) }
170
+ let(:name2) { name1 }
171
+ let(:age2) { age1 }
172
+
173
+ it do
174
+ expect(model1).not_to eq(model2)
175
+ end
176
+ end
177
+
178
+ context 'when the models have the same attributes' do
179
+ let(:name2) { name1 }
180
+ let(:age2) { age1 }
181
+
182
+ it do
183
+ expect(model1).to eq(model2)
184
+ end
185
+ end
186
+
187
+ context 'when the models have a listed different attribute' do
188
+ let(:name) { name1 }
189
+
190
+ it do
191
+ expect(model1).not_to eq(model2)
192
+ end
193
+ end
194
+
195
+ context 'when the models have very different attributes' do
196
+ it do
197
+ expect(model1).not_to eq(model2)
198
+ end
199
+ end
200
+ end
201
+ end
202
+ end
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Sinclair::EqualsChecker do
6
+ subject(:checker) { described_class.new(attributes) }
7
+
8
+ let(:attributes) { %i[] }
9
+
10
+ let(:model1_class) { SampleModel }
11
+ let(:model2_class) { SampleModel }
12
+ let(:model1) { model1_class.new(**model1_attributes) }
13
+ let(:model2) { model2_class.new(**model2_attributes) }
14
+
15
+ let(:model1_attributes) { { name: name1, age: age1 } }
16
+ let(:model2_attributes) { { name: name2, age: age2 } }
17
+ let(:name1) { SecureRandom.hex(10) }
18
+ let(:name2) { SecureRandom.hex(10) }
19
+ let(:age1) { Random.rand(10..20) }
20
+ let(:age2) { Random.rand(21..50) }
21
+
22
+ describe 'match?' do
23
+ context 'when the attributes is empty' do
24
+ context 'when they are different classes and attributes are the same' do
25
+ let(:model2_class) { Class.new(SampleModel) }
26
+ let(:name2) { name1 }
27
+ let(:age2) { age1 }
28
+
29
+ it do
30
+ expect(checker).not_to be_match(model1, model2)
31
+ end
32
+ end
33
+
34
+ context 'when the models have the same attributes' do
35
+ let(:name2) { name1 }
36
+ let(:age2) { age1 }
37
+
38
+ it do
39
+ expect(checker).to be_match(model1, model2)
40
+ end
41
+ end
42
+
43
+ context 'when the models have very different attributes' do
44
+ it do
45
+ expect(checker).to be_match(model1, model2)
46
+ end
47
+ end
48
+ end
49
+
50
+ context 'when the attributes is missing just one attribute' do
51
+ let(:attributes) { %i[name] }
52
+
53
+ context 'when they are different classes and attributes are the same' do
54
+ let(:model2_class) { Class.new(SampleModel) }
55
+ let(:name2) { name1 }
56
+ let(:age2) { age1 }
57
+
58
+ it do
59
+ expect(checker).not_to be_match(model1, model2)
60
+ end
61
+ end
62
+
63
+ context 'when the models have a non listed different attribute' do
64
+ let(:name2) { name1 }
65
+
66
+ it do
67
+ expect(checker).to be_match(model1, model2)
68
+ end
69
+ end
70
+
71
+ context 'when the models have a listed different attribute' do
72
+ let(:age2) { age1 }
73
+
74
+ it do
75
+ expect(checker).not_to be_match(model1, model2)
76
+ end
77
+ end
78
+
79
+ context 'when the models have very different attributes' do
80
+ it do
81
+ expect(checker).not_to be_match(model1, model2)
82
+ end
83
+ end
84
+ end
85
+
86
+ context 'when all attributes are included' do
87
+ let(:attributes) { %i[name age] }
88
+
89
+ context 'when they are different classes and attributes are the same' do
90
+ let(:model2_class) { Class.new(SampleModel) }
91
+ let(:name2) { name1 }
92
+ let(:age2) { age1 }
93
+
94
+ it do
95
+ expect(checker).not_to be_match(model1, model2)
96
+ end
97
+ end
98
+
99
+ context 'when the models have the same attributes' do
100
+ let(:name2) { name1 }
101
+ let(:age2) { age1 }
102
+
103
+ it do
104
+ expect(checker).to be_match(model1, model2)
105
+ end
106
+ end
107
+
108
+ context 'when the models have a listed different attribute' do
109
+ let(:name) { name1 }
110
+
111
+ it do
112
+ expect(checker).not_to be_match(model1, model2)
113
+ end
114
+ end
115
+
116
+ context 'when the models have very different attributes' do
117
+ it do
118
+ expect(checker).not_to be_match(model1, model2)
119
+ end
120
+ end
121
+ end
122
+ end
123
+
124
+ describe '#add' do
125
+ let(:attributes) { [:name] }
126
+ let(:new_attributes) { [:age] }
127
+
128
+ context 'when the new field has different values' do
129
+ let(:name2) { name1 }
130
+
131
+ it 'uses the new field to the match' do
132
+ expect { checker.add(new_attributes) }
133
+ .to change { checker.match?(model1, model2) }
134
+ .from(true).to(false)
135
+ end
136
+ end
137
+
138
+ context 'when the old field has different values' do
139
+ let(:age2) { age1 }
140
+
141
+ it 'uses the new field to the match' do
142
+ expect { checker.add(new_attributes) }
143
+ .not_to change { checker.match?(model1, model2) }
144
+ .from(false)
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SampleModel
4
+ def initialize(name: nil, age: nil)
5
+ @name = name
6
+ @age = age
7
+ end
8
+
9
+ protected
10
+
11
+ attr_reader :name
12
+
13
+ private
14
+
15
+ attr_reader :age
16
+ end
17
+
18
+ class OtherModel < SampleModel
19
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sinclair
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.0
4
+ version: 1.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - DarthJee
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-31 00:00:00.000000000 Z
11
+ date: 2023-01-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - '='
32
32
  - !ruby/object:Gem::Version
33
- version: 2.3.20
33
+ version: 2.3.25
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - '='
39
39
  - !ruby/object:Gem::Version
40
- version: 2.3.20
40
+ version: 2.3.25
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: pry
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -272,6 +272,8 @@ files:
272
272
  - config/yardstick.yml
273
273
  - docker-compose.yml
274
274
  - lib/sinclair.rb
275
+ - lib/sinclair/comparable.rb
276
+ - lib/sinclair/comparable/class_methods.rb
275
277
  - lib/sinclair/config.rb
276
278
  - lib/sinclair/config/methods_builder.rb
277
279
  - lib/sinclair/config_builder.rb
@@ -280,6 +282,7 @@ files:
280
282
  - lib/sinclair/configurable.rb
281
283
  - lib/sinclair/env_settable.rb
282
284
  - lib/sinclair/env_settable/builder.rb
285
+ - lib/sinclair/equals_checker.rb
283
286
  - lib/sinclair/exception.rb
284
287
  - lib/sinclair/input_hash.rb
285
288
  - lib/sinclair/matchers.rb
@@ -314,18 +317,21 @@ files:
314
317
  - sinclair.jpg
315
318
  - spec/integration/readme/my_class_spec.rb
316
319
  - spec/integration/readme/my_model_spec.rb
320
+ - spec/integration/readme/sinclair/comparable_spec.rb
317
321
  - spec/integration/readme/sinclair/configurable_spec.rb
318
322
  - spec/integration/readme/sinclair/env_settable_spec.rb
319
323
  - spec/integration/readme/sinclair/matchers_spec.rb
320
324
  - spec/integration/readme/sinclair/options_spec.rb
321
325
  - spec/integration/readme/sinclair_spec.rb
322
326
  - spec/integration/yard/my_builder_spec.rb
327
+ - spec/integration/yard/sinclair/comparable_spec.rb
323
328
  - spec/integration/yard/sinclair/config_builder_spec.rb
324
329
  - spec/integration/yard/sinclair/config_class_spec.rb
325
330
  - spec/integration/yard/sinclair/config_factory_spec.rb
326
331
  - spec/integration/yard/sinclair/config_spec.rb
327
332
  - spec/integration/yard/sinclair/configurable_spec.rb
328
333
  - spec/integration/yard/sinclair/env_settable_spec.rb
334
+ - spec/integration/yard/sinclair/equals_checker_spec.rb
329
335
  - spec/integration/yard/sinclair/input_hash_spec.rb
330
336
  - spec/integration/yard/sinclair/matchers/add_class_method_spec.rb
331
337
  - spec/integration/yard/sinclair/matchers/add_class_method_to_spec.rb
@@ -334,6 +340,7 @@ files:
334
340
  - spec/integration/yard/sinclair/options_parser_spec.rb
335
341
  - spec/integration/yard/sinclair/options_spec.rb
336
342
  - spec/integration/yard/sinclair_spec.rb
343
+ - spec/lib/sinclair/comparable_spec.rb
337
344
  - spec/lib/sinclair/config/methods_builder_spec.rb
338
345
  - spec/lib/sinclair/config_builder_spec.rb
339
346
  - spec/lib/sinclair/config_class_spec.rb
@@ -342,6 +349,7 @@ files:
342
349
  - spec/lib/sinclair/configurable_spec.rb
343
350
  - spec/lib/sinclair/env_settable/builder_spec.rb
344
351
  - spec/lib/sinclair/env_settable_spec.rb
352
+ - spec/lib/sinclair/equals_checker_spec.rb
345
353
  - spec/lib/sinclair/exception/invalid_options_spec.rb
346
354
  - spec/lib/sinclair/input_hash_spec.rb
347
355
  - spec/lib/sinclair/matchers/add_class_method_spec.rb
@@ -404,6 +412,7 @@ files:
404
412
  - spec/support/models/server_config.rb
405
413
  - spec/support/models/service_client.rb
406
414
  - spec/support/models/validator_builder.rb
415
+ - spec/support/sample_model.rb
407
416
  - spec/support/shared_examples/class_method_definition.rb
408
417
  - spec/support/shared_examples/config.rb
409
418
  - spec/support/shared_examples/config_factory.rb
@@ -427,7 +436,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
427
436
  - !ruby/object:Gem::Version
428
437
  version: '0'
429
438
  requirements: []
430
- rubygems_version: 3.3.20
439
+ rubygems_version: 3.3.25
431
440
  signing_key:
432
441
  specification_version: 4
433
442
  summary: Gem for easy concern creation