transpec 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|