sinclair 1.6.6 → 1.8.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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +2 -2
  3. data/Dockerfile +2 -2
  4. data/README.md +8 -1
  5. data/config/check_specs.yml +3 -0
  6. data/config/yardstick.yml +7 -1
  7. data/lib/sinclair/config.rb +46 -0
  8. data/lib/sinclair/config_class.rb +15 -0
  9. data/lib/sinclair/configurable.rb +10 -2
  10. data/lib/sinclair/matchers/add_class_method.rb +16 -13
  11. data/lib/sinclair/matchers/add_class_method_to.rb +9 -23
  12. data/lib/sinclair/matchers/add_instance_method.rb +16 -18
  13. data/lib/sinclair/matchers/add_instance_method_to.rb +12 -16
  14. data/lib/sinclair/matchers/add_method.rb +39 -30
  15. data/lib/sinclair/matchers/add_method_to.rb +4 -56
  16. data/lib/sinclair/matchers/base.rb +45 -0
  17. data/lib/sinclair/matchers/change_class_method.rb +42 -0
  18. data/lib/sinclair/matchers/change_class_method_on.rb +64 -0
  19. data/lib/sinclair/matchers/change_instance_method.rb +42 -0
  20. data/lib/sinclair/matchers/change_instance_method_on.rb +98 -0
  21. data/lib/sinclair/matchers/change_method_on.rb +25 -0
  22. data/lib/sinclair/matchers/method_to.rb +82 -0
  23. data/lib/sinclair/matchers.rb +38 -30
  24. data/lib/sinclair/options/class_methods.rb +1 -5
  25. data/lib/sinclair/version.rb +1 -1
  26. data/sinclair.gemspec +12 -12
  27. data/spec/integration/readme/my_class_spec.rb +1 -1
  28. data/spec/integration/readme/sinclair/configurable_spec.rb +11 -1
  29. data/spec/integration/yard/sinclair/config_spec.rb +27 -0
  30. data/spec/lib/sinclair/config_class_spec.rb +1 -33
  31. data/spec/lib/sinclair/config_spec.rb +85 -0
  32. data/spec/lib/sinclair/matchers/add_class_method_to_spec.rb +40 -16
  33. data/spec/lib/sinclair/matchers/add_instance_method_to_spec.rb +36 -12
  34. data/spec/lib/sinclair/matchers/change_class_method_on_spec.rb +138 -0
  35. data/spec/lib/sinclair/matchers/change_class_method_spec.rb +38 -0
  36. data/spec/lib/sinclair/matchers/change_instance_method_on_spec.rb +149 -0
  37. data/spec/lib/sinclair/matchers/change_instance_method_spec.rb +38 -0
  38. data/spec/lib/sinclair/matchers_spec.rb +30 -0
  39. data/spec/support/models/login_configurable.rb +7 -0
  40. data/spec/support/shared_examples/config.rb +103 -0
  41. metadata +39 -28
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Sinclair
4
+ module Matchers
5
+ # @api private
6
+ # @author darthjee
7
+ #
8
+ # AddInstanceMethod is able to build an instance of
9
+ # {Sinclair::Matchers::ChangeClassMethodOn}
10
+ class ChangeClassMethod < Base
11
+ include AddMethod
12
+
13
+ # @api public
14
+ #
15
+ # Builds final matcher
16
+ #
17
+ # @return [Sinclair::Matchers::ChangeClassMethodOn]
18
+ alias on to
19
+
20
+ private
21
+
22
+ # @private
23
+ #
24
+ # Error description on wrong usage
25
+ #
26
+ # @return String
27
+ def matcher_error
28
+ 'You should specify which class the method is being changed on' \
29
+ "change_class_method(:#{method_name}).on(klass)"
30
+ end
31
+
32
+ # @private
33
+ #
34
+ # Class of the real matcher
35
+ #
36
+ # @return [Class<ChangeClassMethodOn>]
37
+ def add_method_to_class
38
+ ChangeClassMethodOn
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Sinclair
4
+ module Matchers
5
+ # @api private
6
+ # @author darthjee
7
+ #
8
+ # Checks if a class method was changed
9
+ # by the call of a block
10
+ #
11
+ # This is used with a RSpec DSL method
12
+ # change_class_method(method_name).on(class_object)
13
+ class ChangeClassMethodOn < ChangeMethodOn
14
+ # @param target [Class]
15
+ # Class where the class method should be added to
16
+ #
17
+ # @param method_name [Symbol,String] method name
18
+ def initialize(target, method_name)
19
+ @klass = target
20
+ super(method_name)
21
+ end
22
+
23
+ # Return expectaton description
24
+ #
25
+ # @return [String]
26
+ def description
27
+ "change class method '#{method_name}' on #{klass}"
28
+ end
29
+
30
+ # Returns message on expectation failure
31
+ #
32
+ # @return [String]
33
+ def failure_message_for_should
34
+ "expected class method '#{method_name}' to be changed on #{klass} but " \
35
+ "#{initial_state ? "it didn't" : "it didn't exist"}"
36
+ end
37
+
38
+ # Returns message on expectation failure for negative expectation
39
+ #
40
+ # @return [String]
41
+ def failure_message_for_should_not
42
+ "expected class method '#{method_name}' not to be changed on #{klass} but it was"
43
+ end
44
+
45
+ private
46
+
47
+ # Checks if class has instance method defined
48
+ #
49
+ # @return [Boolean]
50
+ def state
51
+ klass.methods(false).include?(method_name.to_sym) \
52
+ && klass.method(method_name)
53
+ end
54
+
55
+ # Raises when block was not given
56
+ #
57
+ # @raise SyntaxError
58
+ def raise_block_syntax_error
59
+ raise SyntaxError, 'Block not received by the `change_class_method_on` matcher. ' \
60
+ 'Perhaps you want to use `{ ... }` instead of do/end?'
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Sinclair
4
+ module Matchers
5
+ # @api private
6
+ # @author darthjee
7
+ #
8
+ # AddInstanceMethod is able to build an instance of
9
+ # {Sinclair::Matchers::ChangeInstanceMethodOn}
10
+ class ChangeInstanceMethod < Base
11
+ include AddMethod
12
+
13
+ # @api public
14
+ #
15
+ # Builds final matcher
16
+ #
17
+ # @return [Sinclair::Matchers::ChangeInstanceMethodOn]
18
+ alias on to
19
+
20
+ private
21
+
22
+ # @private
23
+ #
24
+ # Error description on wrong usage
25
+ #
26
+ # @return String
27
+ def matcher_error
28
+ 'You should specify which instance the method is being changed on' \
29
+ "change_method(:#{method_name}).on(instance)"
30
+ end
31
+
32
+ # @private
33
+ #
34
+ # Class of the real matcher
35
+ #
36
+ # @return [Class<Sinclair::Matchers::Base>]
37
+ def add_method_to_class
38
+ ChangeInstanceMethodOn
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Sinclair
4
+ module Matchers
5
+ # @api private
6
+ # @author darthjee
7
+ #
8
+ # Checks if a method was changed
9
+ # by the call of a block
10
+ #
11
+ # This is used with a RSpec DSL method
12
+ # change_method(method_name).on(class_object)
13
+ class ChangeInstanceMethodOn < ChangeMethodOn
14
+ # @overload initialize(klass, method_name)
15
+ # @param [Class] klass
16
+ # class where the method should be added to
17
+ #
18
+ # @overload initialize(instance, method_name)
19
+ # @param [Object] instance
20
+ # instance of the class where the method should be added to
21
+ #
22
+ # @param method_name [Symbol,String] method name
23
+ def initialize(target, method_name)
24
+ if target.is_a?(Class)
25
+ @klass = target
26
+ else
27
+ @instance = target
28
+ end
29
+
30
+ super(method_name)
31
+ end
32
+
33
+ # Returnst expectaton description
34
+ #
35
+ # @return [String]
36
+ def description
37
+ "change method '#{method_name}' on #{klass} instances"
38
+ end
39
+
40
+ # Returns message on expectation failure
41
+ #
42
+ # @return [String]
43
+ def failure_message_for_should
44
+ "expected '#{method_name}' to be changed on #{klass} but " \
45
+ "#{initial_state ? "it didn't" : "it didn't exist"}"
46
+ end
47
+
48
+ # Returns message on expectation failure for negative expectation
49
+ #
50
+ # @return [String]
51
+ def failure_message_for_should_not
52
+ "expected '#{method_name}' not to be changed on #{klass} but it was"
53
+ end
54
+
55
+ protected
56
+
57
+ # @method instance
58
+ # @api private
59
+ # @private
60
+ #
61
+ # Instance of the class where the method should be added
62
+ #
63
+ # @return [Object]
64
+ attr_reader :instance
65
+
66
+ # @private
67
+ #
68
+ # Class to be analised
69
+ #
70
+ # @return [Class]
71
+ def klass
72
+ @klass ||= instance.class
73
+ end
74
+
75
+ private
76
+
77
+ # @private
78
+ #
79
+ # Checks if class has instance method defined
80
+ #
81
+ # @return [Boolean]
82
+ def state
83
+ klass.method_defined?(method_name) &&
84
+ klass.instance_method(method_name)
85
+ end
86
+
87
+ # @private
88
+ #
89
+ # Raises when block was not given
90
+ #
91
+ # @raise SyntaxError
92
+ def raise_block_syntax_error
93
+ raise SyntaxError, 'Block not received by the `change_instance_method_on` matcher. ' \
94
+ 'Perhaps you want to use `{ ... }` instead of do/end?'
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Sinclair
4
+ module Matchers
5
+ # @api private
6
+ # @author darthjee
7
+ # @abstract
8
+ #
9
+ # Base class for change_method_on matcher
10
+ class ChangeMethodOn < Base
11
+ include MethodTo
12
+
13
+ private
14
+
15
+ # @private
16
+ #
17
+ # Checks if a method was changed
18
+ #
19
+ # @return Boolean
20
+ def check
21
+ initial_state && initial_state != final_state
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Sinclair
4
+ module Matchers
5
+ # @api private
6
+ #
7
+ # Common methods on final matchers
8
+ module MethodTo
9
+ # Used for other versions of rspec
10
+ #
11
+ # Some versions call failure_message, others
12
+ # call failure_message_for_should
13
+ #
14
+ # @return [String]
15
+ def failure_message
16
+ failure_message_for_should
17
+ end
18
+
19
+ # Used for other versions of rspec
20
+ #
21
+ # Some versions call failure_message_when_negated, others
22
+ # call failure_message_for_should_not
23
+ #
24
+ # @return [String]
25
+ def failure_message_when_negated
26
+ failure_message_for_should_not
27
+ end
28
+
29
+ # Checks if expectation is true or not
30
+ #
31
+ # @return [Boolean] expectation check
32
+ def matches?(event_proc)
33
+ return false unless event_proc.is_a?(Proc)
34
+
35
+ raise_block_syntax_error if block_given?
36
+ perform_change(event_proc)
37
+ check
38
+ end
39
+
40
+ protected
41
+
42
+ # @method klass
43
+ # @api private
44
+ # @private
45
+ #
46
+ # Class where class method should be added to
47
+ #
48
+ # @return [Class]
49
+ attr_reader :klass
50
+
51
+ private
52
+
53
+ # @method initial_state
54
+ # @api private
55
+ # @private
56
+ #
57
+ # State before running the block
58
+ #
59
+ # @return [Object]
60
+
61
+ # @method final_state
62
+ # @api private
63
+ # @private
64
+ #
65
+ # State after running the block
66
+ #
67
+ # @return [Object]
68
+ attr_reader :initial_state, :final_state
69
+
70
+ # @private
71
+ #
72
+ # Call block to check if it aded a method or not
73
+ #
74
+ # @return [Boolan]
75
+ def perform_change(event_proc)
76
+ @initial_state = state
77
+ event_proc.call
78
+ @final_state = state
79
+ end
80
+ end
81
+ end
82
+ end
@@ -7,33 +7,21 @@ class Sinclair
7
7
  # Matchers module will have the DSL to be included in RSpec in order to have
8
8
  # access to the matchers
9
9
  #
10
- # @example
11
- # RSpec.configure do |config|
12
- # config.include Sinclair::Matchers
13
- # end
14
- #
15
- # class MyModel
16
- # end
17
- #
18
- # RSpec.describe 'my test' do
19
- # let(:klass) { Class.new(MyModel) }
20
- # let(:builder) { Sinclair.new(klass) }
21
- #
22
- # before do
23
- # builder.add_method(:class_name, 'self.class.name')
24
- # end
25
- #
26
- # it do
27
- # expect { builder.build }.to add_method(:class_name).to(klass)
28
- # end
29
- # end
10
+ # @example (see Sinclair::Matchers::AddMethod#to)
30
11
  module Matchers
31
- autoload :AddMethod, 'sinclair/matchers/add_method'
32
- autoload :AddInstanceMethod, 'sinclair/matchers/add_instance_method'
33
- autoload :AddClassMethod, 'sinclair/matchers/add_class_method'
34
- autoload :AddMethodTo, 'sinclair/matchers/add_method_to'
35
- autoload :AddInstanceMethodTo, 'sinclair/matchers/add_instance_method_to'
36
- autoload :AddClassMethodTo, 'sinclair/matchers/add_class_method_to'
12
+ autoload :Base, 'sinclair/matchers/base'
13
+ autoload :AddInstanceMethod, 'sinclair/matchers/add_instance_method'
14
+ autoload :AddClassMethod, 'sinclair/matchers/add_class_method'
15
+ autoload :AddMethod, 'sinclair/matchers/add_method'
16
+ autoload :AddMethodTo, 'sinclair/matchers/add_method_to'
17
+ autoload :AddInstanceMethodTo, 'sinclair/matchers/add_instance_method_to'
18
+ autoload :AddClassMethodTo, 'sinclair/matchers/add_class_method_to'
19
+ autoload :ChangeClassMethod, 'sinclair/matchers/change_class_method'
20
+ autoload :ChangeInstanceMethod, 'sinclair/matchers/change_instance_method'
21
+ autoload :ChangeMethodOn, 'sinclair/matchers/change_method_on'
22
+ autoload :ChangeClassMethodOn, 'sinclair/matchers/change_class_method_on'
23
+ autoload :ChangeInstanceMethodOn, 'sinclair/matchers/change_instance_method_on'
24
+ autoload :MethodTo, 'sinclair/matchers/method_to'
37
25
 
38
26
  # DSL to AddInstanceMethod
39
27
  #
@@ -41,8 +29,8 @@ class Sinclair
41
29
  # @example (see Sinclair::Matchers::AddInstanceMethod#to)
42
30
  #
43
31
  # @return [AddInstanceMethod] RSpec Matcher
44
- def add_method(method)
45
- Sinclair::Matchers::AddInstanceMethod.new(method)
32
+ def add_method(method_name)
33
+ Sinclair::Matchers::AddInstanceMethod.new(method_name)
46
34
  end
47
35
 
48
36
  # DSL to AddClassMethod
@@ -51,8 +39,28 @@ class Sinclair
51
39
  # @example (see Sinclair::Matchers::AddClassMethod#to)
52
40
  #
53
41
  # @return [AddClassMethod] RSpec Matcher
54
- def add_class_method(method)
55
- Sinclair::Matchers::AddClassMethod.new(method)
42
+ def add_class_method(method_name)
43
+ Sinclair::Matchers::AddClassMethod.new(method_name)
44
+ end
45
+
46
+ # DSL to ChangeInstanceMethod
47
+ #
48
+ # @example (see Sinclair::Matchers)
49
+ # @example (see Sinclair::Matchers::ChangeInstanceMethod#to)
50
+ #
51
+ # @return [ChangeInstanceMethod] RSpec Matcher
52
+ def change_method(method_name)
53
+ Sinclair::Matchers::ChangeInstanceMethod.new(method_name)
54
+ end
55
+
56
+ # DSL to ChangeClassMethod
57
+ #
58
+ # @example (see Sinclair::Matchers)
59
+ # @example (see Sinclair::Matchers::ChangeClassMethod#to)
60
+ #
61
+ # @return [ChangeClassMethod] RSpec Matcher
62
+ def change_class_method(method_name)
63
+ Sinclair::Matchers::ChangeClassMethod.new(method_name)
56
64
  end
57
65
  end
58
66
  end
@@ -4,7 +4,7 @@ require 'set'
4
4
 
5
5
  class Sinclair
6
6
  class Options
7
- # Class Methods for {Sinclai::Options}
7
+ # Class Methods for {Sinclair::Options}
8
8
  module ClassMethods
9
9
  # @api private
10
10
  #
@@ -47,10 +47,7 @@ class Sinclair
47
47
  @skip_validation ||= superclass.try(:skip_validation?) || false
48
48
  end
49
49
 
50
- private
51
-
52
50
  # @api public
53
- # @!visibility public
54
51
  #
55
52
  # Add available options
56
53
  #
@@ -71,7 +68,6 @@ class Sinclair
71
68
  end
72
69
 
73
70
  # @api public
74
- # @!visibility public
75
71
  #
76
72
  # Changes class to skip attributes validation
77
73
  #
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Sinclair
4
- VERSION = '1.6.6'
4
+ VERSION = '1.8.0'
5
5
  end
data/sinclair.gemspec CHANGED
@@ -21,20 +21,20 @@ 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', '1.16.1'
25
- gem.add_development_dependency 'pry', '0.12.2'
26
- gem.add_development_dependency 'pry-nav', '0.3.0'
24
+ gem.add_development_dependency 'bundler', '2.3.20'
25
+ gem.add_development_dependency 'pry', '0.14.1'
26
+ gem.add_development_dependency 'pry-nav', '1.0.0'
27
27
  gem.add_development_dependency 'rake', '13.0.1'
28
- gem.add_development_dependency 'reek', '5.6.0'
29
- gem.add_development_dependency 'rspec', '3.9.0'
30
- gem.add_development_dependency 'rspec-core', '3.9.1'
31
- gem.add_development_dependency 'rspec-expectations', '3.9.1'
32
- gem.add_development_dependency 'rspec-mocks', '3.9.1'
33
- gem.add_development_dependency 'rspec-support', '3.9.2'
28
+ gem.add_development_dependency 'reek', '6.0.3'
29
+ gem.add_development_dependency 'rspec', '3.11.0'
30
+ gem.add_development_dependency 'rspec-core', '3.11.0'
31
+ gem.add_development_dependency 'rspec-expectations', '3.11.0'
32
+ gem.add_development_dependency 'rspec-mocks', '3.11.1'
33
+ gem.add_development_dependency 'rspec-support', '3.11.0'
34
34
  gem.add_development_dependency 'rubocop', '0.80.1'
35
35
  gem.add_development_dependency 'rubocop-rspec', '1.38.1'
36
- gem.add_development_dependency 'rubycritic', '4.4.1'
37
- gem.add_development_dependency 'simplecov', '0.17.1'
38
- gem.add_development_dependency 'yard', '0.9.24'
36
+ gem.add_development_dependency 'rubycritic', '4.7.0'
37
+ gem.add_development_dependency 'simplecov', '0.21.2'
38
+ gem.add_development_dependency 'yard', '0.9.27'
39
39
  gem.add_development_dependency 'yardstick', '0.9.9'
40
40
  end
@@ -3,7 +3,7 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe MyClass do
6
- subject(:model) { klass.new(attributes) }
6
+ subject(:model) { klass.new(**attributes) }
7
7
 
8
8
  let(:klass) { described_class }
9
9
  let(:name) { 'name' }
@@ -25,7 +25,17 @@ describe Sinclair::Configurable do
25
25
  .to eq(5555)
26
26
  end
27
27
 
28
- context 'when #rest_config is called' do
28
+ it 'enables options to be returned' do
29
+ expect(MyConfigurable.as_options.host)
30
+ .to eq('interstella.art')
31
+ end
32
+
33
+ it 'enables custom options to be returned' do
34
+ expect(MyConfigurable.as_options(host: 'other').host)
35
+ .to eq('other')
36
+ end
37
+
38
+ context 'when #reset_config is called' do
29
39
  before do
30
40
  MyConfigurable.reset_config
31
41
  end
@@ -24,5 +24,32 @@ describe Sinclair::Config do
24
24
  .to eq('{"password":null,"username":"bob"}')
25
25
  end
26
26
  end
27
+
28
+ describe '#options' do
29
+ subject(:config) { configurable.config }
30
+
31
+ let(:configurable) { LoginConfigurable }
32
+
33
+ before do
34
+ LoginConfigurable.configure do |conf|
35
+ conf.username :some_username
36
+ conf.password :some_password
37
+ end
38
+ end
39
+
40
+ it 'returns options with correct values' do
41
+ expect(config.as_options.username).to eq(:some_username)
42
+ expect(config.as_options.password).to eq(:some_password)
43
+ end
44
+
45
+ context 'when merging with given attributes' do
46
+ subject(:options) { config.as_options(password: :correct_password) }
47
+
48
+ it 'returns options with custom values' do
49
+ expect(options.username).to eq(:some_username)
50
+ expect(options.password).to eq(:correct_password)
51
+ end
52
+ end
53
+ end
27
54
  end
28
55
  end
@@ -16,38 +16,6 @@ describe Sinclair::ConfigClass do
16
16
  end
17
17
 
18
18
  describe '.add_configs' do
19
- let(:setter_block) do
20
- proc { |value| config.instance_variable_set(:@name, value) }
21
- end
22
-
23
- it_behaves_like 'a config methods builder adding config' do
24
- let(:code_block) { proc { klass.add_configs(:name) } }
25
-
26
- it 'sets nil value by default' do
27
- code_block.call
28
- expect(config.name).to be_nil
29
- end
30
-
31
- it 'adds attributes to class' do
32
- expect(&code_block).to change(klass, :config_attributes)
33
- .from([]).to(%i[name])
34
- end
35
- end
36
-
37
- context 'when giving defaults' do
38
- it_behaves_like 'a config methods builder adding config' do
39
- let(:code_block) { proc { klass.add_configs(name: 'Bob') } }
40
-
41
- it 'sets default value' do
42
- code_block.call
43
- expect(config.name).to eq('Bob')
44
- end
45
-
46
- it 'adds attributes to class' do
47
- expect(&code_block).to change(klass, :config_attributes)
48
- .from([]).to(%i[name])
49
- end
50
- end
51
- end
19
+ it_behaves_like 'a config class with .add_configs method'
52
20
  end
53
21
  end