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.
- checksums.yaml +4 -4
- data/.circleci/config.yml +37 -2
- data/Dockerfile +2 -2
- data/README.md +6 -2
- data/config/check_specs.yml +3 -0
- data/config/yardstick.yml +8 -1
- data/lib/sinclair/matchers.rb +37 -10
- data/lib/sinclair/matchers/add_class_method.rb +16 -13
- data/lib/sinclair/matchers/add_class_method_to.rb +9 -23
- data/lib/sinclair/matchers/add_instance_method.rb +16 -18
- data/lib/sinclair/matchers/add_instance_method_to.rb +12 -16
- data/lib/sinclair/matchers/add_method.rb +13 -30
- data/lib/sinclair/matchers/add_method_to.rb +4 -56
- data/lib/sinclair/matchers/base.rb +45 -0
- data/lib/sinclair/matchers/change_class_method.rb +42 -0
- data/lib/sinclair/matchers/change_class_method_on.rb +64 -0
- data/lib/sinclair/matchers/change_instance_method.rb +42 -0
- data/lib/sinclair/matchers/change_instance_method_on.rb +98 -0
- data/lib/sinclair/matchers/change_method_on.rb +25 -0
- data/lib/sinclair/matchers/method_to.rb +82 -0
- data/lib/sinclair/options.rb +47 -46
- data/lib/sinclair/options/builder.rb +1 -1
- data/lib/sinclair/options/class_methods.rb +99 -0
- data/lib/sinclair/version.rb +1 -1
- data/spec/integration/readme/sinclair/options_spec.rb +8 -0
- data/spec/integration/yard/sinclair/options_parser_spec.rb +9 -0
- data/spec/integration/yard/sinclair/options_spec.rb +17 -6
- data/spec/lib/sinclair/matchers/add_class_method_to_spec.rb +40 -16
- data/spec/lib/sinclair/matchers/add_instance_method_to_spec.rb +36 -12
- data/spec/lib/sinclair/matchers/change_class_method_on_spec.rb +138 -0
- data/spec/lib/sinclair/matchers/change_class_method_spec.rb +38 -0
- data/spec/lib/sinclair/matchers/change_instance_method_on_spec.rb +149 -0
- data/spec/lib/sinclair/matchers/change_instance_method_spec.rb +38 -0
- data/spec/lib/sinclair/matchers_spec.rb +30 -0
- data/spec/lib/sinclair/options/builder_spec.rb +16 -8
- data/spec/lib/sinclair/options/class_methods_spec.rb +255 -0
- data/spec/lib/sinclair/options_spec.rb +90 -78
- data/spec/support/models/builder_options.rb +7 -0
- data/spec/support/models/open_options.rb +7 -0
- 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
|
data/lib/sinclair/options.rb
CHANGED
@@ -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,
|
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
|
-
|
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
|
-
|
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
|
|
@@ -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
|
data/lib/sinclair/version.rb
CHANGED
@@ -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
|
-
|
8
|
-
|
7
|
+
describe 'usage' do
|
8
|
+
it 'creates options object' do
|
9
|
+
options = ConnectionOptions.new(retries: 10, port: 8080)
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
17
|
-
|
18
|
-
|
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
|
-
|
21
|
-
|
21
|
+
context 'when a method is not added' do
|
22
|
+
let(:event_proc) { proc {} }
|
22
23
|
|
23
|
-
|
24
|
-
|
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
|
-
|
27
|
-
|
28
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
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
|
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
|
98
|
+
.to eq("add class method '#{method}' to #{klass}")
|
75
99
|
end
|
76
100
|
end
|
77
101
|
end
|