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
@@ -3,89 +3,95 @@
|
|
3
3
|
require 'transpec/syntax'
|
4
4
|
require 'transpec/syntax/mixin/send'
|
5
5
|
require 'transpec/rspec_dsl'
|
6
|
-
require 'transpec/util'
|
7
6
|
|
8
7
|
module Transpec
|
9
8
|
class Syntax
|
10
9
|
class Example < Syntax
|
11
|
-
include Mixin::Send, RSpecDSL
|
10
|
+
include Mixin::Send, RSpecDSL
|
12
11
|
|
13
|
-
|
12
|
+
def self.conversion_target_node?(node, runtime_data = nil)
|
13
|
+
return false unless target_node?(node, runtime_data)
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
15
|
+
# Check whether the context is example group to differenciate
|
16
|
+
# RSpec::Core::ExampleGroup.pending (a relative of #it) and
|
17
|
+
# RSpec::Core::ExampleGroup#pending (marks the example as pending in #it block).
|
18
|
+
if runtime_data && runtime_data.run?(node)
|
19
|
+
# If we have runtime data, check with it.
|
20
|
+
runtime_data[node, :example_group_context?]
|
21
|
+
else
|
22
|
+
# Otherwise check statically.
|
23
|
+
inspector = StaticContextInspector.new(node)
|
24
|
+
inspector.scopes.last == :example_group
|
25
|
+
end
|
21
26
|
end
|
22
27
|
|
23
28
|
def self.target_method?(receiver_node, method_name)
|
24
|
-
receiver_node.nil? &&
|
29
|
+
receiver_node.nil? && EXAMPLE_METHODS.include?(method_name)
|
25
30
|
end
|
26
31
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
replace(selector_range, block_arg_name.to_s) unless method_name == block_arg_name
|
31
|
-
block_node.metadata[:added_example_block_arg] = true
|
32
|
-
else
|
33
|
-
replace(selector_range, 'RSpec.current_example')
|
34
|
-
end
|
35
|
-
|
36
|
-
register_record
|
32
|
+
define_dynamic_analysis_request do |rewriter|
|
33
|
+
code = "is_a?(Class) && ancestors.any? { |a| a.name == 'RSpec::Core::ExampleGroup' }"
|
34
|
+
rewriter.register_request(node, :example_group_context?, code, :context)
|
37
35
|
end
|
38
36
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
block_arg_node || block_node.metadata[:added_example_block_arg]
|
37
|
+
def convert_pending_to_skip!
|
38
|
+
convert_pending_selector_to_skip!
|
39
|
+
convert_pending_metadata_to_skip!
|
43
40
|
end
|
44
41
|
|
45
|
-
def
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
42
|
+
def metadata_key_nodes
|
43
|
+
metadata_nodes.each_with_object([]) do |node, key_nodes|
|
44
|
+
if node.hash_type?
|
45
|
+
key_nodes.concat(node.children.map { |pair_node| pair_node.children.first })
|
46
|
+
else
|
47
|
+
key_nodes << node
|
48
|
+
end
|
52
49
|
end
|
53
50
|
end
|
54
51
|
|
55
|
-
|
56
|
-
method_name_of_block_node(block_node)
|
57
|
-
end
|
52
|
+
private
|
58
53
|
|
59
|
-
def
|
60
|
-
|
61
|
-
|
54
|
+
def convert_pending_selector_to_skip!
|
55
|
+
return unless method_name == :pending
|
56
|
+
replace(selector_range, 'skip')
|
57
|
+
register_record("pending 'is an example' { }", "skip 'is an example' { }")
|
62
58
|
end
|
63
59
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
60
|
+
def convert_pending_metadata_to_skip!
|
61
|
+
metadata_key_nodes.each do |node|
|
62
|
+
next unless pending_symbol?(node)
|
63
|
+
replace(symbol_range_without_colon(node), 'skip')
|
64
|
+
if node.parent_node.pair_type?
|
65
|
+
register_record("it 'is an example', :pending => value { }",
|
66
|
+
"it 'is an example', :skip => value { }")
|
67
|
+
else
|
68
|
+
register_record("it 'is an example', :pending { }",
|
69
|
+
"it 'is an example', :skip { }")
|
70
|
+
end
|
69
71
|
end
|
70
72
|
end
|
71
73
|
|
72
|
-
def
|
73
|
-
|
74
|
-
|
74
|
+
def pending_symbol?(node)
|
75
|
+
return false unless node.sym_type?
|
76
|
+
key = node.children.first
|
77
|
+
key == :pending
|
75
78
|
end
|
76
79
|
|
77
|
-
def
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
original_syntax = "#{prefix} { example }"
|
82
|
-
converted_syntax = "#{prefix} { |example| example }"
|
80
|
+
def symbol_range_without_colon(node)
|
81
|
+
range = node.loc.expression
|
82
|
+
if range.source.start_with?(':')
|
83
|
+
Parser::Source::Range.new(range.source_buffer, range.begin_pos + 1, range.end_pos)
|
83
84
|
else
|
84
|
-
|
85
|
-
converted_syntax = 'def helper_method RSpec.current_example; end'
|
85
|
+
range
|
86
86
|
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def metadata_nodes
|
90
|
+
arg_nodes[1..-1] || []
|
91
|
+
end
|
87
92
|
|
88
|
-
|
93
|
+
def register_record(original_syntax, converted_syntax)
|
94
|
+
report.records << Record.new(original_syntax, converted_syntax)
|
89
95
|
end
|
90
96
|
end
|
91
97
|
end
|
data/lib/transpec/syntax/have.rb
CHANGED
@@ -60,12 +60,12 @@ module Transpec
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def project_requires_collection_matcher?
|
63
|
-
runtime_subject_data
|
63
|
+
runtime_subject_data(:project_requires_collection_matcher?)
|
64
64
|
end
|
65
65
|
|
66
66
|
def collection_accessor
|
67
|
-
if runtime_subject_data
|
68
|
-
runtime_subject_data
|
67
|
+
if runtime_subject_data(:collection_accessor)
|
68
|
+
runtime_subject_data(:collection_accessor).to_sym
|
69
69
|
else
|
70
70
|
items_name
|
71
71
|
end
|
@@ -73,16 +73,15 @@ module Transpec
|
|
73
73
|
|
74
74
|
def subject_is_owner_of_collection?
|
75
75
|
return true if items_method_has_arguments?
|
76
|
-
|
76
|
+
!runtime_subject_data(:collection_accessor).nil?
|
77
77
|
end
|
78
78
|
|
79
79
|
def collection_accessor_is_private?
|
80
|
-
runtime_subject_data
|
80
|
+
runtime_subject_data(:collection_accessor_is_private?)
|
81
81
|
end
|
82
82
|
|
83
83
|
def query_method
|
84
|
-
if
|
85
|
-
available_query_methods = runtime_subject_data[:available_query_methods].result
|
84
|
+
if (available_query_methods = runtime_subject_data(:available_query_methods))
|
86
85
|
(QUERY_METHOD_PRIORITIES & available_query_methods.map(&:to_sym)).first
|
87
86
|
else
|
88
87
|
default_query_method
|
@@ -102,24 +101,37 @@ module Transpec
|
|
102
101
|
size_node.loc.expression.source
|
103
102
|
end
|
104
103
|
|
104
|
+
def accurate_conversion?
|
105
|
+
!runtime_subject_data.nil?
|
106
|
+
end
|
107
|
+
|
108
|
+
def matcher_range
|
109
|
+
expression_range.join(items_node.loc.expression)
|
110
|
+
end
|
111
|
+
|
105
112
|
private
|
106
113
|
|
107
114
|
def source_builder
|
108
115
|
@source_builder ||= SourceBuilder.new(self, size_source)
|
109
116
|
end
|
110
117
|
|
111
|
-
def runtime_subject_data
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
118
|
+
def runtime_subject_data(key = nil)
|
119
|
+
unless instance_variable_defined?(:@runtime_subject_data)
|
120
|
+
node = explicit_subject? ? expectation.subject_node : expectation.node
|
121
|
+
@runtime_subject_data = runtime_data[node]
|
122
|
+
end
|
116
123
|
|
117
|
-
|
118
|
-
|
124
|
+
return @runtime_subject_data unless key
|
125
|
+
|
126
|
+
if @runtime_subject_data
|
127
|
+
@runtime_subject_data[key]
|
128
|
+
else
|
129
|
+
nil
|
130
|
+
end
|
119
131
|
end
|
120
132
|
|
121
133
|
def register_record
|
122
|
-
|
134
|
+
report.records << HaveRecord.new(self)
|
123
135
|
end
|
124
136
|
end
|
125
137
|
end
|
@@ -28,6 +28,18 @@ module Transpec
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
+
def annotation
|
32
|
+
return @annotation if instance_variable_defined?(:@annotation)
|
33
|
+
|
34
|
+
@annotation = if have.accurate_conversion?
|
35
|
+
nil
|
36
|
+
else
|
37
|
+
AccuracyAnnotation.new(have.matcher_range)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
31
43
|
def build_expectation(subject, type)
|
32
44
|
case type
|
33
45
|
when :should
|
@@ -35,22 +35,6 @@ module Transpec
|
|
35
35
|
source << ".#{have.query_method}"
|
36
36
|
end
|
37
37
|
|
38
|
-
def base_subject_source(node)
|
39
|
-
if node.send_type? && (arg_node = node.children[2])
|
40
|
-
left_of_arg_source = node.loc.selector.end.join(arg_node.loc.expression.begin).source
|
41
|
-
|
42
|
-
if left_of_arg_source.match(/\A\s*\Z/)
|
43
|
-
source = node.loc.expression.begin.join(node.loc.selector.end).source
|
44
|
-
source << '('
|
45
|
-
source << arg_node.loc.expression.begin.join(node.loc.expression.end).source
|
46
|
-
source << ')'
|
47
|
-
return source
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
node.loc.expression.source
|
52
|
-
end
|
53
|
-
|
54
38
|
def replacement_matcher_source(parenthesize_arg = true)
|
55
39
|
case have.expectation.current_syntax_type
|
56
40
|
when :should
|
@@ -60,6 +44,24 @@ module Transpec
|
|
60
44
|
end
|
61
45
|
end
|
62
46
|
|
47
|
+
private
|
48
|
+
|
49
|
+
def base_subject_source(node)
|
50
|
+
map = node.loc
|
51
|
+
source = map.expression.source
|
52
|
+
|
53
|
+
if node.send_type? && (arg_node = node.children[2])
|
54
|
+
left_of_arg_range = map.selector.end.join(arg_node.loc.expression.begin)
|
55
|
+
unless left_of_arg_range.source.include?('(')
|
56
|
+
relative_index = left_of_arg_range.begin_pos - map.expression.begin_pos
|
57
|
+
source[relative_index, left_of_arg_range.length] = '('
|
58
|
+
source << ')'
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
source
|
63
|
+
end
|
64
|
+
|
63
65
|
def replacement_matcher_source_for_should
|
64
66
|
case have.method_name
|
65
67
|
when :have, :have_exactly then "== #{size_source}"
|
data/lib/transpec/syntax/its.rb
CHANGED
@@ -16,7 +16,7 @@ module Transpec
|
|
16
16
|
define_dynamic_analysis_request do |rewriter|
|
17
17
|
key = :project_requires_its?
|
18
18
|
code = 'defined?(RSpec::Its)'
|
19
|
-
rewriter.register_request(
|
19
|
+
rewriter.register_request(node, key, code, :context)
|
20
20
|
end
|
21
21
|
|
22
22
|
def convert_to_describe_subject_it!
|
@@ -42,12 +42,11 @@ module Transpec
|
|
42
42
|
alias_method :attribute_node, :arg_node
|
43
43
|
|
44
44
|
def block_node
|
45
|
-
|
45
|
+
node.parent_node
|
46
46
|
end
|
47
47
|
|
48
48
|
def project_requires_its?
|
49
|
-
|
50
|
-
node_data && node_data[:project_requires_its?].result
|
49
|
+
runtime_data[node, :project_requires_its?]
|
51
50
|
end
|
52
51
|
|
53
52
|
private
|
@@ -89,11 +88,11 @@ module Transpec
|
|
89
88
|
end
|
90
89
|
|
91
90
|
def base_indentation
|
92
|
-
@base_indentation ||= indentation_of_line(
|
91
|
+
@base_indentation ||= indentation_of_line(node)
|
93
92
|
end
|
94
93
|
|
95
94
|
def register_record
|
96
|
-
|
95
|
+
report.records << Record.new(original_syntax, converted_syntax)
|
97
96
|
end
|
98
97
|
|
99
98
|
def original_syntax
|
@@ -113,16 +112,18 @@ module Transpec
|
|
113
112
|
end
|
114
113
|
|
115
114
|
class AttributeExpression
|
115
|
+
attr_reader :node
|
116
|
+
|
116
117
|
def initialize(node)
|
117
118
|
@node = node
|
118
119
|
end
|
119
120
|
|
120
121
|
def brackets?
|
121
|
-
|
122
|
+
node.array_type?
|
122
123
|
end
|
123
124
|
|
124
125
|
def literal?
|
125
|
-
Util.literal?(
|
126
|
+
Util.literal?(node)
|
126
127
|
end
|
127
128
|
|
128
129
|
def attributes
|
@@ -136,20 +137,20 @@ module Transpec
|
|
136
137
|
private
|
137
138
|
|
138
139
|
def brackets_attributes
|
139
|
-
selector =
|
140
|
+
selector = node.loc.expression.source
|
140
141
|
description = literal? ? quote(selector) : selector
|
141
142
|
[Attribute.new(selector, description)]
|
142
143
|
end
|
143
144
|
|
144
145
|
def non_brackets_attributes
|
145
146
|
if literal?
|
146
|
-
expression =
|
147
|
+
expression = node.children.first.to_s
|
147
148
|
chained_names = expression.split('.')
|
148
149
|
chained_names.map do |name|
|
149
150
|
Attribute.new(".#{name}", quote("##{name}"))
|
150
151
|
end
|
151
152
|
else
|
152
|
-
source =
|
153
|
+
source = node.loc.expression.source
|
153
154
|
selector = ".send(#{source})"
|
154
155
|
[Attribute.new(selector, source)]
|
155
156
|
end
|
@@ -23,7 +23,7 @@ module Transpec
|
|
23
23
|
replacement_method_name = CONVERSION_CORRESPONDENCE[method_name].to_s
|
24
24
|
replace(selector_range, replacement_method_name)
|
25
25
|
|
26
|
-
|
26
|
+
report.records << Record.new("#{method_name} { }", "#{replacement_method_name} { }")
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
@@ -19,10 +19,6 @@ module Transpec
|
|
19
19
|
]
|
20
20
|
# rubocop:enable LineLength
|
21
21
|
|
22
|
-
def self.dynamic_analysis_target_node?(node)
|
23
|
-
target_node?(node)
|
24
|
-
end
|
25
|
-
|
26
22
|
def self.conversion_target_node?(node, runtime_data = nil)
|
27
23
|
return false unless check_target_node_statically(node)
|
28
24
|
|
@@ -64,7 +60,7 @@ module Transpec
|
|
64
60
|
return if method_name == :stub_chain && !rspec_version.receive_message_chain_available?
|
65
61
|
|
66
62
|
unless allow_to_receive_available?
|
67
|
-
fail ContextError.new(
|
63
|
+
fail ContextError.new("##{method_name}", '#allow', selector_range)
|
68
64
|
end
|
69
65
|
|
70
66
|
source, type = replacement_source_and_conversion_type(rspec_version)
|
@@ -121,7 +117,7 @@ module Transpec
|
|
121
117
|
hash_node.children.each_with_index do |pair_node, index|
|
122
118
|
key_node, value_node = *pair_node
|
123
119
|
expression = build_allow_to_receive(key_node, value_node, false)
|
124
|
-
expression.prepend(indentation_of_line(
|
120
|
+
expression.prepend(indentation_of_line(node)) if index > 0
|
125
121
|
expressions << expression
|
126
122
|
end
|
127
123
|
|
@@ -182,7 +178,7 @@ module Transpec
|
|
182
178
|
else
|
183
179
|
AllowRecord
|
184
180
|
end
|
185
|
-
|
181
|
+
report.records << record_class.new(self, conversion_type)
|
186
182
|
end
|
187
183
|
|
188
184
|
class AllowRecord < Record
|
@@ -25,7 +25,7 @@ module Transpec
|
|
25
25
|
return instance_variable_get(matcher_ivar_name)
|
26
26
|
end
|
27
27
|
|
28
|
-
if matcher_class.conversion_target_node?(matcher_node,
|
28
|
+
if matcher_class.conversion_target_node?(matcher_node, runtime_data)
|
29
29
|
instance_variable_set(matcher_ivar_name, send(matcher_creator_name))
|
30
30
|
else
|
31
31
|
instance_variable_set(matcher_ivar_name, nil)
|
@@ -33,7 +33,7 @@ module Transpec
|
|
33
33
|
end
|
34
34
|
|
35
35
|
define_method(matcher_creator_name) do
|
36
|
-
matcher_class.new(matcher_node, self,
|
36
|
+
matcher_class.new(matcher_node, self, source_rewriter, runtime_data, report)
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|