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 +4 -4
- data/.circleci/config.yml +20 -6
- data/.rubocop.yml +4 -1
- data/Dockerfile +1 -1
- data/README.md +25 -1
- data/config/check_specs.yml +1 -0
- data/config/yardstick.yml +2 -0
- data/lib/sinclair/comparable/class_methods.rb +33 -0
- data/lib/sinclair/comparable.rb +47 -0
- data/lib/sinclair/config_builder.rb +4 -2
- data/lib/sinclair/equals_checker.rb +108 -0
- data/lib/sinclair/version.rb +1 -1
- data/lib/sinclair.rb +2 -0
- data/sinclair.gemspec +1 -1
- data/spec/integration/readme/sinclair/comparable_spec.rb +24 -0
- data/spec/integration/yard/sinclair/comparable_spec.rb +24 -0
- data/spec/integration/yard/sinclair/equals_checker_spec.rb +51 -0
- data/spec/lib/sinclair/comparable_spec.rb +202 -0
- data/spec/lib/sinclair/equals_checker_spec.rb +148 -0
- data/spec/support/sample_model.rb +19 -0
- metadata +14 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 23c4aa7f5d3c743f783dc6196e0799bbef94fa2c4f42825379c4cc61aad8e9ec
|
4
|
+
data.tar.gz: 4aa6481202521cc4c0cf8b0210e798a8d56344a43c42e41157ae7a3121ea67a4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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.
|
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
|
-
|
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
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.
|
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
|
|
data/config/check_specs.yml
CHANGED
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
|
-
|
80
|
-
|
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
|
data/lib/sinclair/version.rb
CHANGED
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.
|
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.
|
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:
|
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.
|
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.
|
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.
|
439
|
+
rubygems_version: 3.3.25
|
431
440
|
signing_key:
|
432
441
|
specification_version: 4
|
433
442
|
summary: Gem for easy concern creation
|