transpec 1.9.3 → 1.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/.travis.yml +1 -1
- data/CHANGELOG.md +5 -0
- data/CONTRIBUTING.md +19 -0
- data/README.md +78 -9
- data/README.md.erb +68 -10
- data/lib/transpec/annotatable.rb +16 -0
- data/lib/transpec/cli.rb +35 -27
- data/lib/transpec/configuration.rb +1 -0
- data/lib/transpec/conversion_error.rb +23 -0
- data/lib/transpec/converter.rb +59 -50
- data/lib/transpec/dynamic_analyzer.rb +13 -29
- data/lib/transpec/dynamic_analyzer/rewriter.rb +3 -10
- data/lib/transpec/dynamic_analyzer/runtime_data.rb +16 -8
- data/lib/transpec/file_finder.rb +1 -1
- data/lib/transpec/git.rb +1 -1
- data/lib/transpec/option_parser.rb +12 -10
- data/lib/transpec/project.rb +3 -3
- data/lib/transpec/record.rb +19 -2
- data/lib/transpec/report.rb +29 -13
- data/lib/transpec/rspec_version.rb +7 -7
- data/lib/transpec/static_context_inspector.rb +1 -5
- data/lib/transpec/syntax.rb +11 -16
- data/lib/transpec/syntax/be_boolean.rb +1 -1
- data/lib/transpec/syntax/be_close.rb +1 -1
- data/lib/transpec/syntax/current_example.rb +88 -0
- data/lib/transpec/syntax/double.rb +1 -1
- data/lib/transpec/syntax/example.rb +60 -54
- data/lib/transpec/syntax/have.rb +27 -15
- data/lib/transpec/syntax/have/have_record.rb +12 -0
- data/lib/transpec/syntax/have/source_builder.rb +18 -16
- data/lib/transpec/syntax/its.rb +12 -11
- data/lib/transpec/syntax/matcher_definition.rb +1 -1
- data/lib/transpec/syntax/method_stub.rb +3 -7
- data/lib/transpec/syntax/mixin/matcher_owner.rb +2 -2
- data/lib/transpec/syntax/mixin/monkey_patch.rb +3 -5
- data/lib/transpec/syntax/mixin/monkey_patch_any_instance.rb +2 -4
- data/lib/transpec/syntax/mixin/owned_matcher.rb +1 -4
- data/lib/transpec/syntax/mixin/send.rb +7 -9
- data/lib/transpec/syntax/oneliner_should.rb +4 -4
- data/lib/transpec/syntax/operator.rb +27 -11
- data/lib/transpec/syntax/pending.rb +110 -0
- data/lib/transpec/syntax/raise_error.rb +1 -1
- data/lib/transpec/syntax/receive.rb +4 -4
- data/lib/transpec/syntax/rspec_configure/framework.rb +3 -3
- data/lib/transpec/syntax/should.rb +2 -2
- data/lib/transpec/syntax/should_receive.rb +3 -3
- data/lib/transpec/util.rb +38 -6
- data/lib/transpec/version.rb +2 -2
- data/spec/support/file_helper.rb +1 -1
- data/spec/support/shared_context.rb +3 -8
- data/spec/transpec/cli_spec.rb +63 -1
- data/spec/transpec/configuration_spec.rb +1 -0
- data/spec/transpec/converter_spec.rb +106 -15
- data/spec/transpec/dynamic_analyzer/rewriter_spec.rb +12 -52
- data/spec/transpec/dynamic_analyzer_spec.rb +2 -2
- data/spec/transpec/option_parser_spec.rb +3 -2
- data/spec/transpec/report_spec.rb +33 -4
- data/spec/transpec/rspec_version_spec.rb +5 -2
- data/spec/transpec/syntax/current_example_spec.rb +267 -0
- data/spec/transpec/syntax/example_spec.rb +156 -122
- data/spec/transpec/syntax/have_spec.rb +43 -32
- data/spec/transpec/syntax/method_stub_spec.rb +8 -0
- data/spec/transpec/syntax/operator_spec.rb +67 -2
- data/spec/transpec/syntax/pending_spec.rb +375 -0
- metadata +12 -4
- data/lib/transpec/context_error.rb +0 -23
@@ -13,6 +13,7 @@ module Transpec
|
|
13
13
|
[:convert_stub, true],
|
14
14
|
[:convert_have_items, true],
|
15
15
|
[:convert_its, true],
|
16
|
+
[:convert_pending, true],
|
16
17
|
[:convert_deprecated_method, true],
|
17
18
|
[:parenthesize_matcher_arg, true],
|
18
19
|
[:add_receiver_arg_to_any_instance_implementation_block, true],
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'transpec/annotatable'
|
4
|
+
|
5
|
+
module Transpec
|
6
|
+
class ConversionError < StandardError
|
7
|
+
include Annotatable
|
8
|
+
end
|
9
|
+
|
10
|
+
class ContextError < ConversionError
|
11
|
+
def initialize(original_syntax, target_syntax, source_range)
|
12
|
+
message = build_message(original_syntax, target_syntax)
|
13
|
+
super(message, source_range)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def build_message(original_syntax, target_syntax)
|
19
|
+
"Cannot convert #{original_syntax} into #{target_syntax} " +
|
20
|
+
"since #{target_syntax} is not available in the context."
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/transpec/converter.rb
CHANGED
@@ -9,18 +9,17 @@ require 'transpec/syntax'
|
|
9
9
|
Transpec::Syntax.require_all
|
10
10
|
|
11
11
|
module Transpec
|
12
|
-
class Converter < BaseRewriter
|
13
|
-
attr_reader :configuration, :rspec_version, :runtime_data, :report
|
12
|
+
class Converter < BaseRewriter # rubocop:disable ClassLength
|
13
|
+
attr_reader :configuration, :rspec_version, :runtime_data, :report
|
14
14
|
|
15
15
|
alias_method :convert_file!, :rewrite_file!
|
16
16
|
alias_method :convert, :rewrite
|
17
17
|
|
18
|
-
def initialize(configuration = nil, rspec_version = nil, runtime_data = nil
|
18
|
+
def initialize(configuration = nil, rspec_version = nil, runtime_data = nil)
|
19
19
|
@configuration = configuration || Configuration.new
|
20
20
|
@rspec_version = rspec_version || Transpec.current_rspec_version
|
21
21
|
@runtime_data = runtime_data
|
22
|
-
@report =
|
23
|
-
@context_errors = []
|
22
|
+
@report = Report.new
|
24
23
|
end
|
25
24
|
|
26
25
|
def process(ast, source_rewriter)
|
@@ -32,9 +31,9 @@ module Transpec
|
|
32
31
|
|
33
32
|
def dispatch_node(node, source_rewriter)
|
34
33
|
Syntax.standalone_syntaxes.each do |syntax_class|
|
35
|
-
next unless syntax_class.conversion_target_node?(node,
|
34
|
+
next unless syntax_class.conversion_target_node?(node, runtime_data)
|
36
35
|
|
37
|
-
syntax = syntax_class.new(node, source_rewriter,
|
36
|
+
syntax = syntax_class.new(node, source_rewriter, runtime_data, report)
|
38
37
|
|
39
38
|
handler_name = "process_#{syntax_class.snake_case_name}"
|
40
39
|
send(handler_name, syntax)
|
@@ -42,15 +41,15 @@ module Transpec
|
|
42
41
|
break
|
43
42
|
end
|
44
43
|
rescue OverlappedRewriteError # rubocop:disable HandleExceptions
|
45
|
-
rescue
|
46
|
-
|
44
|
+
rescue ConversionError => error
|
45
|
+
report.conversion_errors << error
|
47
46
|
end
|
48
47
|
|
49
48
|
def process_should(should)
|
50
|
-
if
|
49
|
+
if configuration.convert_should?
|
51
50
|
should.expectize!(
|
52
|
-
|
53
|
-
|
51
|
+
configuration.negative_form_of_to,
|
52
|
+
configuration.parenthesize_matcher_arg?
|
54
53
|
)
|
55
54
|
end
|
56
55
|
|
@@ -59,22 +58,22 @@ module Transpec
|
|
59
58
|
end
|
60
59
|
|
61
60
|
def process_oneliner_should(oneliner_should)
|
62
|
-
negative_form =
|
63
|
-
parenthesize =
|
61
|
+
negative_form = configuration.negative_form_of_to
|
62
|
+
parenthesize = configuration.parenthesize_matcher_arg?
|
64
63
|
|
65
64
|
# TODO: Referencing oneliner_should.have_matcher.project_requires_collection_matcher?
|
66
65
|
# from this converter is considered bad design.
|
67
|
-
should_convert_have_items =
|
66
|
+
should_convert_have_items = configuration.convert_have_items? &&
|
68
67
|
oneliner_should.have_matcher &&
|
69
68
|
!oneliner_should.have_matcher.project_requires_collection_matcher?
|
70
69
|
|
71
70
|
if should_convert_have_items
|
72
|
-
if
|
71
|
+
if configuration.convert_should?
|
73
72
|
oneliner_should.convert_have_items_to_standard_expect!(negative_form, parenthesize)
|
74
73
|
else
|
75
74
|
oneliner_should.convert_have_items_to_standard_should!
|
76
75
|
end
|
77
|
-
elsif
|
76
|
+
elsif configuration.convert_oneliner? && rspec_version.oneliner_is_expected_available?
|
78
77
|
oneliner_should.expectize!(negative_form, parenthesize)
|
79
78
|
end
|
80
79
|
|
@@ -93,79 +92,89 @@ module Transpec
|
|
93
92
|
|
94
93
|
def process_should_receive(should_receive)
|
95
94
|
if should_receive.useless_expectation?
|
96
|
-
if
|
97
|
-
if
|
98
|
-
should_receive.allowize_useless_expectation!(
|
95
|
+
if configuration.convert_deprecated_method?
|
96
|
+
if configuration.convert_stub?
|
97
|
+
should_receive.allowize_useless_expectation!(configuration.negative_form_of_to)
|
99
98
|
else
|
100
99
|
should_receive.stubize_useless_expectation!
|
101
100
|
end
|
102
|
-
elsif
|
103
|
-
should_receive.expectize!(
|
101
|
+
elsif configuration.convert_should_receive?
|
102
|
+
should_receive.expectize!(configuration.negative_form_of_to)
|
104
103
|
end
|
105
|
-
elsif
|
106
|
-
should_receive.expectize!(
|
104
|
+
elsif configuration.convert_should_receive?
|
105
|
+
should_receive.expectize!(configuration.negative_form_of_to)
|
107
106
|
end
|
108
107
|
|
109
108
|
process_messaging_host(should_receive)
|
110
109
|
end
|
111
110
|
|
112
111
|
def process_double(double)
|
113
|
-
double.convert_to_double! if
|
112
|
+
double.convert_to_double! if configuration.convert_deprecated_method?
|
114
113
|
end
|
115
114
|
|
116
115
|
def process_method_stub(method_stub)
|
117
|
-
if
|
116
|
+
if configuration.convert_stub?
|
118
117
|
if !method_stub.hash_arg? ||
|
119
|
-
|
120
|
-
|
121
|
-
method_stub.allowize!(
|
122
|
-
elsif
|
118
|
+
rspec_version.receive_messages_available? ||
|
119
|
+
configuration.convert_stub_with_hash_to_stub_and_return?
|
120
|
+
method_stub.allowize!(rspec_version)
|
121
|
+
elsif configuration.convert_deprecated_method?
|
123
122
|
method_stub.convert_deprecated_method!
|
124
123
|
end
|
125
|
-
elsif
|
124
|
+
elsif configuration.convert_deprecated_method?
|
126
125
|
method_stub.convert_deprecated_method!
|
127
126
|
end
|
128
127
|
|
129
|
-
method_stub.remove_no_message_allowance! if
|
128
|
+
method_stub.remove_no_message_allowance! if configuration.convert_deprecated_method?
|
130
129
|
|
131
130
|
process_messaging_host(method_stub)
|
132
131
|
end
|
133
132
|
|
134
133
|
def process_be_boolean(be_boolean)
|
135
|
-
return unless
|
136
|
-
return unless
|
134
|
+
return unless rspec_version.be_truthy_available?
|
135
|
+
return unless configuration.convert_deprecated_method?
|
137
136
|
|
138
|
-
case
|
137
|
+
case configuration.boolean_matcher_type
|
139
138
|
when :conditional
|
140
|
-
be_boolean.convert_to_conditional_matcher!(
|
139
|
+
be_boolean.convert_to_conditional_matcher!(configuration.form_of_be_falsey)
|
141
140
|
when :exact
|
142
141
|
be_boolean.convert_to_exact_matcher!
|
143
142
|
end
|
144
143
|
end
|
145
144
|
|
146
145
|
def process_be_close(be_close)
|
147
|
-
be_close.convert_to_be_within! if
|
146
|
+
be_close.convert_to_be_within! if configuration.convert_deprecated_method?
|
148
147
|
end
|
149
148
|
|
150
149
|
def process_raise_error(raise_error)
|
151
150
|
return unless raise_error
|
152
|
-
if
|
151
|
+
if configuration.convert_deprecated_method?
|
153
152
|
raise_error.remove_error_specification_with_negative_expectation!
|
154
153
|
end
|
155
154
|
end
|
156
155
|
|
157
156
|
def process_its(its)
|
158
|
-
its.convert_to_describe_subject_it! if
|
157
|
+
its.convert_to_describe_subject_it! if configuration.convert_its?
|
159
158
|
end
|
160
159
|
|
161
160
|
def process_example(example)
|
162
|
-
return
|
163
|
-
example.
|
161
|
+
return if !rspec_version.rspec_2_99? || !configuration.convert_pending?
|
162
|
+
example.convert_pending_to_skip!
|
163
|
+
end
|
164
|
+
|
165
|
+
def process_pending(pending)
|
166
|
+
return if !rspec_version.rspec_2_99? || !configuration.convert_pending?
|
167
|
+
pending.convert_deprecated_syntax!
|
168
|
+
end
|
169
|
+
|
170
|
+
def process_current_example(current_example)
|
171
|
+
return unless rspec_version.yielded_example_available?
|
172
|
+
current_example.convert! if configuration.convert_deprecated_method?
|
164
173
|
end
|
165
174
|
|
166
175
|
def process_matcher_definition(matcher_definition)
|
167
|
-
return unless
|
168
|
-
matcher_definition.convert_deprecated_method! if
|
176
|
+
return unless rspec_version.non_should_matcher_protocol_available?
|
177
|
+
matcher_definition.convert_deprecated_method! if configuration.convert_deprecated_method?
|
169
178
|
end
|
170
179
|
|
171
180
|
def process_rspec_configure(rspec_configure)
|
@@ -177,7 +186,7 @@ module Transpec
|
|
177
186
|
rspec_configure.mocks.syntaxes = :expect
|
178
187
|
end
|
179
188
|
|
180
|
-
if rspec_version.
|
189
|
+
if rspec_version.rspec_2_99? &&
|
181
190
|
configuration.convert_deprecated_method?
|
182
191
|
should_yield = configuration.add_receiver_arg_to_any_instance_implementation_block?
|
183
192
|
rspec_configure.mocks.yield_receiver_to_any_instance_implementation_blocks = should_yield
|
@@ -185,8 +194,8 @@ module Transpec
|
|
185
194
|
end
|
186
195
|
|
187
196
|
def process_have(have)
|
188
|
-
return if !have ||
|
189
|
-
have.convert_to_standard_expectation!(
|
197
|
+
return if !have || !configuration.convert_have_items?
|
198
|
+
have.convert_to_standard_expectation!(configuration.parenthesize_matcher_arg)
|
190
199
|
end
|
191
200
|
|
192
201
|
def process_messaging_host(messaging_host)
|
@@ -202,22 +211,22 @@ module Transpec
|
|
202
211
|
|
203
212
|
def process_any_instance_block(messaging_host)
|
204
213
|
return unless messaging_host
|
205
|
-
return unless rspec_version.
|
214
|
+
return unless rspec_version.rspec_2_99?
|
206
215
|
return unless configuration.convert_deprecated_method?
|
207
216
|
return unless configuration.add_receiver_arg_to_any_instance_implementation_block?
|
208
217
|
messaging_host.add_receiver_arg_to_any_instance_implementation_block!
|
209
218
|
end
|
210
219
|
|
211
220
|
def need_to_modify_expectation_syntax_configuration?(rspec_configure)
|
212
|
-
return false unless
|
221
|
+
return false unless configuration.convert_should?
|
213
222
|
rspec_configure.expectations.syntaxes == [:should]
|
214
223
|
rescue Syntax::RSpecConfigure::Framework::UnknownSyntaxError
|
215
224
|
false
|
216
225
|
end
|
217
226
|
|
218
227
|
def need_to_modify_mock_syntax_configuration?(rspec_configure)
|
219
|
-
return false if
|
220
|
-
|
228
|
+
return false if !configuration.convert_should_receive? &&
|
229
|
+
!configuration.convert_stub?
|
221
230
|
rspec_configure.mocks.syntaxes == [:should]
|
222
231
|
rescue Syntax::RSpecConfigure::Framework::UnknownSyntaxError
|
223
232
|
false
|
@@ -13,7 +13,7 @@ require 'English'
|
|
13
13
|
|
14
14
|
module Transpec
|
15
15
|
class DynamicAnalyzer
|
16
|
-
ANALYSIS_METHOD = '
|
16
|
+
ANALYSIS_METHOD = 'transpec_analyze'
|
17
17
|
HELPER_FILE = 'transpec_analysis_helper.rb'
|
18
18
|
RESULT_FILE = 'transpec_analysis_result.json'
|
19
19
|
HELPER_SOURCE = <<-END
|
@@ -26,16 +26,6 @@ module Transpec
|
|
26
26
|
@data ||= {}
|
27
27
|
end
|
28
28
|
|
29
|
-
def self.node_id(filename, begin_pos, end_pos)
|
30
|
-
absolute_path = File.expand_path(filename)
|
31
|
-
relative_path = Pathname.new(absolute_path).relative_path_from(base_pathname).to_s
|
32
|
-
[relative_path, begin_pos, end_pos].join('_')
|
33
|
-
end
|
34
|
-
|
35
|
-
def self.base_pathname
|
36
|
-
@base_pathname ||= Pathname.new(@base_path)
|
37
|
-
end
|
38
|
-
|
39
29
|
at_exit do
|
40
30
|
# Use JSON rather than Marshal so that:
|
41
31
|
# * Unknown third-party class information won't be serialized.
|
@@ -50,28 +40,22 @@ module Transpec
|
|
50
40
|
end
|
51
41
|
end
|
52
42
|
|
53
|
-
def #{ANALYSIS_METHOD}(object, context,
|
54
|
-
|
43
|
+
def #{ANALYSIS_METHOD}(object, context, node_id, analysis_codes)
|
44
|
+
node_data = {}
|
45
|
+
|
46
|
+
analysis_codes.each do |key, (target_type, code)|
|
55
47
|
target = case target_type
|
56
48
|
when :object then object
|
57
49
|
when :context then context
|
58
50
|
end
|
59
51
|
|
60
|
-
eval_data = {}
|
61
|
-
|
62
52
|
begin
|
63
|
-
|
64
|
-
rescue Exception
|
65
|
-
eval_data[:error] = error
|
53
|
+
node_data[key] = target.instance_eval(code)
|
54
|
+
rescue Exception
|
66
55
|
end
|
67
|
-
|
68
|
-
[key, eval_data]
|
69
56
|
end
|
70
57
|
|
71
|
-
|
72
|
-
|
73
|
-
id = TranspecAnalysis.node_id(filename, begin_pos, end_pos)
|
74
|
-
TranspecAnalysis.data[id] = object_data
|
58
|
+
TranspecAnalysis.data[node_id] = node_data
|
75
59
|
|
76
60
|
object
|
77
61
|
end
|
@@ -93,7 +77,7 @@ module Transpec
|
|
93
77
|
end
|
94
78
|
|
95
79
|
def default_rspec_command
|
96
|
-
if
|
80
|
+
if project.require_bundler?
|
97
81
|
'bundle exec rspec'
|
98
82
|
else
|
99
83
|
'rspec'
|
@@ -128,9 +112,9 @@ module Transpec
|
|
128
112
|
@in_copied_project = true
|
129
113
|
|
130
114
|
Dir.mktmpdir do |tmpdir|
|
131
|
-
copy_recursively(
|
132
|
-
|
133
|
-
Dir.chdir(
|
115
|
+
copy_recursively(project.path, tmpdir)
|
116
|
+
copied_project_path = File.join(tmpdir, project.basename)
|
117
|
+
Dir.chdir(copied_project_path) do
|
134
118
|
yield
|
135
119
|
end
|
136
120
|
end
|
@@ -139,7 +123,7 @@ module Transpec
|
|
139
123
|
end
|
140
124
|
|
141
125
|
def run_rspec(paths)
|
142
|
-
|
126
|
+
project.with_bundler_clean_env do
|
143
127
|
ENV['SPEC_OPTS'] = ['-r', "./#{HELPER_FILE}"].shelljoin
|
144
128
|
|
145
129
|
command = "#{rspec_command} #{paths.shelljoin}"
|
@@ -54,11 +54,11 @@ module Transpec
|
|
54
54
|
|
55
55
|
def process_requests(source_rewriter)
|
56
56
|
requests.each do |node, analysis_codes|
|
57
|
-
|
57
|
+
inject_analysis_code(node, analysis_codes, source_rewriter)
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
-
def
|
61
|
+
def inject_analysis_code(node, analysis_codes, source_rewriter)
|
62
62
|
front, rear = build_wrapper_codes(node, analysis_codes)
|
63
63
|
|
64
64
|
source_range = if (block_node = block_node_taken_by_method(node))
|
@@ -73,15 +73,8 @@ module Transpec
|
|
73
73
|
end
|
74
74
|
|
75
75
|
def build_wrapper_codes(node, analysis_codes)
|
76
|
-
source_range = node.loc.expression
|
77
|
-
|
78
76
|
front = "#{ANALYSIS_METHOD}(("
|
79
|
-
|
80
|
-
rear = format(
|
81
|
-
'), self, %s, __FILE__, %d, %d)',
|
82
|
-
hash_literal(analysis_codes), source_range.begin_pos, source_range.end_pos
|
83
|
-
)
|
84
|
-
|
77
|
+
rear = format('), self, %s, %s)', node_id(node).inspect, hash_literal(analysis_codes))
|
85
78
|
[front, rear]
|
86
79
|
end
|
87
80
|
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
+
require 'transpec/util'
|
3
4
|
require 'json'
|
4
5
|
require 'ostruct'
|
5
6
|
require 'pathname'
|
@@ -7,6 +8,8 @@ require 'pathname'
|
|
7
8
|
module Transpec
|
8
9
|
class DynamicAnalyzer
|
9
10
|
class RuntimeData
|
11
|
+
include Util
|
12
|
+
|
10
13
|
attr_reader :data
|
11
14
|
|
12
15
|
def self.load(string_or_io)
|
@@ -19,16 +22,21 @@ module Transpec
|
|
19
22
|
@data = data
|
20
23
|
end
|
21
24
|
|
22
|
-
def [](node)
|
23
|
-
|
25
|
+
def [](node, key = nil)
|
26
|
+
node_data = data[node_id(node)]
|
27
|
+
return nil unless node_data
|
28
|
+
return node_data unless key
|
29
|
+
node_data[key]
|
30
|
+
end
|
31
|
+
|
32
|
+
def run?(node)
|
33
|
+
!self[node].nil?
|
24
34
|
end
|
25
35
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
relative_path = Pathname.new(absolute_path).relative_path_from(Pathname.pwd).to_s
|
31
|
-
[relative_path, source_range.begin_pos, source_range.end_pos].join('_')
|
36
|
+
def present?(node, key)
|
37
|
+
node_data = self[node]
|
38
|
+
return false unless node_data
|
39
|
+
node_data.respond_to?(key)
|
32
40
|
end
|
33
41
|
|
34
42
|
class CompatibleOpenStruct < OpenStruct
|
data/lib/transpec/file_finder.rb
CHANGED