transpec 1.9.3 → 1.10.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/.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