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
@@ -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
|