transpec 0.1.3 → 0.2.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/CHANGELOG.md +5 -0
- data/README.md +35 -3
- data/README.md.erb +35 -3
- data/lib/transpec/cli.rb +50 -4
- data/lib/transpec/commit_message.rb +25 -0
- data/lib/transpec/git.rb +18 -0
- data/lib/transpec/record.rb +28 -0
- data/lib/transpec/report.rb +109 -0
- data/lib/transpec/rewriter.rb +17 -8
- data/lib/transpec/syntax.rb +25 -22
- data/lib/transpec/syntax/be_close.rb +6 -0
- data/lib/transpec/syntax/double.rb +5 -0
- data/lib/transpec/syntax/matcher.rb +17 -1
- data/lib/transpec/syntax/method_stub.rb +40 -8
- data/lib/transpec/syntax/raise_error.rb +17 -0
- data/lib/transpec/syntax/send_node_syntax.rb +4 -0
- data/lib/transpec/syntax/should.rb +23 -2
- data/lib/transpec/syntax/should_receive.rb +54 -2
- data/lib/transpec/version.rb +2 -2
- data/spec/.rubocop.yml +1 -1
- data/spec/support/shared_context.rb +10 -0
- data/spec/transpec/cli_spec.rb +76 -29
- data/spec/transpec/commit_message_spec.rb +63 -0
- data/spec/transpec/configuration_spec.rb +1 -1
- data/spec/transpec/git_spec.rb +114 -38
- data/spec/transpec/record_spec.rb +18 -0
- data/spec/transpec/report_spec.rb +89 -0
- data/spec/transpec/rewriter_spec.rb +5 -0
- data/spec/transpec/syntax/be_close_spec.rb +10 -1
- data/spec/transpec/syntax/double_spec.rb +10 -0
- data/spec/transpec/syntax/matcher_spec.rb +31 -0
- data/spec/transpec/syntax/method_stub_spec.rb +53 -44
- data/spec/transpec/syntax/raise_error_spec.rb +64 -24
- data/spec/transpec/syntax/should_receive_spec.rb +67 -7
- data/spec/transpec/syntax/should_spec.rb +26 -0
- data/tasks/test.rake +27 -12
- metadata +11 -2
data/lib/transpec/rewriter.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
+
require 'transpec/report'
|
3
4
|
require 'transpec/ast/builder'
|
4
5
|
require 'transpec/ast/scanner'
|
5
6
|
require 'transpec/configuration'
|
@@ -16,11 +17,12 @@ require 'parser/current'
|
|
16
17
|
|
17
18
|
module Transpec
|
18
19
|
class Rewriter
|
19
|
-
attr_reader :
|
20
|
+
attr_reader :report, :invalid_context_errors
|
20
21
|
|
21
|
-
def initialize(configuration = Configuration.new)
|
22
|
+
def initialize(configuration = Configuration.new, report = Report.new)
|
22
23
|
@configuration = configuration
|
23
|
-
@
|
24
|
+
@report = report
|
25
|
+
@invalid_context_errors = []
|
24
26
|
end
|
25
27
|
|
26
28
|
def rewrite_file!(file_path)
|
@@ -35,7 +37,10 @@ module Transpec
|
|
35
37
|
|
36
38
|
@source_rewriter = Parser::Source::Rewriter.new(source_buffer)
|
37
39
|
failed_overlapping_rewrite = false
|
38
|
-
@source_rewriter.diagnostics.consumer = proc
|
40
|
+
@source_rewriter.diagnostics.consumer = proc do
|
41
|
+
failed_overlapping_rewrite = true
|
42
|
+
fail OverlappedRewriteError
|
43
|
+
end
|
39
44
|
|
40
45
|
AST::Scanner.scan(ast) do |node, ancestor_nodes|
|
41
46
|
dispatch_node(node, ancestor_nodes)
|
@@ -44,7 +49,7 @@ module Transpec
|
|
44
49
|
rewritten_source = @source_rewriter.process
|
45
50
|
|
46
51
|
if failed_overlapping_rewrite
|
47
|
-
rewriter = self.class.new(@configuration)
|
52
|
+
rewriter = self.class.new(@configuration, @report)
|
48
53
|
rewritten_source = rewriter.rewrite(rewritten_source, name)
|
49
54
|
end
|
50
55
|
|
@@ -71,7 +76,8 @@ module Transpec
|
|
71
76
|
syntax = syntax_class.new(
|
72
77
|
node,
|
73
78
|
ancestor_nodes,
|
74
|
-
@source_rewriter
|
79
|
+
@source_rewriter,
|
80
|
+
@report
|
75
81
|
)
|
76
82
|
|
77
83
|
handler_name = "process_#{syntax_class.snake_case_name}"
|
@@ -79,8 +85,9 @@ module Transpec
|
|
79
85
|
|
80
86
|
break
|
81
87
|
end
|
82
|
-
rescue
|
83
|
-
|
88
|
+
rescue OverlappedRewriteError # rubocop:disable HandleExceptions
|
89
|
+
rescue Syntax::InvalidContextError => error
|
90
|
+
@invalid_context_errors << error
|
84
91
|
end
|
85
92
|
|
86
93
|
def process_should(should)
|
@@ -152,5 +159,7 @@ module Transpec
|
|
152
159
|
!@configuration.convert_to_allow_to_receive?
|
153
160
|
rspec_configure.mock_syntaxes == [:should]
|
154
161
|
end
|
162
|
+
|
163
|
+
class OverlappedRewriteError < StandardError; end
|
155
164
|
end
|
156
165
|
end
|
data/lib/transpec/syntax.rb
CHANGED
@@ -1,30 +1,12 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
3
|
require 'transpec/context'
|
4
|
+
require 'transpec/report'
|
5
|
+
require 'transpec/record'
|
4
6
|
|
5
7
|
module Transpec
|
6
8
|
class Syntax
|
7
|
-
|
8
|
-
attr_reader :message, :source_range
|
9
|
-
|
10
|
-
def initialize(source_range, original_syntax, target_syntax)
|
11
|
-
@source_range = source_range
|
12
|
-
@message = build_message(original_syntax, target_syntax)
|
13
|
-
end
|
14
|
-
|
15
|
-
def source_buffer
|
16
|
-
@source_range.source_buffer
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
def build_message(original_syntax, target_syntax)
|
22
|
-
"Cannot convert #{original_syntax} into #{target_syntax} " +
|
23
|
-
"since #{target_syntax} is not available in the context."
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
attr_reader :node, :ancestor_nodes, :source_rewriter
|
9
|
+
attr_reader :node, :ancestor_nodes, :source_rewriter, :report
|
28
10
|
|
29
11
|
def self.all
|
30
12
|
@subclasses ||= []
|
@@ -48,10 +30,11 @@ module Transpec
|
|
48
30
|
target_method_names.include?(method_name)
|
49
31
|
end
|
50
32
|
|
51
|
-
def initialize(node, ancestor_nodes, source_rewriter)
|
33
|
+
def initialize(node, ancestor_nodes, source_rewriter, report = Report.new)
|
52
34
|
@node = node
|
53
35
|
@ancestor_nodes = ancestor_nodes
|
54
36
|
@source_rewriter = source_rewriter
|
37
|
+
@report = report
|
55
38
|
end
|
56
39
|
|
57
40
|
def context
|
@@ -91,5 +74,25 @@ module Transpec
|
|
91
74
|
def replace(range, content)
|
92
75
|
@source_rewriter.replace(range, content)
|
93
76
|
end
|
77
|
+
|
78
|
+
class InvalidContextError < StandardError
|
79
|
+
attr_reader :message, :source_range
|
80
|
+
|
81
|
+
def initialize(source_range, original_syntax, target_syntax)
|
82
|
+
@source_range = source_range
|
83
|
+
@message = build_message(original_syntax, target_syntax)
|
84
|
+
end
|
85
|
+
|
86
|
+
def source_buffer
|
87
|
+
@source_range.source_buffer
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def build_message(original_syntax, target_syntax)
|
93
|
+
"Cannot convert #{original_syntax} into #{target_syntax} " +
|
94
|
+
"since #{target_syntax} is not available in the context."
|
95
|
+
end
|
96
|
+
end
|
94
97
|
end
|
95
98
|
end
|
@@ -16,6 +16,8 @@ module Transpec
|
|
16
16
|
be_within_source << ')'
|
17
17
|
|
18
18
|
replace(expression_range, be_within_source)
|
19
|
+
|
20
|
+
register_record
|
19
21
|
end
|
20
22
|
|
21
23
|
private
|
@@ -27,6 +29,10 @@ module Transpec
|
|
27
29
|
def self.target_method_names
|
28
30
|
[:be_close]
|
29
31
|
end
|
32
|
+
|
33
|
+
def register_record
|
34
|
+
@report.records << Record.new('be_close(expected, delta)', 'be_within(delta).of(expected)')
|
35
|
+
end
|
30
36
|
end
|
31
37
|
end
|
32
38
|
end
|
@@ -11,6 +11,7 @@ module Transpec
|
|
11
11
|
def convert_to_double!
|
12
12
|
return if method_name == :double
|
13
13
|
replace(selector_range, 'double')
|
14
|
+
register_record
|
14
15
|
end
|
15
16
|
|
16
17
|
private
|
@@ -22,6 +23,10 @@ module Transpec
|
|
22
23
|
def self.target_method_names
|
23
24
|
[:double, :mock, :stub]
|
24
25
|
end
|
26
|
+
|
27
|
+
def register_record
|
28
|
+
@report.records << Record.new("#{method_name}('something')", "double('something')")
|
29
|
+
end
|
25
30
|
end
|
26
31
|
end
|
27
32
|
end
|
@@ -13,9 +13,10 @@ module Transpec
|
|
13
13
|
false
|
14
14
|
end
|
15
15
|
|
16
|
-
def initialize(node, source_rewriter)
|
16
|
+
def initialize(node, source_rewriter, report = Report.new)
|
17
17
|
@node = node
|
18
18
|
@source_rewriter = source_rewriter
|
19
|
+
@report = report
|
19
20
|
end
|
20
21
|
|
21
22
|
def correct_operator!(parenthesize_arg = true)
|
@@ -47,11 +48,13 @@ module Transpec
|
|
47
48
|
handle_anterior_of_operator!
|
48
49
|
replace(selector_range, 'eq')
|
49
50
|
parenthesize!(parenthesize_arg)
|
51
|
+
register_record(nil, 'eq(expected)')
|
50
52
|
end
|
51
53
|
|
52
54
|
def convert_to_be_operator!
|
53
55
|
return if prefixed_with_be?
|
54
56
|
insert_before(selector_range, 'be ')
|
57
|
+
register_record(nil, "be #{method_name} expected")
|
55
58
|
end
|
56
59
|
|
57
60
|
def convert_to_match!(parenthesize_arg)
|
@@ -64,6 +67,14 @@ module Transpec
|
|
64
67
|
end
|
65
68
|
|
66
69
|
parenthesize!(parenthesize_arg)
|
70
|
+
|
71
|
+
# Need to register record after all source rewrites are done
|
72
|
+
# to avoid false record when failed with overlapped rewrite.
|
73
|
+
if arg_node.type == :array
|
74
|
+
register_record('=~ [1, 2]', 'match_array([1, 2])')
|
75
|
+
else
|
76
|
+
register_record('=~ /pattern/', 'match(/pattern/)')
|
77
|
+
end
|
67
78
|
end
|
68
79
|
|
69
80
|
def handle_anterior_of_operator!
|
@@ -113,6 +124,11 @@ module Transpec
|
|
113
124
|
here_document?(arg_node) ||
|
114
125
|
arg_node.each_descendent_node.any? { |n| here_document?(n) }
|
115
126
|
end
|
127
|
+
|
128
|
+
def register_record(original_syntax, converted_syntax)
|
129
|
+
original_syntax ||= "#{method_name} expected"
|
130
|
+
@report.records << Record.new(original_syntax, converted_syntax)
|
131
|
+
end
|
116
132
|
end
|
117
133
|
end
|
118
134
|
end
|
@@ -23,7 +23,7 @@ module Transpec
|
|
23
23
|
fail 'Already replaced deprecated method, cannot allowize.' if @replaced_deprecated_method
|
24
24
|
|
25
25
|
unless context.in_example_group?
|
26
|
-
fail
|
26
|
+
fail InvalidContextError.new(selector_range, "##{method_name}", '#allow')
|
27
27
|
end
|
28
28
|
|
29
29
|
if arg_node.type == :hash
|
@@ -34,20 +34,19 @@ module Transpec
|
|
34
34
|
replace(expression_range, expression)
|
35
35
|
end
|
36
36
|
|
37
|
+
register_record(:allow)
|
38
|
+
|
37
39
|
@allowized = true
|
38
40
|
end
|
39
41
|
|
40
42
|
def replace_deprecated_method!
|
41
|
-
|
42
|
-
when :stub! then 'stub'
|
43
|
-
when :unstub! then 'unstub'
|
44
|
-
end
|
45
|
-
|
46
|
-
return unless replacement_method_name
|
43
|
+
return unless replacement_method_for_deprecated_method
|
47
44
|
|
48
45
|
fail 'Already allowized, cannot replace deprecated method.' if @allowized
|
49
46
|
|
50
|
-
replace(selector_range,
|
47
|
+
replace(selector_range, replacement_method_for_deprecated_method)
|
48
|
+
|
49
|
+
register_record(:deprecated)
|
51
50
|
|
52
51
|
@replaced_deprecated_method = true
|
53
52
|
end
|
@@ -107,6 +106,39 @@ module Transpec
|
|
107
106
|
message_source.prepend(':') if node.type == :sym && !message_source.start_with?(':')
|
108
107
|
message_source
|
109
108
|
end
|
109
|
+
|
110
|
+
def replacement_method_for_deprecated_method
|
111
|
+
case method_name
|
112
|
+
when :stub! then 'stub'
|
113
|
+
when :unstub! then 'unstub'
|
114
|
+
else nil
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def register_record(conversion_type)
|
119
|
+
@report.records << Record.new(original_syntax, converted_syntax(conversion_type))
|
120
|
+
end
|
121
|
+
|
122
|
+
def original_syntax
|
123
|
+
syntax = any_instance? ? 'SomeClass.any_instance' : 'obj'
|
124
|
+
syntax << ".#{method_name}"
|
125
|
+
syntax << (arg_node.type == :hash ? '(:message => value)' : '(:message)')
|
126
|
+
end
|
127
|
+
|
128
|
+
def converted_syntax(conversion_type)
|
129
|
+
case conversion_type
|
130
|
+
when :allow
|
131
|
+
syntax = any_instance? ? 'allow_any_instance_of(SomeClass)' : 'allow(obj)'
|
132
|
+
syntax << '.to receive(:message)'
|
133
|
+
syntax << '.and_return(value)' if arg_node.type == :hash
|
134
|
+
when :deprecated
|
135
|
+
syntax = 'obj.'
|
136
|
+
syntax << replacement_method_for_deprecated_method
|
137
|
+
syntax << '(:message)'
|
138
|
+
end
|
139
|
+
|
140
|
+
syntax
|
141
|
+
end
|
110
142
|
end
|
111
143
|
end
|
112
144
|
end
|
@@ -15,6 +15,8 @@ module Transpec
|
|
15
15
|
return if arg_nodes.empty?
|
16
16
|
|
17
17
|
remove(parentheses_range)
|
18
|
+
|
19
|
+
register_record
|
18
20
|
end
|
19
21
|
|
20
22
|
def positive?
|
@@ -31,6 +33,21 @@ module Transpec
|
|
31
33
|
def self.target_method_names
|
32
34
|
[:raise_error]
|
33
35
|
end
|
36
|
+
|
37
|
+
def register_record
|
38
|
+
original_syntax = 'expect { }.not_to raise_error('
|
39
|
+
|
40
|
+
if arg_nodes.first.type == :const
|
41
|
+
original_syntax << 'SpecificErrorClass'
|
42
|
+
original_syntax << ', message' if arg_nodes.count >= 2
|
43
|
+
else
|
44
|
+
original_syntax << 'message'
|
45
|
+
end
|
46
|
+
|
47
|
+
original_syntax << ')'
|
48
|
+
|
49
|
+
@report.records << Record.new(original_syntax, 'expect { }.not_to raise_error')
|
50
|
+
end
|
34
51
|
end
|
35
52
|
end
|
36
53
|
end
|
@@ -16,7 +16,7 @@ module Transpec
|
|
16
16
|
|
17
17
|
def expectize!(negative_form = 'not_to', parenthesize_matcher_arg = true)
|
18
18
|
unless context.in_example_group?
|
19
|
-
fail
|
19
|
+
fail InvalidContextError.new(selector_range, "##{method_name}", '#expect')
|
20
20
|
end
|
21
21
|
|
22
22
|
if proc_literal?(subject_node)
|
@@ -27,11 +27,13 @@ module Transpec
|
|
27
27
|
|
28
28
|
replace(should_range, positive? ? 'to' : negative_form)
|
29
29
|
|
30
|
+
register_record(negative_form)
|
31
|
+
|
30
32
|
matcher.correct_operator!(parenthesize_matcher_arg)
|
31
33
|
end
|
32
34
|
|
33
35
|
def matcher
|
34
|
-
@matcher ||= Matcher.new(matcher_node, @source_rewriter)
|
36
|
+
@matcher ||= Matcher.new(matcher_node, @source_rewriter, @report)
|
35
37
|
end
|
36
38
|
|
37
39
|
def matcher_node
|
@@ -61,6 +63,25 @@ module Transpec
|
|
61
63
|
selector_range.join(expression_range.end)
|
62
64
|
end
|
63
65
|
end
|
66
|
+
|
67
|
+
def register_record(negative_form_of_to)
|
68
|
+
if proc_literal?(subject_node)
|
69
|
+
original_syntax = 'lambda { }.should'
|
70
|
+
converted_syntax = 'expect { }.'
|
71
|
+
else
|
72
|
+
original_syntax = 'obj.should'
|
73
|
+
converted_syntax = 'expect(obj).'
|
74
|
+
end
|
75
|
+
|
76
|
+
if positive?
|
77
|
+
converted_syntax << 'to'
|
78
|
+
else
|
79
|
+
original_syntax << '_not'
|
80
|
+
converted_syntax << negative_form_of_to
|
81
|
+
end
|
82
|
+
|
83
|
+
@report.records << Record.new(original_syntax, converted_syntax)
|
84
|
+
end
|
64
85
|
end
|
65
86
|
end
|
66
87
|
end
|
@@ -18,6 +18,7 @@ module Transpec
|
|
18
18
|
|
19
19
|
def expectize!(negative_form = 'not_to')
|
20
20
|
convert_to_syntax!('expect', negative_form)
|
21
|
+
register_record(:expect, negative_form)
|
21
22
|
end
|
22
23
|
|
23
24
|
def allowize_useless_expectation!(negative_form = 'not_to')
|
@@ -25,20 +26,24 @@ module Transpec
|
|
25
26
|
|
26
27
|
convert_to_syntax!('allow', negative_form)
|
27
28
|
remove_allowance_for_no_message!
|
29
|
+
|
30
|
+
register_record(:allow, negative_form)
|
28
31
|
end
|
29
32
|
|
30
|
-
def stubize_useless_expectation!
|
33
|
+
def stubize_useless_expectation!
|
31
34
|
return unless useless_expectation?
|
32
35
|
|
33
36
|
replace(selector_range, 'stub')
|
34
37
|
remove_allowance_for_no_message!
|
38
|
+
|
39
|
+
register_record(:stub)
|
35
40
|
end
|
36
41
|
|
37
42
|
private
|
38
43
|
|
39
44
|
def convert_to_syntax!(syntax, negative_form)
|
40
45
|
unless context.in_example_group?
|
41
|
-
fail
|
46
|
+
fail InvalidContextError.new(selector_range, "##{method_name}", "##{syntax}")
|
42
47
|
end
|
43
48
|
|
44
49
|
if any_instance?
|
@@ -121,6 +126,53 @@ module Transpec
|
|
121
126
|
return child_node if child_node.type == :block
|
122
127
|
end
|
123
128
|
end
|
129
|
+
|
130
|
+
def register_record(conversion_type, negative_form_of_to = nil)
|
131
|
+
@report.records << Record.new(
|
132
|
+
original_syntax(conversion_type),
|
133
|
+
converted_syntax(conversion_type, negative_form_of_to)
|
134
|
+
)
|
135
|
+
end
|
136
|
+
|
137
|
+
def original_syntax(conversion_type)
|
138
|
+
syntax = if any_instance? && conversion_type != :stub
|
139
|
+
'SomeClass.any_instance.'
|
140
|
+
else
|
141
|
+
'obj.'
|
142
|
+
end
|
143
|
+
|
144
|
+
syntax << (positive? ? 'should_receive' : 'should_not_receive')
|
145
|
+
syntax << '(:message)'
|
146
|
+
|
147
|
+
if [:allow, :stub].include?(conversion_type)
|
148
|
+
syntax << '.any_number_of_times' if any_number_of_times?
|
149
|
+
syntax << '.at_least(0)' if at_least_zero?
|
150
|
+
end
|
151
|
+
|
152
|
+
syntax
|
153
|
+
end
|
154
|
+
|
155
|
+
def converted_syntax(conversion_type, negative_form_of_to)
|
156
|
+
return 'obj.stub(:message)' if conversion_type == :stub
|
157
|
+
|
158
|
+
syntax = case conversion_type
|
159
|
+
when :expect
|
160
|
+
if any_instance?
|
161
|
+
'expect_any_instance_of(SomeClass).'
|
162
|
+
else
|
163
|
+
'expect(obj).'
|
164
|
+
end
|
165
|
+
when :allow
|
166
|
+
if any_instance?
|
167
|
+
'allow_any_instance_of(SomeClass).'
|
168
|
+
else
|
169
|
+
'allow(obj).'
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
syntax << (positive? ? 'to' : negative_form_of_to)
|
174
|
+
syntax << ' receive(:message)'
|
175
|
+
end
|
124
176
|
end
|
125
177
|
end
|
126
178
|
end
|