sinclair 1.6.6 → 1.6.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/check_specs.yml +3 -0
- data/config/yardstick.yml +7 -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/version.rb +1 -1
- 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
- metadata +13 -2
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Sinclair
|
4
|
+
module Matchers
|
5
|
+
# @abstract
|
6
|
+
# @api private
|
7
|
+
#
|
8
|
+
# Base class for all matchers
|
9
|
+
class Base < RSpec::Matchers::BuiltIn::BaseMatcher
|
10
|
+
# @param method_name [String,Symbol] the method, to be checked, name
|
11
|
+
def initialize(method_name)
|
12
|
+
@method_name = method_name.to_sym
|
13
|
+
end
|
14
|
+
|
15
|
+
# definition needed for block matchers
|
16
|
+
#
|
17
|
+
# @return [Boolean]
|
18
|
+
def supports_block_expectations?
|
19
|
+
true
|
20
|
+
end
|
21
|
+
|
22
|
+
# Checkes if another instnce is equal self
|
23
|
+
#
|
24
|
+
# @return [Boolean]
|
25
|
+
def equal?(other)
|
26
|
+
return unless other.class == self.class
|
27
|
+
|
28
|
+
other.method_name == method_name &&
|
29
|
+
other.try(:klass) == try(:klass)
|
30
|
+
end
|
31
|
+
|
32
|
+
alias == equal?
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
# @method method_name
|
37
|
+
# @private
|
38
|
+
#
|
39
|
+
# The method, to be checked, name
|
40
|
+
#
|
41
|
+
# @return [Symbol]
|
42
|
+
attr_reader :method_name
|
43
|
+
end
|
44
|
+
end
|
45
|
+
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::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 [Class] klass
|
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
|
data/lib/sinclair/version.rb
CHANGED
@@ -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
|