transpec 0.2.6 → 1.0.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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +10 -0
- data/README.md +111 -56
- data/README.md.erb +117 -62
- data/lib/transpec/ast/node.rb +41 -0
- data/lib/transpec/base_rewriter.rb +55 -0
- data/lib/transpec/cli.rb +43 -153
- data/lib/transpec/configuration.rb +13 -9
- data/lib/transpec/{rewriter.rb → converter.rb} +44 -71
- data/lib/transpec/dynamic_analyzer/rewriter.rb +94 -0
- data/lib/transpec/dynamic_analyzer/runtime_data.rb +27 -0
- data/lib/transpec/dynamic_analyzer.rb +166 -0
- data/lib/transpec/file_finder.rb +53 -0
- data/lib/transpec/option_parser.rb +166 -0
- data/lib/transpec/{context.rb → static_context_inspector.rb} +2 -2
- data/lib/transpec/syntax/be_close.rb +7 -9
- data/lib/transpec/syntax/double.rb +6 -10
- data/lib/transpec/syntax/expect.rb +35 -0
- data/lib/transpec/syntax/have.rb +195 -0
- data/lib/transpec/syntax/method_stub.rb +22 -27
- data/lib/transpec/syntax/mixin/allow_no_message.rb +73 -0
- data/lib/transpec/syntax/mixin/any_instance.rb +22 -0
- data/lib/transpec/syntax/mixin/expectizable.rb +26 -0
- data/lib/transpec/syntax/mixin/have_matcher.rb +23 -0
- data/lib/transpec/syntax/mixin/monkey_patch.rb +37 -0
- data/lib/transpec/syntax/mixin/send.rb +109 -0
- data/lib/transpec/syntax/{matcher.rb → operator_matcher.rb} +27 -14
- data/lib/transpec/syntax/raise_error.rb +6 -10
- data/lib/transpec/syntax/rspec_configure.rb +29 -28
- data/lib/transpec/syntax/should.rb +45 -15
- data/lib/transpec/syntax/should_receive.rb +44 -16
- data/lib/transpec/syntax.rb +29 -21
- data/lib/transpec/util.rb +12 -2
- data/lib/transpec/version.rb +3 -3
- data/spec/spec_helper.rb +8 -6
- data/spec/support/cache_helper.rb +50 -0
- data/spec/support/shared_context.rb +49 -1
- data/spec/transpec/ast/node_spec.rb +65 -0
- data/spec/transpec/cli_spec.rb +33 -242
- data/spec/transpec/commit_message_spec.rb +2 -2
- data/spec/transpec/configuration_spec.rb +12 -8
- data/spec/transpec/{rewriter_spec.rb → converter_spec.rb} +198 -148
- data/spec/transpec/dynamic_analyzer/rewriter_spec.rb +183 -0
- data/spec/transpec/dynamic_analyzer_spec.rb +164 -0
- data/spec/transpec/file_finder_spec.rb +118 -0
- data/spec/transpec/option_parser_spec.rb +185 -0
- data/spec/transpec/{context_spec.rb → static_context_inspector_spec.rb} +27 -12
- data/spec/transpec/syntax/be_close_spec.rb +8 -4
- data/spec/transpec/syntax/double_spec.rb +105 -12
- data/spec/transpec/syntax/expect_spec.rb +83 -0
- data/spec/transpec/syntax/have_spec.rb +599 -0
- data/spec/transpec/syntax/method_stub_spec.rb +276 -115
- data/spec/transpec/syntax/{matcher_spec.rb → operator_matcher_spec.rb} +277 -98
- data/spec/transpec/syntax/raise_error_spec.rb +92 -46
- data/spec/transpec/syntax/should_receive_spec.rb +298 -92
- data/spec/transpec/syntax/should_spec.rb +230 -44
- data/spec/transpec/util_spec.rb +2 -9
- data/tasks/lib/transpec_demo.rb +1 -1
- data/tasks/lib/transpec_test.rb +5 -7
- data/tasks/test.rake +5 -1
- data/transpec.gemspec +1 -1
- metadata +46 -22
- data/lib/transpec/syntax/able_to_allow_no_message.rb +0 -73
- data/lib/transpec/syntax/able_to_target_any_instance.rb +0 -24
- data/lib/transpec/syntax/expectizable.rb +0 -27
- data/lib/transpec/syntax/send_node_syntax.rb +0 -57
@@ -1,28 +1,39 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
3
|
require 'transpec/syntax'
|
4
|
-
require 'transpec/syntax/
|
5
|
-
require 'transpec/syntax/
|
4
|
+
require 'transpec/syntax/mixin/send'
|
5
|
+
require 'transpec/syntax/mixin/monkey_patch'
|
6
|
+
require 'transpec/syntax/mixin/allow_no_message'
|
7
|
+
require 'transpec/syntax/mixin/any_instance'
|
6
8
|
require 'transpec/util'
|
7
9
|
require 'English'
|
8
10
|
|
9
11
|
module Transpec
|
10
12
|
class Syntax
|
11
13
|
class MethodStub < Syntax
|
12
|
-
include
|
14
|
+
include Mixin::Send, Mixin::MonkeyPatch, Mixin::AllowNoMessage, Mixin::AnyInstance, Util
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
16
|
+
def self.target_method?(receiver_node, method_name)
|
17
|
+
!receiver_node.nil? && [:stub, :unstub, :stub!, :unstub!].include?(method_name)
|
18
|
+
end
|
19
|
+
|
20
|
+
def register_request_for_dynamic_analysis(rewriter)
|
21
|
+
register_request_of_syntax_availability_inspection(
|
22
|
+
rewriter,
|
23
|
+
:allow_to_receive_available?,
|
24
|
+
[:allow, :receive]
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
def allow_to_receive_available?
|
29
|
+
check_syntax_availability(__method__)
|
30
|
+
end
|
18
31
|
|
19
32
|
def allowize!
|
20
33
|
# There's no way of unstubbing in #allow syntax.
|
21
34
|
return unless [:stub, :stub!].include?(method_name)
|
22
35
|
|
23
|
-
|
24
|
-
|
25
|
-
unless context.allow_to_receive_available?
|
36
|
+
unless allow_to_receive_available?
|
26
37
|
fail InvalidContextError.new(selector_range, "##{method_name}", '#allow')
|
27
38
|
end
|
28
39
|
|
@@ -35,34 +46,18 @@ module Transpec
|
|
35
46
|
end
|
36
47
|
|
37
48
|
register_record(:allow)
|
38
|
-
|
39
|
-
@allowized = true
|
40
49
|
end
|
41
50
|
|
42
|
-
def
|
51
|
+
def convert_deprecated_method!
|
43
52
|
return unless replacement_method_for_deprecated_method
|
44
53
|
|
45
|
-
fail 'Already allowized, cannot replace deprecated method.' if @allowized
|
46
|
-
|
47
54
|
replace(selector_range, replacement_method_for_deprecated_method)
|
48
55
|
|
49
56
|
register_record(:deprecated)
|
50
|
-
|
51
|
-
@replaced_deprecated_method = true
|
52
57
|
end
|
53
58
|
|
54
59
|
private
|
55
60
|
|
56
|
-
def self.target_receiver_node?(node)
|
57
|
-
return false if node.nil?
|
58
|
-
const_name = Util.const_name(node)
|
59
|
-
!CLASSES_DEFINING_OWN_STUB_METHOD.include?(const_name)
|
60
|
-
end
|
61
|
-
|
62
|
-
def self.target_method_names
|
63
|
-
[:stub, :unstub, :stub!, :unstub!]
|
64
|
-
end
|
65
|
-
|
66
61
|
def build_allow_expressions_from_hash_node(hash_node)
|
67
62
|
expressions = []
|
68
63
|
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Transpec
|
4
|
+
class Syntax
|
5
|
+
module Mixin
|
6
|
+
module AllowNoMessage
|
7
|
+
include ::AST::Sexp
|
8
|
+
|
9
|
+
def allow_no_message?
|
10
|
+
any_number_of_times? || at_least_zero?
|
11
|
+
end
|
12
|
+
|
13
|
+
def remove_allowance_for_no_message!
|
14
|
+
remove_any_number_of_times!
|
15
|
+
remove_at_least_zero!
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def any_number_of_times?
|
21
|
+
!any_number_of_times_node.nil?
|
22
|
+
end
|
23
|
+
|
24
|
+
def at_least_zero?
|
25
|
+
!at_least_zero_node.nil?
|
26
|
+
end
|
27
|
+
|
28
|
+
def remove_any_number_of_times!
|
29
|
+
return unless any_number_of_times?
|
30
|
+
remove_dot_and_method!(any_number_of_times_node)
|
31
|
+
end
|
32
|
+
|
33
|
+
def remove_at_least_zero!
|
34
|
+
return unless at_least_zero?
|
35
|
+
remove_dot_and_method!(at_least_zero_node)
|
36
|
+
end
|
37
|
+
|
38
|
+
def remove_dot_and_method!(send_node)
|
39
|
+
map = send_node.loc
|
40
|
+
dot_and_method_range = map.dot.join(map.expression.end)
|
41
|
+
remove(dot_and_method_range)
|
42
|
+
end
|
43
|
+
|
44
|
+
def any_number_of_times_node
|
45
|
+
each_following_chained_method_node do |chained_node|
|
46
|
+
method_name = chained_node.children[1]
|
47
|
+
return chained_node if method_name == :any_number_of_times
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def at_least_zero_node
|
52
|
+
each_following_chained_method_node do |chained_node|
|
53
|
+
_, method_name, arg_node = *chained_node
|
54
|
+
next unless method_name == :at_least
|
55
|
+
return chained_node if arg_node == s(:int, 0)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def each_following_chained_method_node
|
60
|
+
return to_enum(__method__) unless block_given?
|
61
|
+
|
62
|
+
@ancestor_nodes.reverse.reduce(@node) do |child_node, parent_node|
|
63
|
+
return unless [:send, :block].include?(parent_node.type)
|
64
|
+
return unless parent_node.children.first == child_node
|
65
|
+
yield parent_node, child_node
|
66
|
+
parent_node
|
67
|
+
end
|
68
|
+
nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Transpec
|
4
|
+
class Syntax
|
5
|
+
module Mixin
|
6
|
+
module AnyInstance
|
7
|
+
def any_instance?
|
8
|
+
!class_node_of_any_instance.nil?
|
9
|
+
end
|
10
|
+
|
11
|
+
def class_node_of_any_instance
|
12
|
+
return nil unless subject_node.type == :send
|
13
|
+
return nil unless subject_node.children.count == 2
|
14
|
+
receiver_node, method_name = *subject_node
|
15
|
+
return nil unless method_name == :any_instance
|
16
|
+
return nil unless receiver_node.type == :const
|
17
|
+
receiver_node
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'transpec/util'
|
4
|
+
|
5
|
+
module Transpec
|
6
|
+
class Syntax
|
7
|
+
module Mixin
|
8
|
+
module Expectizable
|
9
|
+
def wrap_subject_in_expect!
|
10
|
+
wrap_subject_with_method!('expect')
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def wrap_subject_with_method!(method)
|
16
|
+
if Util.in_parentheses?(subject_node)
|
17
|
+
insert_before(subject_range, method)
|
18
|
+
else
|
19
|
+
insert_before(subject_range, "#{method}(")
|
20
|
+
insert_after(subject_range, ')')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'transpec/syntax/have'
|
4
|
+
|
5
|
+
module Transpec
|
6
|
+
class Syntax
|
7
|
+
module Mixin
|
8
|
+
module HaveMatcher
|
9
|
+
def have_matcher
|
10
|
+
return @have_matcher if instance_variable_defined?(:@have_matcher)
|
11
|
+
|
12
|
+
@have_matcher ||= begin
|
13
|
+
if Have.target_node?(matcher_node, @runtime_data)
|
14
|
+
Have.new(matcher_node, self, @source_rewriter, @runtime_data, @report)
|
15
|
+
else
|
16
|
+
nil
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Transpec
|
4
|
+
class Syntax
|
5
|
+
module Mixin
|
6
|
+
module MonkeyPatch
|
7
|
+
def register_request_of_syntax_availability_inspection(rewriter, key, methods)
|
8
|
+
code = "self.class.name.start_with?('RSpec::')"
|
9
|
+
|
10
|
+
methods.each do |method|
|
11
|
+
code << " && respond_to?(#{method.inspect})"
|
12
|
+
end
|
13
|
+
|
14
|
+
rewriter.register_request(@node, key, code, :context)
|
15
|
+
end
|
16
|
+
|
17
|
+
def check_syntax_availability(key)
|
18
|
+
node_data = runtime_node_data(@node)
|
19
|
+
|
20
|
+
if node_data
|
21
|
+
node_data[key].result
|
22
|
+
else
|
23
|
+
static_context_inspector.send(key)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def subject_node
|
28
|
+
receiver_node
|
29
|
+
end
|
30
|
+
|
31
|
+
def subject_range
|
32
|
+
receiver_range
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Transpec
|
4
|
+
class Syntax
|
5
|
+
module Mixin
|
6
|
+
module Send
|
7
|
+
def self.included(klass)
|
8
|
+
klass.extend(ClassMethods)
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def register_request_for_dynamic_analysis(node, rewriter)
|
13
|
+
return unless target_node?(node)
|
14
|
+
|
15
|
+
receiver_node, method_name, *_ = *node
|
16
|
+
|
17
|
+
if receiver_node
|
18
|
+
target_node = receiver_node
|
19
|
+
target_object_type = :object
|
20
|
+
else
|
21
|
+
target_node = node
|
22
|
+
target_object_type = :context
|
23
|
+
end
|
24
|
+
|
25
|
+
key = source_location_key(method_name)
|
26
|
+
code = "method(#{method_name.inspect}).source_location"
|
27
|
+
rewriter.register_request(target_node, key, code, target_object_type)
|
28
|
+
end
|
29
|
+
|
30
|
+
def target_node?(node, runtime_data = nil)
|
31
|
+
check_target_node_statically(node) && check_target_node_dynamically(node, runtime_data)
|
32
|
+
end
|
33
|
+
|
34
|
+
def target_method?(receiver_node, method_name)
|
35
|
+
false
|
36
|
+
end
|
37
|
+
|
38
|
+
def check_target_node_statically(node)
|
39
|
+
return false unless node && node.type == :send
|
40
|
+
receiver_node, method_name, *_ = *node
|
41
|
+
target_method?(receiver_node, method_name)
|
42
|
+
end
|
43
|
+
|
44
|
+
def check_target_node_dynamically(node, runtime_data)
|
45
|
+
return true unless runtime_data
|
46
|
+
|
47
|
+
receiver_node, method_name, *_ = *node
|
48
|
+
target_node = receiver_node ? receiver_node : node
|
49
|
+
|
50
|
+
return true unless (node_data = runtime_data[target_node])
|
51
|
+
return true unless (eval_data = node_data[source_location_key(method_name)])
|
52
|
+
return true unless (source_location = eval_data.result)
|
53
|
+
|
54
|
+
file_path = source_location.first
|
55
|
+
!file_path.match(%r{/gems/rspec\-[^/]+/lib/rspec/}).nil?
|
56
|
+
end
|
57
|
+
|
58
|
+
def source_location_key(method_name)
|
59
|
+
"#{method_name}_source_location".to_sym
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def receiver_node
|
64
|
+
@node.children[0]
|
65
|
+
end
|
66
|
+
|
67
|
+
def method_name
|
68
|
+
@node.children[1]
|
69
|
+
end
|
70
|
+
|
71
|
+
def arg_node
|
72
|
+
@node.children[2]
|
73
|
+
end
|
74
|
+
|
75
|
+
def arg_nodes
|
76
|
+
@node.children[2..-1]
|
77
|
+
end
|
78
|
+
|
79
|
+
def selector_range
|
80
|
+
@node.loc.selector
|
81
|
+
end
|
82
|
+
|
83
|
+
def receiver_range
|
84
|
+
receiver_node.loc.expression
|
85
|
+
end
|
86
|
+
|
87
|
+
def arg_range
|
88
|
+
arg_node.loc.expression
|
89
|
+
end
|
90
|
+
|
91
|
+
def parentheses_range
|
92
|
+
selector_range.end.join(expression_range.end)
|
93
|
+
end
|
94
|
+
|
95
|
+
def range_in_between_receiver_and_selector
|
96
|
+
receiver_range.end.join(selector_range.begin)
|
97
|
+
end
|
98
|
+
|
99
|
+
def range_in_between_selector_and_arg
|
100
|
+
selector_range.end.join(arg_range.begin)
|
101
|
+
end
|
102
|
+
|
103
|
+
def range_after_arg
|
104
|
+
arg_range.end.join(expression_range.end)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -1,22 +1,34 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
3
|
require 'transpec/syntax'
|
4
|
-
require 'transpec/syntax/
|
4
|
+
require 'transpec/syntax/mixin/send'
|
5
5
|
require 'transpec/util'
|
6
6
|
|
7
7
|
module Transpec
|
8
8
|
class Syntax
|
9
|
-
class
|
10
|
-
include
|
9
|
+
class OperatorMatcher < Syntax
|
10
|
+
include Mixin::Send, Util, ::AST::Sexp
|
11
11
|
|
12
|
-
|
12
|
+
OPERATORS = [:==, :===, :<, :<=, :>, :>=, :=~].freeze
|
13
|
+
|
14
|
+
def self.standalone?
|
13
15
|
false
|
14
16
|
end
|
15
17
|
|
16
|
-
def
|
18
|
+
def self.target_method?(receiver_node, method_name)
|
19
|
+
!receiver_node.nil? && OPERATORS.include?(method_name)
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(node, source_rewriter = nil, runtime_data = nil, report = nil)
|
17
23
|
@node = node
|
18
24
|
@source_rewriter = source_rewriter
|
19
|
-
@
|
25
|
+
@runtime_data = runtime_data
|
26
|
+
@report = report || Report.new
|
27
|
+
end
|
28
|
+
|
29
|
+
def register_request_for_dynamic_analysis(rewriter)
|
30
|
+
return unless method_name == :=~
|
31
|
+
rewriter.register_request(arg_node, :arg_is_enumerable?, 'is_a?(Enumerable)')
|
20
32
|
end
|
21
33
|
|
22
34
|
def correct_operator!(parenthesize_arg = true)
|
@@ -31,7 +43,7 @@ module Transpec
|
|
31
43
|
end
|
32
44
|
|
33
45
|
def parenthesize!(always = true)
|
34
|
-
return if
|
46
|
+
return if contain_here_document?(arg_node)
|
35
47
|
|
36
48
|
left_of_arg_source = range_in_between_selector_and_arg.source
|
37
49
|
|
@@ -60,7 +72,7 @@ module Transpec
|
|
60
72
|
def convert_to_match!(parenthesize_arg)
|
61
73
|
handle_anterior_of_operator!
|
62
74
|
|
63
|
-
if
|
75
|
+
if arg_is_enumerable?
|
64
76
|
replace(selector_range, 'match_array')
|
65
77
|
else
|
66
78
|
replace(selector_range, 'match')
|
@@ -70,7 +82,7 @@ module Transpec
|
|
70
82
|
|
71
83
|
# Need to register record after all source rewrites are done
|
72
84
|
# to avoid false record when failed with overlapped rewrite.
|
73
|
-
if
|
85
|
+
if arg_is_enumerable?
|
74
86
|
register_record('=~ [1, 2]', 'match_array([1, 2])')
|
75
87
|
else
|
76
88
|
register_record('=~ /pattern/', 'match(/pattern/)')
|
@@ -85,6 +97,12 @@ module Transpec
|
|
85
97
|
end
|
86
98
|
end
|
87
99
|
|
100
|
+
def arg_is_enumerable?
|
101
|
+
return true if arg_node.type == :array
|
102
|
+
node_data = runtime_node_data(arg_node)
|
103
|
+
node_data && node_data[:arg_is_enumerable?].result
|
104
|
+
end
|
105
|
+
|
88
106
|
def parenthesize_single_line!(always)
|
89
107
|
if in_parentheses?(arg_node)
|
90
108
|
remove(range_in_between_selector_and_arg)
|
@@ -120,11 +138,6 @@ module Transpec
|
|
120
138
|
end
|
121
139
|
end
|
122
140
|
|
123
|
-
def argument_is_here_document?
|
124
|
-
here_document?(arg_node) ||
|
125
|
-
arg_node.each_descendent_node.any? { |n| here_document?(n) }
|
126
|
-
end
|
127
|
-
|
128
141
|
def register_record(original_syntax, converted_syntax)
|
129
142
|
original_syntax ||= "#{method_name} expected"
|
130
143
|
@report.records << Record.new(original_syntax, converted_syntax)
|
@@ -1,12 +1,16 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
3
|
require 'transpec/syntax'
|
4
|
-
require 'transpec/syntax/
|
4
|
+
require 'transpec/syntax/mixin/send'
|
5
5
|
|
6
6
|
module Transpec
|
7
7
|
class Syntax
|
8
8
|
class RaiseError < Syntax
|
9
|
-
include
|
9
|
+
include Mixin::Send
|
10
|
+
|
11
|
+
def self.target_method?(receiver_node, method_name)
|
12
|
+
receiver_node.nil? && method_name == :raise_error
|
13
|
+
end
|
10
14
|
|
11
15
|
def remove_error_specification_with_negative_expectation!
|
12
16
|
return if positive?
|
@@ -31,14 +35,6 @@ module Transpec
|
|
31
35
|
|
32
36
|
private
|
33
37
|
|
34
|
-
def self.target_receiver_node?(node)
|
35
|
-
node.nil?
|
36
|
-
end
|
37
|
-
|
38
|
-
def self.target_method_names
|
39
|
-
[:raise_error]
|
40
|
-
end
|
41
|
-
|
42
38
|
def register_record
|
43
39
|
original_syntax = 'expect { }.not_to raise_error('
|
44
40
|
|
@@ -2,11 +2,39 @@
|
|
2
2
|
|
3
3
|
require 'transpec/syntax'
|
4
4
|
require 'transpec/util'
|
5
|
-
require 'transpec/ast/scanner'
|
6
5
|
|
7
6
|
module Transpec
|
8
7
|
class Syntax
|
9
8
|
class RSpecConfigure < Syntax
|
9
|
+
extend Util
|
10
|
+
|
11
|
+
def self.target_node?(node, runtime_data = nil)
|
12
|
+
return false unless node && node.type == :block
|
13
|
+
send_node = node.children.first
|
14
|
+
receiver_node, method_name, *_ = *send_node
|
15
|
+
const_name(receiver_node) == 'RSpec' && method_name == :configure
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.add_framework_configuration(type, config_method_name)
|
19
|
+
class_eval <<-END
|
20
|
+
def #{type}_syntaxes
|
21
|
+
#{type}_framework_configuration.syntaxes
|
22
|
+
end
|
23
|
+
|
24
|
+
def modify_#{type}_syntaxes!(syntaxes)
|
25
|
+
#{type}_framework_configuration.modify_syntaxes!(syntaxes)
|
26
|
+
end
|
27
|
+
|
28
|
+
def #{type}_framework_configuration
|
29
|
+
@#{type}_framework_configuration ||=
|
30
|
+
FrameworkConfiguration.new(node, :#{config_method_name}, source_rewriter)
|
31
|
+
end
|
32
|
+
END
|
33
|
+
end
|
34
|
+
|
35
|
+
add_framework_configuration :expectation, :expect_with
|
36
|
+
add_framework_configuration :mock, :mock_with
|
37
|
+
|
10
38
|
class FrameworkConfiguration
|
11
39
|
include ::AST::Sexp
|
12
40
|
|
@@ -83,33 +111,6 @@ module Transpec
|
|
83
111
|
end
|
84
112
|
end
|
85
113
|
|
86
|
-
def self.target_node?(node)
|
87
|
-
return false unless node.type == :block
|
88
|
-
send_node = node.children.first
|
89
|
-
receiver_node, method_name, *_ = *send_node
|
90
|
-
Util.const_name(receiver_node) == 'RSpec' && method_name == :configure
|
91
|
-
end
|
92
|
-
|
93
|
-
def self.add_framework_configuration(type, config_method_name)
|
94
|
-
class_eval <<-END
|
95
|
-
def #{type}_syntaxes
|
96
|
-
#{type}_framework_configuration.syntaxes
|
97
|
-
end
|
98
|
-
|
99
|
-
def modify_#{type}_syntaxes!(syntaxes)
|
100
|
-
#{type}_framework_configuration.modify_syntaxes!(syntaxes)
|
101
|
-
end
|
102
|
-
|
103
|
-
def #{type}_framework_configuration
|
104
|
-
@#{type}_framework_configuration ||=
|
105
|
-
FrameworkConfiguration.new(node, :#{config_method_name}, source_rewriter)
|
106
|
-
end
|
107
|
-
END
|
108
|
-
end
|
109
|
-
|
110
|
-
add_framework_configuration :expectation, :expect_with
|
111
|
-
add_framework_configuration :mock, :mock_with
|
112
|
-
|
113
114
|
class UnknownSyntaxError < StandardError; end
|
114
115
|
end
|
115
116
|
end
|
@@ -1,21 +1,50 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
3
|
require 'transpec/syntax'
|
4
|
-
require 'transpec/syntax/
|
5
|
-
require 'transpec/syntax/
|
4
|
+
require 'transpec/syntax/mixin/send'
|
5
|
+
require 'transpec/syntax/mixin/monkey_patch'
|
6
|
+
require 'transpec/syntax/mixin/expectizable'
|
7
|
+
require 'transpec/syntax/mixin/have_matcher'
|
6
8
|
require 'transpec/util'
|
9
|
+
require 'transpec/syntax/operator_matcher'
|
7
10
|
|
8
11
|
module Transpec
|
9
12
|
class Syntax
|
10
13
|
class Should < Syntax
|
11
|
-
include Expectizable, Util
|
14
|
+
include Mixin::Send, Mixin::MonkeyPatch, Mixin::Expectizable, Mixin::HaveMatcher, Util
|
15
|
+
|
16
|
+
attr_reader :current_syntax_type
|
17
|
+
|
18
|
+
def self.target_method?(receiver_node, method_name)
|
19
|
+
!receiver_node.nil? && [:should, :should_not].include?(method_name)
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(node, ancestor_nodes, source_rewriter = nil, runtime_data = nil, report = nil)
|
23
|
+
super
|
24
|
+
@current_syntax_type = :should
|
25
|
+
end
|
26
|
+
|
27
|
+
def register_request_for_dynamic_analysis(rewriter)
|
28
|
+
register_request_of_syntax_availability_inspection(
|
29
|
+
rewriter,
|
30
|
+
:expect_available?,
|
31
|
+
[:expect]
|
32
|
+
)
|
33
|
+
|
34
|
+
operator_matcher.register_request_for_dynamic_analysis(rewriter) if operator_matcher
|
35
|
+
have_matcher.register_request_for_dynamic_analysis(rewriter) if have_matcher
|
36
|
+
end
|
37
|
+
|
38
|
+
def expect_available?
|
39
|
+
check_syntax_availability(__method__)
|
40
|
+
end
|
12
41
|
|
13
42
|
def positive?
|
14
43
|
method_name == :should
|
15
44
|
end
|
16
45
|
|
17
46
|
def expectize!(negative_form = 'not_to', parenthesize_matcher_arg = true)
|
18
|
-
unless
|
47
|
+
unless expect_available?
|
19
48
|
fail InvalidContextError.new(selector_range, "##{method_name}", '#expect')
|
20
49
|
end
|
21
50
|
|
@@ -27,13 +56,22 @@ module Transpec
|
|
27
56
|
|
28
57
|
replace(should_range, positive? ? 'to' : negative_form)
|
29
58
|
|
59
|
+
@current_syntax_type = :expect
|
30
60
|
register_record(negative_form)
|
31
61
|
|
32
|
-
|
62
|
+
operator_matcher.correct_operator!(parenthesize_matcher_arg) if operator_matcher
|
33
63
|
end
|
34
64
|
|
35
|
-
def
|
36
|
-
@
|
65
|
+
def operator_matcher
|
66
|
+
return @operator_matcher if instance_variable_defined?(:@operator_matcher)
|
67
|
+
|
68
|
+
@operator_matcher ||= begin
|
69
|
+
if OperatorMatcher.target_node?(matcher_node, @runtime_data)
|
70
|
+
OperatorMatcher.new(matcher_node, @source_rewriter, @runtime_data, @report)
|
71
|
+
else
|
72
|
+
nil
|
73
|
+
end
|
74
|
+
end
|
37
75
|
end
|
38
76
|
|
39
77
|
def matcher_node
|
@@ -42,14 +80,6 @@ module Transpec
|
|
42
80
|
|
43
81
|
private
|
44
82
|
|
45
|
-
def self.target_receiver_node?(node)
|
46
|
-
!node.nil?
|
47
|
-
end
|
48
|
-
|
49
|
-
def self.target_method_names
|
50
|
-
[:should, :should_not]
|
51
|
-
end
|
52
|
-
|
53
83
|
def replace_proc_selector_with_expect!
|
54
84
|
send_node = subject_node.children.first
|
55
85
|
range_of_subject_method_taking_block = send_node.loc.expression
|