sinclair 1.8.0 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  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