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
data/lib/transpec/git.rb
CHANGED
@@ -18,6 +18,7 @@ module Transpec
|
|
18
18
|
stub: :convert_stub=,
|
19
19
|
have_items: :convert_have_items=,
|
20
20
|
its: :convert_its=,
|
21
|
+
pending: :convert_pending=,
|
21
22
|
deprecated: :convert_deprecated_method=
|
22
23
|
}
|
23
24
|
|
@@ -51,27 +52,27 @@ module Transpec
|
|
51
52
|
@parser = create_parser
|
52
53
|
|
53
54
|
define_option('-f', '--force') do
|
54
|
-
|
55
|
+
configuration.forced = true
|
55
56
|
end
|
56
57
|
|
57
58
|
define_option('-s', '--skip-dynamic-analysis') do
|
58
|
-
|
59
|
+
configuration.skip_dynamic_analysis = true
|
59
60
|
end
|
60
61
|
|
61
62
|
define_option('-c', '--rspec-command COMMAND') do |command|
|
62
|
-
|
63
|
+
configuration.rspec_command = command
|
63
64
|
end
|
64
65
|
|
65
66
|
define_option('-k', '--keep TYPE[,TYPE...]') do |types|
|
66
67
|
types.split(',').each do |type|
|
67
68
|
config_attr = CONFIG_ATTRS_FOR_KEEP_TYPES[type.to_sym]
|
68
69
|
fail ArgumentError, "Unknown syntax type #{type.inspect}" unless config_attr
|
69
|
-
|
70
|
+
configuration.send(config_attr, false)
|
70
71
|
end
|
71
72
|
end
|
72
73
|
|
73
74
|
define_option('-n', '--negative-form FORM') do |form|
|
74
|
-
|
75
|
+
configuration.negative_form_of_to = form
|
75
76
|
end
|
76
77
|
|
77
78
|
define_option('-b', '--boolean-matcher TYPE') do |type|
|
@@ -79,20 +80,20 @@ module Transpec
|
|
79
80
|
types = VALID_BOOLEAN_MATCHER_TYPES.map(&:inspect).join(', ')
|
80
81
|
fail ArgumentError, "Boolean matcher type must be any of #{types}"
|
81
82
|
end
|
82
|
-
|
83
|
-
|
83
|
+
configuration.boolean_matcher_type = type.include?('truthy') ? :conditional : :exact
|
84
|
+
configuration.form_of_be_falsey = type.include?('falsy') ? 'be_falsy' : 'be_falsey'
|
84
85
|
end
|
85
86
|
|
86
87
|
define_option('-a', '--no-yield-any-instance') do
|
87
|
-
|
88
|
+
configuration.add_receiver_arg_to_any_instance_implementation_block = false
|
88
89
|
end
|
89
90
|
|
90
91
|
define_option('-t', '--convert-stub-with-hash') do
|
91
|
-
|
92
|
+
configuration.convert_stub_with_hash_to_stub_and_return = true
|
92
93
|
end
|
93
94
|
|
94
95
|
define_option('-p', '--no-parentheses-matcher-arg') do
|
95
|
-
|
96
|
+
configuration.parenthesize_matcher_arg = false
|
96
97
|
end
|
97
98
|
|
98
99
|
define_option('--no-color') do
|
@@ -145,6 +146,7 @@ module Transpec
|
|
145
146
|
" #{'stub'.bright} (to #{'allow(obj).to receive'.underline})",
|
146
147
|
" #{'have_items'.bright} (to #{'expect(obj.size).to eq(n)'.underline})",
|
147
148
|
" #{'its'.bright} (to #{'describe { subject { }; it { } }'.underline})",
|
149
|
+
" #{'pending'.bright} (to #{'skip'.underline})",
|
148
150
|
" #{'deprecated'.bright} (e.g. from #{'mock'.underline} to #{'double'.underline})",
|
149
151
|
'These are all converted by default.'
|
150
152
|
],
|
data/lib/transpec/project.rb
CHANGED
@@ -12,11 +12,11 @@ module Transpec
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def basename
|
15
|
-
File.basename(
|
15
|
+
File.basename(path)
|
16
16
|
end
|
17
17
|
|
18
18
|
def require_bundler?
|
19
|
-
gemfile_path = File.join(
|
19
|
+
gemfile_path = File.join(path, 'Gemfile')
|
20
20
|
File.exist?(gemfile_path)
|
21
21
|
end
|
22
22
|
|
@@ -44,7 +44,7 @@ module Transpec
|
|
44
44
|
|
45
45
|
output = nil
|
46
46
|
|
47
|
-
Dir.chdir(
|
47
|
+
Dir.chdir(path) do
|
48
48
|
with_bundler_clean_env do
|
49
49
|
IO.popen(command) do |io|
|
50
50
|
output = io.read
|
data/lib/transpec/record.rb
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
+
require 'transpec/annotatable'
|
4
|
+
|
3
5
|
module Transpec
|
4
6
|
class Record
|
5
|
-
attr_reader :original_syntax, :converted_syntax
|
7
|
+
attr_reader :original_syntax, :converted_syntax, :annotation
|
6
8
|
|
7
|
-
def initialize(original_syntax, converted_syntax)
|
9
|
+
def initialize(original_syntax, converted_syntax, annotation = nil)
|
8
10
|
@original_syntax = original_syntax
|
9
11
|
@converted_syntax = converted_syntax
|
12
|
+
@annotation = annotation
|
10
13
|
end
|
11
14
|
|
12
15
|
def ==(other)
|
@@ -25,4 +28,18 @@ module Transpec
|
|
25
28
|
"`#{original_syntax}` -> `#{converted_syntax}`"
|
26
29
|
end
|
27
30
|
end
|
31
|
+
|
32
|
+
class Annotation
|
33
|
+
include Annotatable
|
34
|
+
end
|
35
|
+
|
36
|
+
class AccuracyAnnotation < Annotation
|
37
|
+
def initialize(source_range)
|
38
|
+
message = "The `#{source_range.source}` has been converted " \
|
39
|
+
'but it might possibly be incorrect ' \
|
40
|
+
'due to a lack of runtime information. ' \
|
41
|
+
"It's recommended to review the change carefully."
|
42
|
+
super(message, source_range)
|
43
|
+
end
|
44
|
+
end
|
28
45
|
end
|
data/lib/transpec/report.rb
CHANGED
@@ -4,14 +4,21 @@ require 'rainbow'
|
|
4
4
|
|
5
5
|
module Transpec
|
6
6
|
class Report
|
7
|
-
attr_reader :records, :
|
7
|
+
attr_reader :records, :conversion_errors, :syntax_errors
|
8
8
|
|
9
9
|
def initialize
|
10
10
|
@records = []
|
11
|
-
@
|
11
|
+
@conversion_errors = []
|
12
12
|
@syntax_errors = []
|
13
13
|
end
|
14
14
|
|
15
|
+
def <<(other)
|
16
|
+
records.concat(other.records)
|
17
|
+
conversion_errors.concat(other.conversion_errors)
|
18
|
+
syntax_errors.concat(other.syntax_errors)
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
15
22
|
def unique_record_counts
|
16
23
|
record_counts = Hash.new(0)
|
17
24
|
|
@@ -40,7 +47,15 @@ module Transpec
|
|
40
47
|
end
|
41
48
|
|
42
49
|
def colored_stats
|
43
|
-
|
50
|
+
base_color = if !conversion_errors.empty?
|
51
|
+
:magenta
|
52
|
+
elsif annotation_count.nonzero?
|
53
|
+
:yellow
|
54
|
+
else
|
55
|
+
:green
|
56
|
+
end
|
57
|
+
|
58
|
+
convertion_incomplete_caution_stats(base_color) + error_stats(base_color)
|
44
59
|
end
|
45
60
|
|
46
61
|
def stats
|
@@ -78,21 +93,18 @@ module Transpec
|
|
78
93
|
text << indentation + ' ' + colorize('to: ', :cyan) + record.converted_syntax + "\n"
|
79
94
|
end
|
80
95
|
|
81
|
-
def
|
82
|
-
color = context_errors.empty? ? :green : :yellow
|
83
|
-
|
96
|
+
def convertion_incomplete_caution_stats(color)
|
84
97
|
text = pluralize(records.count, 'conversion') + ', '
|
85
|
-
text << pluralize(
|
98
|
+
text << pluralize(conversion_errors.count, 'incomplete') + ', '
|
99
|
+
text << pluralize(annotation_count, 'caution') + ', '
|
86
100
|
colorize(text, color)
|
87
101
|
end
|
88
102
|
|
89
|
-
def error_stats
|
90
|
-
color = if
|
91
|
-
|
92
|
-
elsif context_errors.empty?
|
93
|
-
:green
|
103
|
+
def error_stats(base_color)
|
104
|
+
color = if syntax_errors.empty?
|
105
|
+
base_color
|
94
106
|
else
|
95
|
-
:
|
107
|
+
:red
|
96
108
|
end
|
97
109
|
|
98
110
|
colorize(pluralize(syntax_errors.count, 'error'), color)
|
@@ -112,5 +124,9 @@ module Transpec
|
|
112
124
|
|
113
125
|
text
|
114
126
|
end
|
127
|
+
|
128
|
+
def annotation_count
|
129
|
+
records.count(&:annotation)
|
130
|
+
end
|
115
131
|
end
|
116
132
|
end
|
@@ -34,27 +34,27 @@ module Transpec
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def <=>(other)
|
37
|
-
|
37
|
+
gem_version <=> other.gem_version
|
38
38
|
end
|
39
39
|
|
40
40
|
def to_s
|
41
|
-
|
41
|
+
gem_version.to_s
|
42
42
|
end
|
43
43
|
|
44
44
|
define_feature :be_truthy, '2.99.0.beta1'
|
45
45
|
define_feature :yielded_example, '2.99.0.beta1'
|
46
46
|
define_feature :yielding_receiver_to_any_instance_implementation_block, '2.99.0.beta1'
|
47
47
|
define_feature :oneliner_is_expected, '2.99.0.beta2', except: '3.0.0.beta1'
|
48
|
+
define_feature :skip, '2.99.0.beta2', except: '3.0.0.beta1'
|
48
49
|
define_feature :receive_messages, '3.0.0.beta1'
|
49
50
|
define_feature :receive_message_chain, '3.0.0.beta2'
|
50
51
|
define_feature :non_should_matcher_protocol, '3.0.0.beta2'
|
51
52
|
|
52
|
-
|
53
|
-
|
53
|
+
RSPEC_2_99 = new('2.99.0.beta1')
|
54
|
+
RSPEC_3_0 = new('3.0.0.beta1')
|
54
55
|
|
55
|
-
def
|
56
|
-
self
|
57
|
-
self < ANY_INSTANCE_IMPLEMENTATION_BLOCK_MIGRATION_EXCLUSIVE_END
|
56
|
+
def rspec_2_99?
|
57
|
+
RSPEC_2_99 <= self && self < RSPEC_3_0
|
58
58
|
end
|
59
59
|
end
|
60
60
|
end
|
@@ -48,10 +48,6 @@ module Transpec
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
-
def inside_of_example_group?
|
52
|
-
scopes.include?(:example_group)
|
53
|
-
end
|
54
|
-
|
55
51
|
def non_monkey_patch_expectation_available?
|
56
52
|
return @expectation_available if instance_variable_defined?(:@expectation_available)
|
57
53
|
@expectation_available = match_scopes(NON_MONKEY_PATCH_EXPECTATION_AVAILABLE_CONTEXT)
|
@@ -72,7 +68,7 @@ module Transpec
|
|
72
68
|
def valid_ancestor_nodes
|
73
69
|
valid_nodes = []
|
74
70
|
|
75
|
-
self_and_ancestor_nodes = [
|
71
|
+
self_and_ancestor_nodes = [node] + node.ancestor_nodes
|
76
72
|
|
77
73
|
self_and_ancestor_nodes.each_cons(2) do |child, parent|
|
78
74
|
valid_nodes << parent unless belong_to_direct_outer_scope?(child)
|
data/lib/transpec/syntax.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
|
-
require 'transpec/
|
4
|
-
require 'transpec/
|
3
|
+
require 'transpec/conversion_error'
|
4
|
+
require 'transpec/dynamic_analyzer/runtime_data'
|
5
5
|
require 'transpec/record'
|
6
6
|
require 'transpec/report'
|
7
|
+
require 'transpec/static_context_inspector'
|
7
8
|
require 'active_support/concern'
|
8
9
|
|
9
10
|
module Transpec
|
@@ -37,19 +38,19 @@ module Transpec
|
|
37
38
|
private
|
38
39
|
|
39
40
|
def remove(range)
|
40
|
-
|
41
|
+
source_rewriter.remove(range)
|
41
42
|
end
|
42
43
|
|
43
44
|
def insert_before(range, content)
|
44
|
-
|
45
|
+
source_rewriter.insert_before(range, content)
|
45
46
|
end
|
46
47
|
|
47
48
|
def insert_after(range, content)
|
48
|
-
|
49
|
+
source_rewriter.insert_after(range, content)
|
49
50
|
end
|
50
51
|
|
51
52
|
def replace(range, content)
|
52
|
-
|
53
|
+
source_rewriter.replace(range, content)
|
53
54
|
end
|
54
55
|
end
|
55
56
|
end
|
@@ -114,26 +115,20 @@ module Transpec
|
|
114
115
|
def initialize(node, source_rewriter = nil, runtime_data = nil, report = nil)
|
115
116
|
@node = node
|
116
117
|
@source_rewriter = source_rewriter
|
117
|
-
@runtime_data = runtime_data
|
118
|
+
@runtime_data = runtime_data || DynamicAnalyzer::RuntimeData.new
|
118
119
|
@report = report || Report.new
|
119
120
|
end
|
120
121
|
|
121
122
|
def static_context_inspector
|
122
|
-
@static_context_inspector ||= StaticContextInspector.new(
|
123
|
+
@static_context_inspector ||= StaticContextInspector.new(node)
|
123
124
|
end
|
124
125
|
|
125
126
|
def parent_node
|
126
|
-
|
127
|
+
node.parent_node
|
127
128
|
end
|
128
129
|
|
129
130
|
def expression_range
|
130
|
-
|
131
|
-
end
|
132
|
-
|
133
|
-
private
|
134
|
-
|
135
|
-
def runtime_node_data(node)
|
136
|
-
@runtime_data && @runtime_data[node]
|
131
|
+
node.loc.expression
|
137
132
|
end
|
138
133
|
end
|
139
134
|
end
|
@@ -29,7 +29,7 @@ module Transpec
|
|
29
29
|
private
|
30
30
|
|
31
31
|
def register_record
|
32
|
-
|
32
|
+
report.records << Record.new('be_close(expected, delta)', 'be_within(delta).of(expected)')
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'transpec/syntax'
|
4
|
+
require 'transpec/syntax/mixin/send'
|
5
|
+
require 'transpec/rspec_dsl'
|
6
|
+
require 'transpec/util'
|
7
|
+
|
8
|
+
module Transpec
|
9
|
+
class Syntax
|
10
|
+
class CurrentExample < Syntax
|
11
|
+
include Mixin::Send, RSpecDSL, Util
|
12
|
+
|
13
|
+
METHODS_YIELD_EXAMPLE = (EXAMPLE_METHODS + HOOK_METHODS + HELPER_METHODS).freeze
|
14
|
+
|
15
|
+
def self.check_target_node_statically(node)
|
16
|
+
super(node) && Util.block_node_taken_by_method(node).nil?
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.target_method?(receiver_node, method_name)
|
20
|
+
receiver_node.nil? && [:example, :running_example].include?(method_name)
|
21
|
+
end
|
22
|
+
|
23
|
+
def convert!
|
24
|
+
if block_node
|
25
|
+
insert_after(block_node.loc.begin, " |#{block_arg_name}|") unless block_has_argument?
|
26
|
+
replace(selector_range, block_arg_name.to_s) unless method_name == block_arg_name
|
27
|
+
block_node.metadata[:added_example_block_arg] = true
|
28
|
+
else
|
29
|
+
replace(selector_range, 'RSpec.current_example')
|
30
|
+
end
|
31
|
+
|
32
|
+
register_record
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def block_has_argument?
|
38
|
+
block_arg_node || block_node.metadata[:added_example_block_arg]
|
39
|
+
end
|
40
|
+
|
41
|
+
def block_node
|
42
|
+
return @block_node if instance_variable_defined?(:@block_node)
|
43
|
+
|
44
|
+
@block_node ||= node.each_ancestor_node.find do |ancestor_node|
|
45
|
+
next false unless ancestor_node.block_type?
|
46
|
+
method_name = method_name_of_block_node(ancestor_node)
|
47
|
+
METHODS_YIELD_EXAMPLE.include?(method_name)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def block_method_name
|
52
|
+
method_name_of_block_node(block_node)
|
53
|
+
end
|
54
|
+
|
55
|
+
def block_arg_node
|
56
|
+
args_node = block_node.children[1]
|
57
|
+
args_node.children.first
|
58
|
+
end
|
59
|
+
|
60
|
+
def block_arg_name
|
61
|
+
if block_arg_node
|
62
|
+
block_arg_node.children.first
|
63
|
+
else
|
64
|
+
:example
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def method_name_of_block_node(block_node)
|
69
|
+
send_node = block_node.children.first
|
70
|
+
send_node.children[1]
|
71
|
+
end
|
72
|
+
|
73
|
+
def register_record
|
74
|
+
if block_node
|
75
|
+
prefix = "#{block_method_name}"
|
76
|
+
prefix << '(:name)' if HELPER_METHODS.include?(block_method_name)
|
77
|
+
original_syntax = "#{prefix} { example }"
|
78
|
+
converted_syntax = "#{prefix} { |example| example }"
|
79
|
+
else
|
80
|
+
original_syntax = 'def helper_method example; end'
|
81
|
+
converted_syntax = 'def helper_method RSpec.current_example; end'
|
82
|
+
end
|
83
|
+
|
84
|
+
report.records << Record.new(original_syntax, converted_syntax)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|