transpec 1.10.4 → 1.11.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 +3 -3
- data/CHANGELOG.md +9 -0
- data/README.md +96 -18
- data/README.md.erb +117 -51
- data/lib/transpec/base_rewriter.rb +25 -28
- data/lib/transpec/cli.rb +27 -14
- data/lib/transpec/configuration.rb +2 -1
- data/lib/transpec/converter.rb +54 -32
- data/lib/transpec/dynamic_analyzer/helper.rb.erb +44 -0
- data/lib/transpec/dynamic_analyzer/node_util.rb +17 -0
- data/lib/transpec/dynamic_analyzer/rewriter.rb +12 -4
- data/lib/transpec/dynamic_analyzer/runtime_data.rb +3 -4
- data/lib/transpec/dynamic_analyzer.rb +14 -52
- data/lib/transpec/option_parser.rb +89 -81
- data/lib/transpec/processed_source.rb +48 -0
- data/lib/transpec/record.rb +2 -2
- data/lib/transpec/report.rb +5 -1
- data/lib/transpec/rspec_dsl.rb +12 -2
- data/lib/transpec/rspec_version.rb +8 -7
- data/lib/transpec/spec_suite.rb +114 -0
- data/lib/transpec/syntax/example.rb +4 -20
- data/lib/transpec/syntax/example_group.rb +38 -0
- data/lib/transpec/syntax/have.rb +6 -9
- data/lib/transpec/syntax/its.rb +5 -7
- data/lib/transpec/syntax/method_stub.rb +12 -13
- data/lib/transpec/syntax/mixin/any_instance_block.rb +14 -6
- data/lib/transpec/syntax/mixin/context_sensitive.rb +41 -0
- data/lib/transpec/syntax/mixin/matcher_owner.rb +16 -26
- data/lib/transpec/syntax/mixin/monkey_patch_any_instance.rb +1 -1
- data/lib/transpec/syntax/mixin/no_message_allowance.rb +2 -2
- data/lib/transpec/syntax/mixin/useless_and_return.rb +2 -2
- data/lib/transpec/syntax/oneliner_should.rb +9 -13
- data/lib/transpec/syntax/operator.rb +3 -7
- data/lib/transpec/syntax/pending.rb +4 -20
- data/lib/transpec/syntax/rspec_configure/configuration_modification.rb +86 -0
- data/lib/transpec/syntax/rspec_configure/framework.rb +45 -86
- data/lib/transpec/syntax/rspec_configure.rb +18 -6
- data/lib/transpec/syntax/should.rb +3 -5
- data/lib/transpec/syntax/should_receive.rb +1 -1
- data/lib/transpec/syntax.rb +8 -0
- data/lib/transpec/util.rb +0 -8
- data/lib/transpec/version.rb +2 -2
- data/spec/acceptance/configuration_modification_spec.rb +132 -0
- data/spec/acceptance/conversion_spec.rb +114 -0
- data/spec/support/shared_context.rb +6 -12
- data/spec/transpec/cli_spec.rb +21 -23
- data/spec/transpec/configuration_spec.rb +2 -1
- data/spec/transpec/converter_spec.rb +292 -213
- data/spec/transpec/dynamic_analyzer/rewriter_spec.rb +3 -3
- data/spec/transpec/dynamic_analyzer_spec.rb +8 -2
- data/spec/transpec/option_parser_spec.rb +42 -4
- data/spec/transpec/processed_source_spec.rb +67 -0
- data/spec/transpec/rspec_version_spec.rb +8 -2
- data/spec/transpec/spec_suite_spec.rb +107 -0
- data/spec/transpec/syntax/allow_spec.rb +9 -27
- data/spec/transpec/syntax/example_group_spec.rb +172 -0
- data/spec/transpec/syntax/expect_spec.rb +18 -54
- data/spec/transpec/syntax/have_spec.rb +35 -14
- data/spec/transpec/syntax/its_spec.rb +27 -7
- data/spec/transpec/syntax/method_stub_spec.rb +31 -8
- data/spec/transpec/syntax/oneliner_should_spec.rb +22 -131
- data/spec/transpec/syntax/rspec_configure_spec.rb +118 -15
- data/spec/transpec/syntax/should_spec.rb +51 -82
- data/tasks/fixtures/guard/COMMIT_EDITMSG +80 -0
- data/tasks/fixtures/mail/COMMIT_EDITMSG +84 -0
- data/tasks/fixtures/twitter/COMMIT_EDITMSG +36 -0
- data/tasks/lib/transpec_test.rb +23 -2
- data/tasks/readme.rake +35 -0
- metadata +22 -4
- data/lib/transpec/parser.rb +0 -9
@@ -7,10 +7,8 @@ require 'optparse'
|
|
7
7
|
require 'rainbow'
|
8
8
|
require 'rainbow/ext/string' unless String.respond_to?(:color)
|
9
9
|
|
10
|
-
# rubocop:disable ClassLength
|
11
|
-
|
12
10
|
module Transpec
|
13
|
-
class OptionParser
|
11
|
+
class OptionParser # rubocop:disable ClassLength
|
14
12
|
CONFIG_ATTRS_FOR_KEEP_TYPES = {
|
15
13
|
should: :convert_should=,
|
16
14
|
oneliner: :convert_oneliner=,
|
@@ -22,6 +20,11 @@ module Transpec
|
|
22
20
|
deprecated: :convert_deprecated_method=
|
23
21
|
}
|
24
22
|
|
23
|
+
CONFIG_ATTRS_FOR_CONVERT_TYPES = {
|
24
|
+
stub_with_hash: :convert_stub_with_hash_to_allow_to_receive_and_return=,
|
25
|
+
example_group: :convert_example_group=
|
26
|
+
}
|
27
|
+
|
25
28
|
VALID_BOOLEAN_MATCHER_TYPES = %w(truthy,falsey truthy,falsy true,false)
|
26
29
|
|
27
30
|
attr_reader :configuration
|
@@ -36,7 +39,7 @@ module Transpec
|
|
36
39
|
end
|
37
40
|
|
38
41
|
def parse(args)
|
39
|
-
args =
|
42
|
+
args = convert_deprecated_options(args)
|
40
43
|
@parser.parse!(args)
|
41
44
|
args
|
42
45
|
end
|
@@ -47,28 +50,27 @@ module Transpec
|
|
47
50
|
|
48
51
|
private
|
49
52
|
|
50
|
-
# rubocop:disable MethodLength
|
51
|
-
def setup_parser
|
53
|
+
def setup_parser # rubocop:disable MethodLength
|
52
54
|
@parser = create_parser
|
53
55
|
|
54
56
|
define_option('-f', '--force') do
|
55
57
|
configuration.forced = true
|
56
58
|
end
|
57
59
|
|
58
|
-
define_option('-s', '--skip-dynamic-analysis') do
|
59
|
-
configuration.skip_dynamic_analysis = true
|
60
|
-
end
|
61
|
-
|
62
60
|
define_option('-c', '--rspec-command COMMAND') do |command|
|
63
61
|
configuration.rspec_command = command
|
64
62
|
end
|
65
63
|
|
66
64
|
define_option('-k', '--keep TYPE[,TYPE...]') do |types|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
65
|
+
configure_conversion(CONFIG_ATTRS_FOR_KEEP_TYPES, types, false)
|
66
|
+
end
|
67
|
+
|
68
|
+
define_option('-v', '--convert TYPE[,TYPE...]') do |types|
|
69
|
+
configure_conversion(CONFIG_ATTRS_FOR_CONVERT_TYPES, types, true)
|
70
|
+
end
|
71
|
+
|
72
|
+
define_option('-s', '--skip-dynamic-analysis') do
|
73
|
+
configuration.skip_dynamic_analysis = true
|
72
74
|
end
|
73
75
|
|
74
76
|
define_option('-n', '--negative-form FORM') do |form|
|
@@ -88,10 +90,6 @@ module Transpec
|
|
88
90
|
configuration.add_receiver_arg_to_any_instance_implementation_block = false
|
89
91
|
end
|
90
92
|
|
91
|
-
define_option('-t', '--convert-stub-with-hash') do
|
92
|
-
configuration.convert_stub_with_hash_to_stub_and_return = true
|
93
|
-
end
|
94
|
-
|
95
93
|
define_option('-p', '--no-parentheses-matcher-arg') do
|
96
94
|
configuration.parenthesize_matcher_arg = false
|
97
95
|
end
|
@@ -105,7 +103,6 @@ module Transpec
|
|
105
103
|
exit
|
106
104
|
end
|
107
105
|
end
|
108
|
-
# rubocop:enable MethodLength
|
109
106
|
|
110
107
|
def create_parser
|
111
108
|
banner = "Usage: transpec [options] [files or directories]\n\n"
|
@@ -116,81 +113,72 @@ module Transpec
|
|
116
113
|
|
117
114
|
def define_option(*options, &block)
|
118
115
|
description_lines = descriptions[options.first]
|
116
|
+
description_lines = description_lines.map { |line| highlight_text(line) }
|
119
117
|
@parser.on(*options, *description_lines, &block)
|
120
118
|
end
|
121
119
|
|
122
|
-
# rubocop:disable
|
123
|
-
def descriptions
|
120
|
+
# rubocop:disable AlignHash
|
121
|
+
def descriptions # rubocop:disable MethodLength
|
124
122
|
@descriptions ||= {
|
125
123
|
'-f' => [
|
126
|
-
'Force processing even if the current Git'
|
127
|
-
'repository is not clean.'
|
124
|
+
'Force processing even if the current Git repository is not clean.'
|
128
125
|
],
|
129
126
|
'-s' => [
|
130
|
-
'Skip dynamic analysis and convert with only',
|
131
|
-
'
|
132
|
-
'option decreases the conversion accuracy.'
|
127
|
+
'Skip dynamic analysis and convert with only static analysis. Note',
|
128
|
+
'that specifying this option decreases the conversion accuracy.'
|
133
129
|
],
|
134
130
|
'-c' => [
|
135
|
-
'Specify a command to run your specs that is',
|
136
|
-
'
|
131
|
+
'Specify a command to run your specs that is used for dynamic',
|
132
|
+
'analysis.',
|
137
133
|
'Default: "bundle exec rspec"'
|
138
134
|
],
|
139
135
|
'-k' => [
|
140
|
-
'Keep specific syntaxes by disabling',
|
141
|
-
'
|
142
|
-
'
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
"
|
148
|
-
|
149
|
-
|
150
|
-
" #{'deprecated'.bright} (e.g. from #{'mock'.underline} to #{'double'.underline})",
|
136
|
+
'Keep specific syntaxes by disabling conversions.',
|
137
|
+
'Conversion Types:',
|
138
|
+
' *should* (to `expect(obj).to`)',
|
139
|
+
' *oneliner* (from `it { should ... }` to `it { is_expected.to ... }`)',
|
140
|
+
' *should_receive* (to `expect(obj).to receive`)',
|
141
|
+
' *stub* (to `allow(obj).to receive`)',
|
142
|
+
' *have_items* (to `expect(collection.size).to eq(n)`)',
|
143
|
+
" *its* (to `describe '#attr' { subject { }; it { } }`)",
|
144
|
+
' *pending* (to `skip`)',
|
145
|
+
' *deprecated* (all other deprecated syntaxes to latest syntaxes)',
|
151
146
|
'These are all converted by default.'
|
152
147
|
],
|
148
|
+
'-v' => [
|
149
|
+
'Enable specific conversions that are disabled by default.',
|
150
|
+
'Conversion Types:',
|
151
|
+
' *stub_with_hash* (`obj.stub(:msg => val)` to',
|
152
|
+
' `allow(obj).to receive(:msg).and_return(val)`)',
|
153
|
+
'These conversions are disabled by default.'
|
154
|
+
],
|
153
155
|
'-n' => [
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
"Default: #{'not_to'.bright}"
|
156
|
+
'Specify a negative form of `to` that is used in the `expect(...).to`',
|
157
|
+
'syntax. Either *not_to* or *to_not*.',
|
158
|
+
'Default: *not_to*'
|
158
159
|
],
|
159
160
|
'-b' => [
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
161
|
+
'Specify a matcher type that `be_true` and `be_false` will be',
|
162
|
+
'converted to.',
|
163
|
+
' *truthy,falsey* (conditional semantics)',
|
164
|
+
' *truthy,falsy* (alias of `falsey`)',
|
165
|
+
' *true,false* (exact equality)',
|
166
|
+
'Default: *truthy,falsey*'
|
166
167
|
],
|
167
168
|
'-a' => [
|
168
|
-
'Suppress yielding receiver instances to',
|
169
|
-
|
170
|
-
'first block argument.'
|
171
|
-
],
|
172
|
-
'-t' => [
|
173
|
-
"Enable conversion of #{'obj.stub(:msg => val)'.underline} to",
|
174
|
-
"#{'allow(obj).to receive(:msg).and_return(val)'.underline}",
|
175
|
-
"when #{'receive_messages(:msg => val)'.underline} is",
|
176
|
-
'unavailable (prior to RSpec 3.0). It will be',
|
177
|
-
'converted to multiple statements if the hash',
|
178
|
-
'includes multiple pairs. This conversion is',
|
179
|
-
'disabled by default.'
|
169
|
+
'Suppress yielding receiver instances to `any_instance`',
|
170
|
+
'implementation blocks as the first block argument.'
|
180
171
|
],
|
181
172
|
'-p' => [
|
182
|
-
'Suppress parenthesizing arguments of matchers',
|
183
|
-
|
184
|
-
|
185
|
-
'
|
186
|
-
'
|
187
|
-
'
|
188
|
-
'
|
189
|
-
'
|
190
|
-
'
|
191
|
-
" #{'== 10'.underline} to #{'eq(10)'.underline}",
|
192
|
-
" #{'=~ /pattern/'.underline} to #{'match(/pattern/)'.underline}",
|
193
|
-
" #{'=~ [1, 2]'.underline} to #{'match_array([1, 2])'.underline}"
|
173
|
+
'Suppress parenthesizing arguments of matchers when converting',
|
174
|
+
'`should` with operator matcher to `expect` with non-operator matcher.',
|
175
|
+
'Note that it will be parenthesized even if this option is',
|
176
|
+
'specified when parentheses are necessary to keep the meaning of',
|
177
|
+
'the expression. By default, arguments of the following operator',
|
178
|
+
'matchers will be parenthesized.',
|
179
|
+
' `== 10` to `eq(10)`',
|
180
|
+
' `=~ /pattern/` to `match(/pattern/)`',
|
181
|
+
' `=~ [1, 2]` to `match_array([1, 2])`'
|
194
182
|
],
|
195
183
|
'--no-color' => [
|
196
184
|
'Disable color in the output.'
|
@@ -200,19 +188,39 @@ module Transpec
|
|
200
188
|
]
|
201
189
|
}
|
202
190
|
end
|
203
|
-
# rubocop:enable
|
191
|
+
# rubocop:enable AlignHash
|
192
|
+
|
193
|
+
def highlight_text(text)
|
194
|
+
text.gsub(/`.+?`/) { |code| code.gsub('`', '').underline }
|
195
|
+
.gsub(/\*.+?\*/) { |code| code.gsub('*', '').bright }
|
196
|
+
end
|
204
197
|
|
205
|
-
def
|
206
|
-
|
198
|
+
def convert_deprecated_options(raw_args)
|
199
|
+
raw_args.each_with_object([]) do |arg, args|
|
207
200
|
case arg
|
208
201
|
when '-m', '--generate-commit-message'
|
209
|
-
|
210
|
-
|
211
|
-
|
202
|
+
deprecate('-m/--generate-commit-message option')
|
203
|
+
when '-t', '--convert-stub-with-hash'
|
204
|
+
deprecate('-t/--convert-stub-with-hash', '`--convert stub_with_hash`')
|
205
|
+
args.concat(%w(--convert stub_with_hash))
|
212
206
|
else
|
213
|
-
|
207
|
+
args << arg
|
214
208
|
end
|
215
209
|
end
|
216
210
|
end
|
211
|
+
|
212
|
+
def deprecate(subject, alternative = nil)
|
213
|
+
message = "DEPRECATION: #{subject} is deprecated."
|
214
|
+
message << " Please use #{alternative} instead." if alternative
|
215
|
+
warn message
|
216
|
+
end
|
217
|
+
|
218
|
+
def configure_conversion(type_to_attr_map, inputted_types, boolean)
|
219
|
+
inputted_types.split(',').each do |type|
|
220
|
+
config_attr = type_to_attr_map[type.to_sym]
|
221
|
+
fail ArgumentError, "Unknown syntax type #{type.inspect}" unless config_attr
|
222
|
+
configuration.send(config_attr, boolean)
|
223
|
+
end
|
224
|
+
end
|
217
225
|
end
|
218
226
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'parser/current'
|
5
|
+
rescue NotImplementedError
|
6
|
+
warn 'Falling back to Ruby 2.1 parser.'
|
7
|
+
require 'parser/ruby21'
|
8
|
+
Parser::CurrentRuby = Parser::Ruby21 # rubocop:disable ConstantName
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'transpec/ast/builder'
|
12
|
+
|
13
|
+
module Transpec
|
14
|
+
class ProcessedSource
|
15
|
+
attr_reader :buffer, :ast, :path, :syntax_error
|
16
|
+
|
17
|
+
def self.parse_file(path)
|
18
|
+
source = File.read(path)
|
19
|
+
parse(source, path)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.parse(source, path = nil)
|
23
|
+
buffer = Parser::Source::Buffer.new(path || '(string)')
|
24
|
+
buffer.source = source
|
25
|
+
|
26
|
+
builder = AST::Builder.new
|
27
|
+
parser = Parser::CurrentRuby.new(builder)
|
28
|
+
|
29
|
+
begin
|
30
|
+
ast = parser.parse(buffer)
|
31
|
+
new(buffer, ast, path)
|
32
|
+
rescue Parser::SyntaxError => error
|
33
|
+
new(buffer, nil, path, error)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def initialize(buffer, ast, path = nil, syntax_error = nil)
|
38
|
+
@buffer = buffer
|
39
|
+
@ast = ast
|
40
|
+
@path = path
|
41
|
+
@syntax_error = syntax_error
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
buffer.source
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/transpec/record.rb
CHANGED
@@ -4,7 +4,7 @@ require 'transpec/annotatable'
|
|
4
4
|
|
5
5
|
module Transpec
|
6
6
|
class Record
|
7
|
-
|
7
|
+
OVERRIDE_FORBIDDEN_METHODS = [
|
8
8
|
:original_syntax,
|
9
9
|
:original_syntax_type,
|
10
10
|
:converted_syntax,
|
@@ -62,7 +62,7 @@ module Transpec
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def self.method_added(method_name)
|
65
|
-
return unless
|
65
|
+
return unless OVERRIDE_FORBIDDEN_METHODS.include?(method_name)
|
66
66
|
fail "Do not override Record##{method_name}."
|
67
67
|
end
|
68
68
|
end
|
data/lib/transpec/report.rb
CHANGED
@@ -26,7 +26,11 @@ module Transpec
|
|
26
26
|
record_counts[record] += 1
|
27
27
|
end
|
28
28
|
|
29
|
-
|
29
|
+
sorted_record_counts = record_counts.sort_by do |record, count|
|
30
|
+
[-count, record.original_syntax_type, record.converted_syntax_type]
|
31
|
+
end
|
32
|
+
|
33
|
+
Hash[sorted_record_counts]
|
30
34
|
end
|
31
35
|
|
32
36
|
def colored_summary(options = nil)
|
data/lib/transpec/rspec_dsl.rb
CHANGED
@@ -3,18 +3,28 @@
|
|
3
3
|
# Aliases by Capybara:
|
4
4
|
# https://github.com/jnicklas/capybara/blob/2.2.0/lib/capybara/rspec/features.rb
|
5
5
|
|
6
|
+
# rubocop:disable LineLength
|
7
|
+
|
6
8
|
module Transpec
|
7
9
|
module RSpecDSL
|
10
|
+
# https://github.com/rspec/rspec-core/blob/77cc21e/lib/rspec/core/example_group.rb#L239-L265
|
11
|
+
# https://github.com/rspec/rspec-core/blob/77cc21e/lib/rspec/core/shared_example_group.rb#L50-L61
|
8
12
|
EXAMPLE_GROUP_METHODS = [
|
13
|
+
:example_group,
|
9
14
|
:describe, :context,
|
15
|
+
:xdescribe, :xcontext,
|
16
|
+
:fdescribe, :fcontext,
|
10
17
|
:shared_examples, :shared_context, :share_examples_for, :shared_examples_for,
|
11
18
|
:feature # Capybara
|
12
19
|
].freeze
|
13
20
|
|
21
|
+
# https://github.com/rspec/rspec-core/blob/77cc21e/lib/rspec/core/example_group.rb#L130-L171
|
14
22
|
EXAMPLE_METHODS = [
|
15
23
|
:example, :it, :specify,
|
16
|
-
:focus, :
|
17
|
-
:
|
24
|
+
:focus, :fexample, :fit, :fspecify,
|
25
|
+
:focused, # TODO: Support conversion
|
26
|
+
:xexample, :xit, :xspecify,
|
27
|
+
:skip, :pending,
|
18
28
|
:scenario, :xscenario # Capybara
|
19
29
|
].freeze
|
20
30
|
|
@@ -41,14 +41,15 @@ module Transpec
|
|
41
41
|
gem_version.to_s
|
42
42
|
end
|
43
43
|
|
44
|
-
define_feature :be_truthy,
|
45
|
-
define_feature :yielded_example,
|
44
|
+
define_feature :be_truthy, '2.99.0.beta1'
|
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
|
-
define_feature :oneliner_is_expected,
|
48
|
-
define_feature :skip,
|
49
|
-
define_feature :receive_messages,
|
50
|
-
define_feature :receive_message_chain,
|
51
|
-
define_feature :non_should_matcher_protocol,
|
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'
|
49
|
+
define_feature :receive_messages, '3.0.0.beta1'
|
50
|
+
define_feature :receive_message_chain, '3.0.0.beta2'
|
51
|
+
define_feature :non_should_matcher_protocol, '3.0.0.beta2'
|
52
|
+
define_feature :non_monkey_patch_example_group, '3.0.0.beta2'
|
52
53
|
|
53
54
|
RSPEC_2_99 = new('2.99.0.beta1')
|
54
55
|
RSPEC_3_0 = new('3.0.0.beta1')
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'transpec/file_finder'
|
4
|
+
require 'transpec/processed_source'
|
5
|
+
require 'transpec/syntax'
|
6
|
+
|
7
|
+
Transpec::Syntax.require_all
|
8
|
+
|
9
|
+
module Transpec
|
10
|
+
class SpecSuite
|
11
|
+
ANALYSIS_TARGET_CLASSES = [Syntax::Mixin::AnyInstanceBlock]
|
12
|
+
|
13
|
+
attr_reader :runtime_data
|
14
|
+
|
15
|
+
def initialize(base_paths = [], runtime_data = nil)
|
16
|
+
@base_paths = base_paths
|
17
|
+
@runtime_data = runtime_data
|
18
|
+
@analyzed = false
|
19
|
+
end
|
20
|
+
|
21
|
+
def specs
|
22
|
+
@specs ||= begin
|
23
|
+
FileFinder.find(@base_paths).map do |path|
|
24
|
+
ProcessedSource.parse_file(path)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def analyze
|
30
|
+
return if @analyzed
|
31
|
+
|
32
|
+
specs.each do |spec|
|
33
|
+
next unless spec.ast
|
34
|
+
spec.ast.each_node do |node|
|
35
|
+
dispatch_node(node)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
@analyzed = true
|
40
|
+
end
|
41
|
+
|
42
|
+
def need_to_modify_yield_receiver_to_any_instance_implementation_blocks_config?
|
43
|
+
analyze
|
44
|
+
@need_to_modify_yield_receiver_to_any_instance_implementation_blocks_config
|
45
|
+
end
|
46
|
+
|
47
|
+
def main_rspec_configure_node?(node)
|
48
|
+
analyze
|
49
|
+
|
50
|
+
if @main_rspec_configure
|
51
|
+
@main_rspec_configure.node.equal?(node)
|
52
|
+
else
|
53
|
+
true
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def dispatch_node(node)
|
60
|
+
Syntax.standalone_syntaxes.each do |syntax_class|
|
61
|
+
syntax = syntax_class.new(node, nil, runtime_data)
|
62
|
+
next unless syntax.conversion_target?
|
63
|
+
dispatch_syntax(syntax)
|
64
|
+
break
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def dispatch_syntax(syntax)
|
69
|
+
invoke_handler(syntax.class, syntax)
|
70
|
+
|
71
|
+
syntax_mixins.each do |mixin|
|
72
|
+
next unless syntax.class.ancestors.include?(mixin)
|
73
|
+
invoke_handler(mixin, syntax)
|
74
|
+
end
|
75
|
+
|
76
|
+
syntax.dependent_syntaxes.each do |dependent_syntax|
|
77
|
+
next unless dependent_syntax.conversion_target?
|
78
|
+
dispatch_syntax(dependent_syntax)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def syntax_mixins
|
83
|
+
Syntax::Mixin.constants.map do |const_name|
|
84
|
+
Syntax::Mixin.const_get(const_name, false)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def invoke_handler(klass, syntax)
|
89
|
+
class_name = klass.name.split('::').last.gsub(/([a-z])([A-Z])/, '\1_\2').downcase
|
90
|
+
handler_name = "process_#{class_name}"
|
91
|
+
send(handler_name, syntax) if respond_to?(handler_name, true)
|
92
|
+
end
|
93
|
+
|
94
|
+
def process_any_instance_block(syntax)
|
95
|
+
@need_to_modify_yield_receiver_to_any_instance_implementation_blocks_config ||=
|
96
|
+
syntax.need_to_add_receiver_arg_to_any_instance_implementation_block?
|
97
|
+
end
|
98
|
+
|
99
|
+
def process_rspec_configure(rspec_configure)
|
100
|
+
return unless runtime_data
|
101
|
+
run_order = runtime_data[rspec_configure.node, :run_order]
|
102
|
+
return unless run_order
|
103
|
+
|
104
|
+
unless @main_rspec_configure
|
105
|
+
@main_rspec_configure = rspec_configure
|
106
|
+
return
|
107
|
+
end
|
108
|
+
|
109
|
+
if run_order < runtime_data[@main_rspec_configure.node, :run_order]
|
110
|
+
@main_rspec_configure = rspec_configure
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -1,36 +1,20 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
|
3
3
|
require 'transpec/syntax'
|
4
|
-
require 'transpec/syntax/mixin/
|
4
|
+
require 'transpec/syntax/mixin/context_sensitive'
|
5
5
|
require 'transpec/rspec_dsl'
|
6
6
|
|
7
7
|
module Transpec
|
8
8
|
class Syntax
|
9
9
|
class Example < Syntax
|
10
|
-
include Mixin::
|
11
|
-
|
12
|
-
define_dynamic_analysis do |rewriter|
|
13
|
-
code = "is_a?(Class) && ancestors.any? { |a| a.name == 'RSpec::Core::ExampleGroup' }"
|
14
|
-
rewriter.register_request(node, :example_group_context?, code, :context)
|
15
|
-
end
|
10
|
+
include Mixin::ContextSensitive, RSpecDSL
|
16
11
|
|
17
12
|
def dynamic_analysis_target?
|
18
13
|
super && receiver_node.nil? && EXAMPLE_METHODS.include?(method_name)
|
19
14
|
end
|
20
15
|
|
21
|
-
def
|
22
|
-
|
23
|
-
|
24
|
-
# Check whether the context is example group to differenciate
|
25
|
-
# RSpec::Core::ExampleGroup.pending (a relative of #it) and
|
26
|
-
# RSpec::Core::ExampleGroup#pending (marks the example as pending in #it block).
|
27
|
-
if runtime_data.run?(node)
|
28
|
-
# If we have runtime data, check with it.
|
29
|
-
runtime_data[node, :example_group_context?]
|
30
|
-
else
|
31
|
-
# Otherwise check statically.
|
32
|
-
static_context_inspector.scopes.last == :example_group
|
33
|
-
end
|
16
|
+
def should_be_in_example_group_context?
|
17
|
+
true
|
34
18
|
end
|
35
19
|
|
36
20
|
def convert_pending_to_skip!
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'transpec/syntax'
|
4
|
+
require 'transpec/syntax/mixin/context_sensitive'
|
5
|
+
require 'transpec/syntax/mixin/monkey_patch'
|
6
|
+
require 'transpec/rspec_dsl'
|
7
|
+
|
8
|
+
module Transpec
|
9
|
+
class Syntax
|
10
|
+
class ExampleGroup < Syntax
|
11
|
+
include Mixin::ContextSensitive, Mixin::MonkeyPatch, RSpecDSL
|
12
|
+
|
13
|
+
def dynamic_analysis_target?
|
14
|
+
super && receiver_node.nil? && EXAMPLE_GROUP_METHODS.include?(method_name)
|
15
|
+
end
|
16
|
+
|
17
|
+
def should_be_in_example_group_context?
|
18
|
+
false
|
19
|
+
end
|
20
|
+
|
21
|
+
def convert_to_non_monkey_patch!
|
22
|
+
insert_before(expression_range, 'RSpec.')
|
23
|
+
register_record
|
24
|
+
end
|
25
|
+
|
26
|
+
def register_record
|
27
|
+
original_syntax = method_name.to_s
|
28
|
+
converted_syntax = "RSpec.#{method_name}"
|
29
|
+
|
30
|
+
[original_syntax, converted_syntax].each do |syntax|
|
31
|
+
syntax << " 'something' { }"
|
32
|
+
end
|
33
|
+
|
34
|
+
@report.records << Record.new(original_syntax, converted_syntax)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/transpec/syntax/have.rb
CHANGED
@@ -28,12 +28,13 @@ module Transpec
|
|
28
28
|
[:have, :have_exactly, :have_at_least, :have_at_most].include?(method_name)
|
29
29
|
end
|
30
30
|
|
31
|
-
def
|
32
|
-
|
31
|
+
def conversion_target?
|
32
|
+
super && !runtime_subject_data(:project_requires_collection_matcher?)
|
33
|
+
end
|
33
34
|
|
35
|
+
def convert_to_standard_expectation!(parenthesize_matcher_arg = true)
|
34
36
|
replace(expectation.subject_range, replacement_subject_source) if explicit_subject?
|
35
37
|
replace(matcher_range, source_builder.replacement_matcher_source(parenthesize_matcher_arg))
|
36
|
-
|
37
38
|
register_record if explicit_subject?
|
38
39
|
end
|
39
40
|
|
@@ -56,10 +57,6 @@ module Transpec
|
|
56
57
|
items_node.children[1]
|
57
58
|
end
|
58
59
|
|
59
|
-
def project_requires_collection_matcher?
|
60
|
-
runtime_subject_data(:project_requires_collection_matcher?)
|
61
|
-
end
|
62
|
-
|
63
60
|
def collection_accessor
|
64
61
|
if runtime_subject_data(:collection_accessor)
|
65
62
|
runtime_subject_data(:collection_accessor).to_sym
|
@@ -70,7 +67,7 @@ module Transpec
|
|
70
67
|
|
71
68
|
def subject_is_owner_of_collection?
|
72
69
|
return true if items_method_has_arguments?
|
73
|
-
|
70
|
+
runtime_subject_data(:collection_accessor)
|
74
71
|
end
|
75
72
|
|
76
73
|
def collection_accessor_is_private?
|
@@ -99,7 +96,7 @@ module Transpec
|
|
99
96
|
end
|
100
97
|
|
101
98
|
def accurate_conversion?
|
102
|
-
|
99
|
+
runtime_subject_data
|
103
100
|
end
|
104
101
|
|
105
102
|
def matcher_range
|
data/lib/transpec/syntax/its.rb
CHANGED
@@ -19,9 +19,11 @@ module Transpec
|
|
19
19
|
super && receiver_node.nil? && method_name == :its
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
23
|
-
|
22
|
+
def conversion_target?
|
23
|
+
super && !runtime_data[node, :project_requires_its?]
|
24
|
+
end
|
24
25
|
|
26
|
+
def convert_to_describe_subject_it!
|
25
27
|
front, rear = build_wrapper_codes
|
26
28
|
|
27
29
|
insert_before(beginning_of_line_range(block_node), front)
|
@@ -45,10 +47,6 @@ module Transpec
|
|
45
47
|
node.parent_node
|
46
48
|
end
|
47
49
|
|
48
|
-
def project_requires_its?
|
49
|
-
runtime_data[node, :project_requires_its?]
|
50
|
-
end
|
51
|
-
|
52
50
|
private
|
53
51
|
|
54
52
|
def build_wrapper_codes
|
@@ -74,7 +72,7 @@ module Transpec
|
|
74
72
|
|
75
73
|
def previous_line_is_blank?
|
76
74
|
return false unless previous_line_source
|
77
|
-
previous_line_source.empty? ||
|
75
|
+
previous_line_source.empty? || previous_line_source.match(/\A\s*\Z/)
|
78
76
|
end
|
79
77
|
|
80
78
|
def previous_and_current_line_are_same_indentation_level?
|