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 +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
|