sinclair 1.6.2 → 1.6.7

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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +37 -2
  3. data/Dockerfile +2 -2
  4. data/README.md +6 -2
  5. data/config/check_specs.yml +3 -0
  6. data/config/yardstick.yml +8 -1
  7. data/lib/sinclair/matchers.rb +37 -10
  8. data/lib/sinclair/matchers/add_class_method.rb +16 -13
  9. data/lib/sinclair/matchers/add_class_method_to.rb +9 -23
  10. data/lib/sinclair/matchers/add_instance_method.rb +16 -18
  11. data/lib/sinclair/matchers/add_instance_method_to.rb +12 -16
  12. data/lib/sinclair/matchers/add_method.rb +13 -30
  13. data/lib/sinclair/matchers/add_method_to.rb +4 -56
  14. data/lib/sinclair/matchers/base.rb +45 -0
  15. data/lib/sinclair/matchers/change_class_method.rb +42 -0
  16. data/lib/sinclair/matchers/change_class_method_on.rb +64 -0
  17. data/lib/sinclair/matchers/change_instance_method.rb +42 -0
  18. data/lib/sinclair/matchers/change_instance_method_on.rb +98 -0
  19. data/lib/sinclair/matchers/change_method_on.rb +25 -0
  20. data/lib/sinclair/matchers/method_to.rb +82 -0
  21. data/lib/sinclair/options.rb +47 -46
  22. data/lib/sinclair/options/builder.rb +1 -1
  23. data/lib/sinclair/options/class_methods.rb +99 -0
  24. data/lib/sinclair/version.rb +1 -1
  25. data/spec/integration/readme/sinclair/options_spec.rb +8 -0
  26. data/spec/integration/yard/sinclair/options_parser_spec.rb +9 -0
  27. data/spec/integration/yard/sinclair/options_spec.rb +17 -6
  28. data/spec/lib/sinclair/matchers/add_class_method_to_spec.rb +40 -16
  29. data/spec/lib/sinclair/matchers/add_instance_method_to_spec.rb +36 -12
  30. data/spec/lib/sinclair/matchers/change_class_method_on_spec.rb +138 -0
  31. data/spec/lib/sinclair/matchers/change_class_method_spec.rb +38 -0
  32. data/spec/lib/sinclair/matchers/change_instance_method_on_spec.rb +149 -0
  33. data/spec/lib/sinclair/matchers/change_instance_method_spec.rb +38 -0
  34. data/spec/lib/sinclair/matchers_spec.rb +30 -0
  35. data/spec/lib/sinclair/options/builder_spec.rb +16 -8
  36. data/spec/lib/sinclair/options/class_methods_spec.rb +255 -0
  37. data/spec/lib/sinclair/options_spec.rb +90 -78
  38. data/spec/support/models/builder_options.rb +7 -0
  39. data/spec/support/models/open_options.rb +7 -0
  40. metadata +17 -2
@@ -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
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'set'
4
+
3
5
  class Sinclair
4
6
  # @api public
5
7
  # @author Darthjee
@@ -18,52 +20,10 @@ class Sinclair
18
20
  # options.port # returns 8080
19
21
  # options.protocol # returns 'https'
20
22
  class Options
21
- autoload :Builder, 'sinclair/options/builder'
22
-
23
- class << self
24
- # @api private
25
- # @private
26
- #
27
- # Options allowed when initializing options
28
- #
29
- # @return [Array<Symbol>]
30
- def allowed_options
31
- @allowed_options ||= (superclass.try(:allowed_options).dup || [])
32
- end
33
-
34
- # @api private
35
- # @private
36
- #
37
- # returns invalid options
38
- #
39
- # @return [Array<Symbol>]
40
- def invalid_options_in(names)
41
- names.map(&:to_sym) - allowed_options
42
- end
43
-
44
- private
23
+ autoload :Builder, 'sinclair/options/builder'
24
+ autoload :ClassMethods, 'sinclair/options/class_methods'
45
25
 
46
- # @api public
47
- # @!visibility public
48
- #
49
- # Add available options
50
- #
51
- # @example (see Options)
52
- #
53
- # @return (see Sinclair#build)
54
- #
55
- # @overload with_options(*options)
56
- # @param options [Array<Symbol>] list of accepted
57
- # options
58
- # @overload with_options(*options, **defaults)
59
- # @param options [Array<Symbol>] list of accepted
60
- # options
61
- # @param defaults [Hash<Symbol,Object>] default options
62
- # hash
63
- def with_options(*options)
64
- Builder.new(self, *options).build
65
- end
66
- end
26
+ extend ClassMethods
67
27
 
68
28
  # @param options [Hash] hash with options (see {.options}, {.with_options})
69
29
  # @example (see Options)
@@ -75,8 +35,47 @@ class Sinclair
75
35
  end
76
36
  end
77
37
 
38
+ # Returns a hash with the current options
39
+ #
40
+ # @return [Hash]
41
+ #
42
+ # @example
43
+ # class ConnectionOptions < Sinclair::Options
44
+ # with_options :timeout, :retries, port: 443, protocol: 'https'
45
+ # end
46
+ #
47
+ # options = ConnectionOptions.new(retries: 10, port: 8080)
48
+ #
49
+ # options.to_h # returns
50
+ # # {
51
+ # # port: 8080,
52
+ # # retries: 10,
53
+ # # timeout: nil,
54
+ # # protocol: 'https'
55
+ # # }
56
+ def to_h
57
+ allowed_options.inject({}) do |hash, option|
58
+ hash.merge(option => public_send(option))
59
+ end
60
+ end
61
+
62
+ # returns if other equals to self
63
+ #
64
+ # @param other [Object] object to be compared
65
+ #
66
+ # @return [TrueClass,FalseClass]
67
+ def ==(other)
68
+ return false unless self.class == other.class
69
+
70
+ allowed_options.all? do |name|
71
+ public_send(name) == other.public_send(name)
72
+ end
73
+ end
74
+
78
75
  private
79
76
 
77
+ delegate :allowed_options, :skip_validation?, :invalid_options_in, to: :class
78
+
80
79
  # @private
81
80
  # @api private
82
81
  #
@@ -86,7 +85,9 @@ class Sinclair
86
85
  #
87
86
  # @return [NilClass]
88
87
  def check_options(options)
89
- invalid_keys = self.class.invalid_options_in(options.keys)
88
+ return if skip_validation?
89
+
90
+ invalid_keys = invalid_options_in(options.keys)
90
91
 
91
92
  return if invalid_keys.empty?
92
93
 
@@ -57,7 +57,7 @@ class Sinclair
57
57
  def add_all_methods
58
58
  attributes.each do |option, value|
59
59
  add_method(option, cached: :full) { value }
60
- klass.allowed_options.push(option.to_sym)
60
+ klass.allow(option)
61
61
  end
62
62
  end
63
63
  end
@@ -0,0 +1,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+
5
+ class Sinclair
6
+ class Options
7
+ # Class Methods for {Sinclai::Options}
8
+ module ClassMethods
9
+ # @api private
10
+ #
11
+ # returns invalid options
12
+ #
13
+ # @return [Array<Symbol>]
14
+ def invalid_options_in(names)
15
+ names.map(&:to_sym) - allowed_options.to_a
16
+ end
17
+
18
+ # @api private
19
+ #
20
+ # Allow new option
21
+ #
22
+ # This does not create the method
23
+ #
24
+ # @param name [String,Symbol] options to be allowed
25
+ #
26
+ # @return [Set<Symbol>]
27
+ def allow(name)
28
+ allowed_options << name.to_sym
29
+ end
30
+
31
+ # @api private
32
+ # @private
33
+ #
34
+ # Options allowed when initializing options
35
+ #
36
+ # @return [Set<Symbol>]
37
+ def allowed_options
38
+ @allowed_options ||= superclass.try(:allowed_options).dup || Set.new
39
+ end
40
+
41
+ # @api private
42
+ #
43
+ # checks if class skips initialization validation
44
+ #
45
+ # @return [TrueClass,FalseClass]
46
+ def skip_validation?
47
+ @skip_validation ||= superclass.try(:skip_validation?) || false
48
+ end
49
+
50
+ private
51
+
52
+ # @api public
53
+ # @!visibility public
54
+ #
55
+ # Add available options
56
+ #
57
+ # @example (see Options)
58
+ #
59
+ # @return (see Sinclair#build)
60
+ #
61
+ # @overload with_options(*options)
62
+ # @param options [Array<Symbol>] list of accepted
63
+ # options
64
+ # @overload with_options(*options, **defaults)
65
+ # @param options [Array<Symbol>] list of accepted
66
+ # options
67
+ # @param defaults [Hash<Symbol,Object>] default options
68
+ # hash
69
+ def with_options(*options)
70
+ Builder.new(self, *options).build
71
+ end
72
+
73
+ # @api public
74
+ # @!visibility public
75
+ #
76
+ # Changes class to skip attributes validation
77
+ #
78
+ # when initializing options, options
79
+ # will accept any arguments when validation
80
+ # is skipped
81
+ #
82
+ # @return [TrueClass]
83
+ #
84
+ # @example
85
+ # class BuilderOptions < Sinclair::Options
86
+ # with_options :name
87
+ #
88
+ # skip_validation
89
+ # end
90
+ # options = BuilderOptions.new(name: 'Joe', age: 10)
91
+ #
92
+ # options.name # returns 'Joe'
93
+ # options.try(:age) # returns nil
94
+ def skip_validation
95
+ @skip_validation = true
96
+ end
97
+ end
98
+ end
99
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Sinclair
4
- VERSION = '1.6.2'
4
+ VERSION = '1.6.7'
5
5
  end
@@ -15,5 +15,13 @@ describe Sinclair::Options do
15
15
  expect(options.protocol).to eq('http')
16
16
  expect(options.port).to eq(443)
17
17
  end
18
+
19
+ context 'when initialized with invalid options' do
20
+ it do
21
+ expect do
22
+ ConnectionOptions.new(invalid: 10)
23
+ end.to raise_error(Sinclair::Exception::InvalidOptions)
24
+ end
25
+ end
18
26
  end
19
27
  end
@@ -13,5 +13,14 @@ describe Sinclair::OptionsParser do
13
13
  expect(model.the_method).to eq('The value is not 10 but 20')
14
14
  end
15
15
  end
16
+
17
+ describe '.skip_validation' do
18
+ it 'accepts options' do
19
+ options = BuilderOptions.new(name: 'Joe', age: 10)
20
+
21
+ expect(options.name).to eq('Joe')
22
+ expect(options.try(:age)).to be_nil
23
+ end
24
+ end
16
25
  end
17
26
  end
@@ -4,13 +4,24 @@ require 'spec_helper'
4
4
 
5
5
  describe Sinclair::Options do
6
6
  describe 'yard' do
7
- it 'creates options object' do
8
- options = ConnectionOptions.new(retries: 10, port: 8080)
7
+ describe 'usage' do
8
+ it 'creates options object' do
9
+ options = ConnectionOptions.new(retries: 10, port: 8080)
9
10
 
10
- expect(options.timeout).to be_nil
11
- expect(options.retries).to eq(10)
12
- expect(options.port).to eq(8080)
13
- expect(options.protocol).to eq('https')
11
+ expect(options.timeout).to be_nil
12
+ expect(options.retries).to eq(10)
13
+ expect(options.port).to eq(8080)
14
+ expect(options.protocol).to eq('https')
15
+ end
16
+ end
17
+
18
+ describe '#to_h' do
19
+ it 'returns options hash' do
20
+ options = ConnectionOptions.new(retries: 10, port: 8080)
21
+
22
+ expect(options.to_h)
23
+ .to eq({ port: 8080, retries: 10, timeout: nil, protocol: 'https' })
24
+ end
14
25
  end
15
26
  end
16
27
  end
@@ -13,22 +13,46 @@ describe Sinclair::Matchers::AddClassMethodTo do
13
13
  proc { klass.send(:define_singleton_method, method) {} }
14
14
  end
15
15
 
16
- context 'when a method is added' do
17
- it { expect(matcher).to be_matches(event_proc) }
18
- end
16
+ context 'when class does not have the method yet' do
17
+ context 'when a method is added' do
18
+ it { expect(matcher).to be_matches(event_proc) }
19
+ end
19
20
 
20
- context 'when a method is not added' do
21
- let(:event_proc) { proc {} }
21
+ context 'when a method is not added' do
22
+ let(:event_proc) { proc {} }
22
23
 
23
- it { expect(matcher).not_to be_matches(event_proc) }
24
- end
24
+ it { expect(matcher).not_to be_matches(event_proc) }
25
+ end
26
+
27
+ context 'when the wrong method is added' do
28
+ let(:event_proc) do
29
+ proc { klass.send(:define_singleton_method, :another_method) {} }
30
+ end
31
+
32
+ it { expect(matcher).not_to be_matches(event_proc) }
33
+ end
25
34
 
26
- context 'when the wrong method is added' do
27
- let(:event_proc) do
28
- proc { klass.send(:define_singleton_method, :another_method) {} }
35
+ context 'when method already existed' do
36
+ before { event_proc.call }
37
+
38
+ it { expect(matcher).not_to be_matches(event_proc) }
29
39
  end
30
40
 
31
- it { expect(matcher).not_to be_matches(event_proc) }
41
+ context 'when method is added to instances' do
42
+ let(:event_proc) do
43
+ proc { klass.send(:define_method, method) {} }
44
+ end
45
+
46
+ it { expect(matcher).not_to be_matches(event_proc) }
47
+ end
48
+ end
49
+
50
+ context 'when class already has the method' do
51
+ before { klass.send(:define_singleton_method, method) {} }
52
+
53
+ context 'when a method is changed' do
54
+ it { expect(matcher).not_to be_matches(event_proc) }
55
+ end
32
56
  end
33
57
 
34
58
  context 'when a block is given' do
@@ -36,7 +60,7 @@ describe Sinclair::Matchers::AddClassMethodTo do
36
60
  expect { matcher.matches?(event_proc) { 1 } }
37
61
  .to raise_error(
38
62
  SyntaxError, 'Block not received by the `add_class_method_to` matcher. ' \
39
- 'Perhaps you want to use `{ ... }` instead of do/end?'
63
+ 'Perhaps you want to use `{ ... }` instead of do/end?'
40
64
  )
41
65
  end
42
66
  end
@@ -45,7 +69,7 @@ describe Sinclair::Matchers::AddClassMethodTo do
45
69
  describe '#failure_message_for_should' do
46
70
  it 'returns information on the instance class and method' do
47
71
  expect(matcher.failure_message_for_should)
48
- .to eq("expected class_method '#{method}' to be added to #{klass} but it didn't")
72
+ .to eq("expected class method '#{method}' to be added to #{klass} but it didn't")
49
73
  end
50
74
 
51
75
  context 'when method already exited' do
@@ -56,7 +80,7 @@ describe Sinclair::Matchers::AddClassMethodTo do
56
80
 
57
81
  it 'returns information on the instance class and method' do
58
82
  expect(matcher.failure_message_for_should)
59
- .to eq("expected class_method '#{method}' to be added to #{klass} but it already existed")
83
+ .to eq("expected class method '#{method}' to be added to #{klass} but it already existed")
60
84
  end
61
85
  end
62
86
  end
@@ -64,14 +88,14 @@ describe Sinclair::Matchers::AddClassMethodTo do
64
88
  describe '#failure_message_for_should_not' do
65
89
  it 'returns information on the instance class and method' do
66
90
  expect(matcher.failure_message_for_should_not)
67
- .to eq("expected class_method '#{method}' not to be added to #{klass} but it was")
91
+ .to eq("expected class method '#{method}' not to be added to #{klass} but it was")
68
92
  end
69
93
  end
70
94
 
71
95
  describe 'description' do
72
96
  it 'returns information on the instance class and method' do
73
97
  expect(matcher.description)
74
- .to eq("add method class_method '#{method}' to #{klass}")
98
+ .to eq("add class method '#{method}' to #{klass}")
75
99
  end
76
100
  end
77
101
  end