synvert-core 0.63.1 → 0.64.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -1
- data/README.md +73 -33
- data/lib/synvert/core/configuration.rb +12 -0
- data/lib/synvert/core/exceptions.rb +0 -4
- data/lib/synvert/core/node_ext.rb +188 -87
- data/lib/synvert/core/rewriter/action/append_action.rb +4 -3
- data/lib/synvert/core/rewriter/action/delete_action.rb +13 -6
- data/lib/synvert/core/rewriter/action/insert_action.rb +16 -7
- data/lib/synvert/core/rewriter/action/insert_after_action.rb +3 -2
- data/lib/synvert/core/rewriter/action/prepend_action.rb +3 -2
- data/lib/synvert/core/rewriter/action/remove_action.rb +16 -10
- data/lib/synvert/core/rewriter/action/replace_action.rb +13 -5
- data/lib/synvert/core/rewriter/action/replace_erb_stmt_with_expr_action.rb +18 -11
- data/lib/synvert/core/rewriter/action/replace_with_action.rb +6 -5
- data/lib/synvert/core/rewriter/action/wrap_action.rb +13 -5
- data/lib/synvert/core/rewriter/action.rb +20 -9
- data/lib/synvert/core/rewriter/any_value.rb +1 -0
- data/lib/synvert/core/rewriter/condition/if_exist_condition.rb +4 -0
- data/lib/synvert/core/rewriter/condition/if_only_exist_condition.rb +4 -0
- data/lib/synvert/core/rewriter/condition/unless_exist_condition.rb +4 -0
- data/lib/synvert/core/rewriter/condition.rb +11 -3
- data/lib/synvert/core/rewriter/gem_spec.rb +6 -3
- data/lib/synvert/core/rewriter/helper.rb +2 -2
- data/lib/synvert/core/rewriter/instance.rb +195 -94
- data/lib/synvert/core/rewriter/ruby_version.rb +4 -4
- data/lib/synvert/core/rewriter/scope/goto_scope.rb +5 -6
- data/lib/synvert/core/rewriter/scope/within_scope.rb +9 -4
- data/lib/synvert/core/rewriter/scope.rb +8 -0
- data/lib/synvert/core/rewriter/warning.rb +1 -1
- data/lib/synvert/core/rewriter.rb +90 -43
- data/lib/synvert/core/version.rb +1 -1
- data/lib/synvert/core.rb +0 -1
- data/spec/synvert/core/node_ext_spec.rb +0 -7
- data/spec/synvert/core/rewriter/action_spec.rb +0 -4
- data/spec/synvert/core/rewriter/gem_spec_spec.rb +1 -1
- data/spec/synvert/core/rewriter/instance_spec.rb +7 -17
- data/synvert-core-ruby.gemspec +2 -1
- metadata +20 -6
@@ -4,12 +4,12 @@ module Synvert::Core
|
|
4
4
|
# Instance is an execution unit, it finds specified ast nodes,
|
5
5
|
# checks if the nodes match some conditions, then add, replace or remove code.
|
6
6
|
#
|
7
|
-
# One instance can
|
7
|
+
# One instance can contain one or many {Synvert::Core::Rewriter::Scope} and {Synvert::Rewriter::Condition}.
|
8
8
|
class Rewriter::Instance
|
9
9
|
include Rewriter::Helper
|
10
10
|
|
11
11
|
class << self
|
12
|
-
#
|
12
|
+
# Get file source.
|
13
13
|
#
|
14
14
|
# @param file_path [String] file path
|
15
15
|
# @return [String] file source
|
@@ -23,7 +23,7 @@ module Synvert::Core
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
#
|
26
|
+
# Get file ast.
|
27
27
|
#
|
28
28
|
# @param file_path [String] file path
|
29
29
|
# @return [String] ast node for file
|
@@ -51,7 +51,7 @@ module Synvert::Core
|
|
51
51
|
@file_ast[file_path] = nil
|
52
52
|
end
|
53
53
|
|
54
|
-
# Reset
|
54
|
+
# Reset file source and ast.
|
55
55
|
def reset
|
56
56
|
@file_source = {}
|
57
57
|
@file_ast = {}
|
@@ -69,12 +69,11 @@ module Synvert::Core
|
|
69
69
|
self.class.file_source(current_file)
|
70
70
|
end
|
71
71
|
|
72
|
-
# Initialize an
|
72
|
+
# Initialize an Instance.
|
73
73
|
#
|
74
74
|
# @param rewriter [Synvert::Core::Rewriter]
|
75
75
|
# @param file_patterns [Array<String>] pattern list to find files, e.g. ['spec/**/*_spec.rb']
|
76
|
-
# @
|
77
|
-
# @return [Synvert::Core::Rewriter::Instance]
|
76
|
+
# @yield block code to find nodes, match conditions and rewrite code.
|
78
77
|
def initialize(rewriter, file_patterns, &block)
|
79
78
|
@rewriter = rewriter
|
80
79
|
@actions = []
|
@@ -84,44 +83,14 @@ module Synvert::Core
|
|
84
83
|
end
|
85
84
|
|
86
85
|
# Process the instance.
|
87
|
-
# It finds
|
88
|
-
#
|
86
|
+
# It finds specified files, for each file, it executes the block code, rewrites the original code,
|
87
|
+
# then write the code back to the original file.
|
89
88
|
def process
|
90
89
|
@file_patterns.each do |file_pattern|
|
91
90
|
Dir.glob(File.join(Configuration.path, file_pattern)).each do |file_path|
|
92
|
-
next if Configuration.skip_files.include?
|
91
|
+
next if Configuration.skip_files.include?(file_path)
|
93
92
|
|
94
|
-
|
95
|
-
puts file_path if Configuration.show_run_process
|
96
|
-
conflict_actions = []
|
97
|
-
source = +self.class.file_source(file_path)
|
98
|
-
ast = self.class.file_ast(file_path)
|
99
|
-
|
100
|
-
@current_file = file_path
|
101
|
-
|
102
|
-
process_with_node ast do
|
103
|
-
begin
|
104
|
-
instance_eval(&@block)
|
105
|
-
rescue NoMethodError
|
106
|
-
puts @current_node.debug_info
|
107
|
-
raise
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
if @actions.length > 0
|
112
|
-
@actions.sort_by! { |action| [action.begin_pos, action.end_pos] }
|
113
|
-
conflict_actions = get_conflict_actions
|
114
|
-
@actions.reverse_each do |action|
|
115
|
-
source[action.begin_pos...action.end_pos] = action.rewritten_code
|
116
|
-
end
|
117
|
-
@actions = []
|
118
|
-
|
119
|
-
update_file(file_path, source)
|
120
|
-
end
|
121
|
-
rescue Parser::SyntaxError
|
122
|
-
puts "[Warn] file #{file_path} was not parsed correctly."
|
123
|
-
# do nothing, iterate next file
|
124
|
-
end while !conflict_actions.empty?
|
93
|
+
process_file(file_path)
|
125
94
|
end
|
126
95
|
end
|
127
96
|
end
|
@@ -158,159 +127,291 @@ module Synvert::Core
|
|
158
127
|
# DSL #
|
159
128
|
#######
|
160
129
|
|
161
|
-
# Parse within_node dsl, it creates a
|
130
|
+
# Parse +within_node+ dsl, it creates a {Synvert::Core::Rewriter::WithinScope} to recursively find matching ast nodes,
|
162
131
|
# then continue operating on each matching ast node.
|
163
|
-
#
|
132
|
+
# @example
|
133
|
+
# # matches User.find_by_login('test')
|
134
|
+
# with_node type: 'send', message: /^find_by_/ do
|
135
|
+
# end
|
164
136
|
# @param rules [Hash] rules to find mathing ast nodes.
|
165
|
-
# @param options [Hash] optional
|
166
|
-
# @
|
167
|
-
|
168
|
-
|
137
|
+
# @param options [Hash] optional
|
138
|
+
# @option stop_when_match [Boolean] set if stop when match, default is false
|
139
|
+
# @option direct [Boolean] set if find direct matching ast nodes, default is false
|
140
|
+
# @yield run on the matching nodes.
|
141
|
+
def within_node(rules, options = {}, &block)
|
142
|
+
options[:stop_when_match] ||= false
|
143
|
+
options[:direct] ||= false
|
169
144
|
Rewriter::WithinScope.new(self, rules, options, &block).process
|
170
145
|
end
|
171
146
|
|
172
147
|
alias with_node within_node
|
173
148
|
|
174
|
-
# Parse
|
175
|
-
# then continue operating on each matching ast node.
|
176
|
-
#
|
177
|
-
# @param rules [Hash] rules to find mathing ast nodes.
|
178
|
-
# @param block [Block] block code to continue operating on the matching nodes.
|
179
|
-
def within_direct_node(rules, &block)
|
180
|
-
Rewriter::WithinScope.new(self, rules, { direct: true }, &block).process
|
181
|
-
end
|
182
|
-
|
183
|
-
alias with_direct_node within_direct_node
|
184
|
-
|
185
|
-
# Parse goto_node dsl, it creates a [Synvert::Core::Rewriter::GotoScope] to go to a child node,
|
149
|
+
# Parse +goto_node+ dsl, it creates a {Synvert::Core::Rewriter::GotoScope} to go to a child node,
|
186
150
|
# then continue operating on the child node.
|
187
|
-
#
|
151
|
+
# @example
|
152
|
+
# # head status: 406
|
153
|
+
# with_node type: 'send', receiver: nil, message: 'head', arguments: { size: 1, first: { type: 'hash' } } do
|
154
|
+
# goto_node 'arguments.first' do
|
155
|
+
# end
|
156
|
+
# end
|
188
157
|
# @param child_node_name [Symbol|String] the name of the child nodes.
|
189
158
|
# @param block [Block] block code to continue operating on the matching nodes.
|
190
159
|
def goto_node(child_node_name, &block)
|
191
160
|
Rewriter::GotoScope.new(self, child_node_name, &block).process
|
192
161
|
end
|
193
162
|
|
194
|
-
# Parse if_exist_node dsl, it creates a
|
163
|
+
# Parse +if_exist_node+ dsl, it creates a {Synvert::Core::Rewriter::IfExistCondition} to check
|
195
164
|
# if matching nodes exist in the child nodes, if so, then continue operating on each matching ast node.
|
196
|
-
#
|
165
|
+
# @example
|
166
|
+
# # Klass.any_instance.stub(:message)
|
167
|
+
# with_node type: 'send', message: 'stub', arguments: { first: { type: { not: 'hash' } } } do
|
168
|
+
# if_exist_node type: 'send', message: 'any_instance' do
|
169
|
+
# end
|
170
|
+
# end
|
197
171
|
# @param rules [Hash] rules to check mathing ast nodes.
|
198
172
|
# @param block [Block] block code to continue operating on the matching nodes.
|
199
173
|
def if_exist_node(rules, &block)
|
200
174
|
Rewriter::IfExistCondition.new(self, rules, &block).process
|
201
175
|
end
|
202
176
|
|
203
|
-
# Parse unless_exist_node dsl, it creates a
|
177
|
+
# Parse +unless_exist_node+ dsl, it creates a {Synvert::Core::Rewriter::UnlessExistCondition} to check
|
204
178
|
# if matching nodes doesn't exist in the child nodes, if so, then continue operating on each matching ast node.
|
205
|
-
#
|
179
|
+
# @example
|
180
|
+
# # obj.stub(:message)
|
181
|
+
# with_node type: 'send', message: 'stub', arguments: { first: { type: { not: 'hash' } } } do
|
182
|
+
# unless_exist_node type: 'send', message: 'any_instance' do
|
183
|
+
# end
|
184
|
+
# end
|
206
185
|
# @param rules [Hash] rules to check mathing ast nodes.
|
207
186
|
# @param block [Block] block code to continue operating on the matching nodes.
|
208
187
|
def unless_exist_node(rules, &block)
|
209
188
|
Rewriter::UnlessExistCondition.new(self, rules, &block).process
|
210
189
|
end
|
211
190
|
|
212
|
-
# Parse if_only_exist_node dsl, it creates a
|
191
|
+
# Parse +if_only_exist_node+ dsl, it creates a {Synvert::Core::Rewriter::IfOnlyExistCondition} to check
|
213
192
|
# if current node has only one child node and the child node matches rules,
|
214
193
|
# if so, then continue operating on each matching ast node.
|
215
|
-
#
|
194
|
+
# @example
|
195
|
+
# # it { should matcher }
|
196
|
+
# with_node type: 'block', caller: { message: 'it' } do
|
197
|
+
# if_only_exist_node type: 'send', receiver: nil, message: 'should' do
|
198
|
+
# end
|
199
|
+
# end
|
216
200
|
# @param rules [Hash] rules to check mathing ast nodes.
|
217
201
|
# @param block [Block] block code to continue operating on the matching nodes.
|
218
202
|
def if_only_exist_node(rules, &block)
|
219
203
|
Rewriter::IfOnlyExistCondition.new(self, rules, &block).process
|
220
204
|
end
|
221
205
|
|
222
|
-
# Parse append dsl, it creates a
|
206
|
+
# Parse +append+ dsl, it creates a {Synvert::Core::Rewriter::AppendAction} to
|
223
207
|
# append the code to the bottom of current node body.
|
224
|
-
#
|
208
|
+
# @example
|
209
|
+
# # def teardown
|
210
|
+
# # clean_something
|
211
|
+
# # end
|
212
|
+
# # =>
|
213
|
+
# # def teardown
|
214
|
+
# # clean_something
|
215
|
+
# # super
|
216
|
+
# # end
|
217
|
+
# with_node type: 'def', name: 'steardown' do
|
218
|
+
# append 'super'
|
219
|
+
# end
|
225
220
|
# @param code [String] code need to be appended.
|
226
221
|
def append(code)
|
227
222
|
@actions << Rewriter::AppendAction.new(self, code).process
|
228
223
|
end
|
229
224
|
|
230
|
-
# Parse prepend dsl, it creates a
|
225
|
+
# Parse +prepend+ dsl, it creates a {Synvert::Core::Rewriter::PrependAction} to
|
231
226
|
# prepend the code to the top of current node body.
|
232
|
-
#
|
227
|
+
# @example
|
228
|
+
# # def setup
|
229
|
+
# # do_something
|
230
|
+
# # end
|
231
|
+
# # =>
|
232
|
+
# # def setup
|
233
|
+
# # super
|
234
|
+
# # do_something
|
235
|
+
# # end
|
236
|
+
# with_node type: 'def', name: 'setup' do
|
237
|
+
# prepend 'super'
|
238
|
+
# end
|
233
239
|
# @param code [String] code need to be prepended.
|
234
240
|
def prepend(code)
|
235
241
|
@actions << Rewriter::PrependAction.new(self, code).process
|
236
242
|
end
|
237
243
|
|
238
|
-
# Parse insert dsl, it creates a
|
239
|
-
#
|
240
|
-
#
|
244
|
+
# Parse +insert+ dsl, it creates a {Synvert::Core::Rewriter::InsertAction} to insert code.
|
245
|
+
# @example
|
246
|
+
# # open('http://test.com')
|
247
|
+
# # =>
|
248
|
+
# # URI.open('http://test.com')
|
249
|
+
# with_node type: 'send', receiver: nil, message: 'open' do
|
250
|
+
# insert 'URI.', at: 'beginning'
|
251
|
+
# end
|
241
252
|
# @param code [String] code need to be inserted.
|
242
|
-
# @param at [String] insert position, beginning or end
|
253
|
+
# @param at [String] insert position, beginning or end
|
243
254
|
# @param to [String] where to insert, if it is nil, will insert to current node.
|
244
255
|
def insert(code, at: 'end', to: nil)
|
245
256
|
@actions << Rewriter::InsertAction.new(self, code, at: at, to: to).process
|
246
257
|
end
|
247
258
|
|
248
|
-
# Parse insert_after dsl, it creates a
|
259
|
+
# Parse +insert_after+ dsl, it creates a {Synvert::Core::Rewriter::InsertAfterAction} to
|
249
260
|
# insert the code next to the current node.
|
250
|
-
#
|
261
|
+
# @example
|
262
|
+
# # Synvert::Application.config.secret_token = "0447aa931d42918bfb934750bb78257088fb671186b5d1b6f9fddf126fc8a14d34f1d045cefab3900751c3da121a8dd929aec9bafe975f1cabb48232b4002e4e"
|
263
|
+
# # =>
|
264
|
+
# # Synvert::Application.config.secret_token = "0447aa931d42918bfb934750bb78257088fb671186b5d1b6f9fddf126fc8a14d34f1d045cefab3900751c3da121a8dd929aec9bafe975f1cabb48232b4002e4e"
|
265
|
+
# # Synvert::Application.config.secret_key_base = "bf4f3f46924ecd9adcb6515681c78144545bba454420973a274d7021ff946b8ef043a95ca1a15a9d1b75f9fbdf85d1a3afaf22f4e3c2f3f78e24a0a188b581df"
|
266
|
+
# with_node type: 'send', message: 'secret_token=' do
|
267
|
+
# insert_after "{{receiver}}.secret_key_base = \"#{SecureRandom.hex(64)}\""
|
268
|
+
# end
|
251
269
|
# @param code [String] code need to be inserted.
|
252
|
-
def insert_after(
|
253
|
-
@actions << Rewriter::InsertAfterAction.new(self,
|
270
|
+
def insert_after(code)
|
271
|
+
@actions << Rewriter::InsertAfterAction.new(self, code).process
|
254
272
|
end
|
255
273
|
|
256
|
-
# Parse replace_with dsl, it creates a
|
257
|
-
# replace current node
|
258
|
-
#
|
274
|
+
# Parse +replace_with+ dsl, it creates a {Synvert::Core::Rewriter::ReplaceWithAction} to
|
275
|
+
# replace the whole code of current node.
|
276
|
+
# @example
|
277
|
+
# # obj.stub(:foo => 1, :bar => 2)
|
278
|
+
# # =>
|
279
|
+
# # allow(obj).to receive_messages(:foo => 1, :bar => 2)
|
280
|
+
# with_node type: 'send', message: 'stub', arguments: { first: { type: 'hash' } } do
|
281
|
+
# replace_with 'allow({{receiver}}).to receive_messages({{arguments}})'
|
282
|
+
# end
|
259
283
|
# @param code [String] code need to be replaced with.
|
260
284
|
def replace_with(code)
|
261
285
|
@actions << Rewriter::ReplaceWithAction.new(self, code).process
|
262
286
|
end
|
263
287
|
|
264
|
-
# Parse replace
|
265
|
-
# replace child nodes
|
266
|
-
#
|
288
|
+
# Parse +replace+ dsl, it creates a {Synvert::Core::Rewriter::ReplaceAction} to
|
289
|
+
# replace the code of specified child nodes.
|
290
|
+
# @example
|
291
|
+
# # assert(object.empty?)
|
292
|
+
# # =>
|
293
|
+
# # assert_empty(object)
|
294
|
+
# with_node type: 'send', receiver: nil, message: 'assert', arguments: { size: 1, first: { type: 'send', message: 'empty?', arguments: { size: 0 } } } do
|
295
|
+
# replace :message, with: 'assert_empty'
|
296
|
+
# replace :arguments, with: '{{arguments.first.receiver}}'
|
297
|
+
# end
|
267
298
|
# @param selectors [Array<Symbol>] selector names of child node.
|
268
299
|
# @param with [String] code need to be replaced with.
|
269
300
|
def replace(*selectors, with:)
|
270
301
|
@actions << Rewriter::ReplaceAction.new(self, *selectors, with: with).process
|
271
302
|
end
|
272
303
|
|
273
|
-
# Parse replace_erb_stmt_with_expr dsl, it creates a
|
304
|
+
# Parse +replace_erb_stmt_with_expr+ dsl, it creates a {Synvert::Core::Rewriter::ReplaceErbStmtWithExprAction} to
|
274
305
|
# replace erb stmt code to expr code.
|
306
|
+
# @example
|
307
|
+
# # <% form_for post do |f| %>
|
308
|
+
# # <% end %>
|
309
|
+
# # =>
|
310
|
+
# # <%= form_for post do |f| %>
|
311
|
+
# # <% end %>
|
312
|
+
# with_node type: 'block', caller: { type: 'send', receiver: nil, message: 'form_for' } do
|
313
|
+
# replace_erb_stmt_with_expr
|
314
|
+
# end
|
275
315
|
def replace_erb_stmt_with_expr
|
276
316
|
@actions << Rewriter::ReplaceErbStmtWithExprAction.new(self).process
|
277
317
|
end
|
278
318
|
|
279
|
-
# Parse remove dsl, it creates a
|
319
|
+
# Parse +remove+ dsl, it creates a {Synvert::Core::Rewriter::RemoveAction} to remove current node.
|
320
|
+
# @example
|
321
|
+
# with_node type: 'send', message: { in: %w[puts p] } do
|
322
|
+
# remove
|
323
|
+
# end
|
280
324
|
def remove
|
281
325
|
@actions << Rewriter::RemoveAction.new(self).process
|
282
326
|
end
|
283
327
|
|
284
|
-
# Parse delete dsl, it creates a
|
285
|
-
#
|
328
|
+
# Parse +delete+ dsl, it creates a {Synvert::Core::Rewriter::DeleteAction} to delete child nodes.
|
329
|
+
# @example
|
330
|
+
# # FactoryBot.create(...)
|
331
|
+
# # =>
|
332
|
+
# # create(...)
|
333
|
+
# with_node type: 'send', receiver: 'FactoryBot', message: 'create' do
|
334
|
+
# delete :receiver, :dot
|
335
|
+
# end
|
286
336
|
# @param selectors [Array<Symbol>] selector names of child node.
|
287
337
|
def delete(*selectors)
|
288
338
|
@actions << Rewriter::DeleteAction.new(self, *selectors).process
|
289
339
|
end
|
290
340
|
|
291
|
-
# Parse wrap
|
341
|
+
# Parse +wrap+ dsl, it creates a {Synvert::Core::Rewriter::WrapAction} to
|
292
342
|
# wrap current node with code.
|
293
|
-
#
|
343
|
+
# @example
|
344
|
+
# # class Foobar
|
345
|
+
# # end
|
346
|
+
# # =>
|
347
|
+
# # module Synvert
|
348
|
+
# # class Foobar
|
349
|
+
# # end
|
350
|
+
# # end
|
351
|
+
# within_node type: 'class' do
|
352
|
+
# wrap with: 'module Synvert'
|
353
|
+
# end
|
294
354
|
# @param with [String] code need to be wrapped with.
|
295
|
-
# @param indent [Integer] number of whitespaces.
|
355
|
+
# @param indent [Integer, nil] number of whitespaces.
|
296
356
|
def wrap(with:, indent: nil)
|
297
357
|
@actions << Rewriter::WrapAction.new(self, with: with, indent: indent).process
|
298
358
|
end
|
299
359
|
|
300
|
-
# Parse warn dsl, it creates a
|
301
|
-
#
|
360
|
+
# Parse +warn+ dsl, it creates a {Synvert::Core::Rewriter::Warning} to save warning message.
|
361
|
+
# @example
|
362
|
+
# within_files 'vendor/plugins' do
|
363
|
+
# warn 'Rails::Plugin is deprecated and will be removed in Rails 4.0. Instead of adding plugins to vendor/plugins use gems or bundler with path or git dependencies.'
|
364
|
+
# end
|
302
365
|
# @param message [String] warning message.
|
303
366
|
def warn(message)
|
304
367
|
@rewriter.add_warning Rewriter::Warning.new(self, message)
|
305
368
|
end
|
306
369
|
|
307
|
-
#
|
370
|
+
# Match any value but nil.
|
371
|
+
# @example
|
372
|
+
# type: 'hash', nothing_value: 'true', status_value: any_value
|
373
|
+
# @return [Synvert::Core::Rewriter::AnyValue]
|
308
374
|
def any_value
|
309
375
|
Rewriter::AnyValue.new
|
310
376
|
end
|
311
377
|
|
312
378
|
private
|
313
379
|
|
380
|
+
# Process one file.
|
381
|
+
#
|
382
|
+
# @param file_path [String]
|
383
|
+
def process_file(file_path)
|
384
|
+
begin
|
385
|
+
puts file_path if Configuration.show_run_process
|
386
|
+
conflict_actions = []
|
387
|
+
source = +self.class.file_source(file_path)
|
388
|
+
ast = self.class.file_ast(file_path)
|
389
|
+
|
390
|
+
@current_file = file_path
|
391
|
+
|
392
|
+
process_with_node(ast) do
|
393
|
+
instance_eval(&@block)
|
394
|
+
rescue NoMethodError
|
395
|
+
puts @current_node.debug_info
|
396
|
+
raise
|
397
|
+
end
|
398
|
+
|
399
|
+
if @actions.length > 0
|
400
|
+
@actions.sort_by! { |action| [action.begin_pos, action.end_pos] }
|
401
|
+
conflict_actions = get_conflict_actions
|
402
|
+
@actions.reverse_each do |action|
|
403
|
+
source[action.begin_pos...action.end_pos] = action.rewritten_code
|
404
|
+
end
|
405
|
+
@actions = []
|
406
|
+
|
407
|
+
update_file(file_path, source)
|
408
|
+
end
|
409
|
+
rescue Parser::SyntaxError
|
410
|
+
puts "[Warn] file #{file_path} was not parsed correctly."
|
411
|
+
# do nothing, iterate next file
|
412
|
+
end while !conflict_actions.empty?
|
413
|
+
end
|
414
|
+
|
314
415
|
# It changes source code from bottom to top, and it can change source code twice at the same time,
|
315
416
|
# So if there is an overlap between two actions, it removes the conflict actions and operate them in the next loop.
|
316
417
|
def get_conflict_actions
|
@@ -17,13 +17,13 @@ module Synvert::Core
|
|
17
17
|
# @return [Boolean] true if matches, otherwise false.
|
18
18
|
def match?
|
19
19
|
if File.exist?(File.join(Configuration.path, '.ruby-version'))
|
20
|
-
|
20
|
+
version_file = '.ruby-version'
|
21
21
|
elsif File.exist?(File.join(Configuration.path, '.rvmrc'))
|
22
|
-
|
22
|
+
version_file = '.rvmrc'
|
23
23
|
end
|
24
|
-
return true unless
|
24
|
+
return true unless version_file
|
25
25
|
|
26
|
-
version = File.read(File.join(Configuration.path,
|
26
|
+
version = File.read(File.join(Configuration.path, version_file))
|
27
27
|
Gem::Version.new(version) >= Gem::Version.new(@version)
|
28
28
|
end
|
29
29
|
end
|
@@ -3,18 +3,17 @@
|
|
3
3
|
module Synvert::Core
|
4
4
|
# Go to and change its scope to a child node.
|
5
5
|
class Rewriter::GotoScope < Rewriter::Scope
|
6
|
-
# Initialize a
|
6
|
+
# Initialize a GotoScope.
|
7
7
|
#
|
8
8
|
# @param instance [Synvert::Core::Rewriter::Instance]
|
9
|
-
# @param child_node_name [Symbol|
|
10
|
-
# @
|
9
|
+
# @param child_node_name [Symbol|String] name of child node
|
10
|
+
# @yield run on the child node
|
11
11
|
def initialize(instance, child_node_name, &block)
|
12
|
-
|
12
|
+
super(instance, &block)
|
13
13
|
@child_node_name = child_node_name
|
14
|
-
@block = block
|
15
14
|
end
|
16
15
|
|
17
|
-
# Go to a child now, then run the block code
|
16
|
+
# Go to a child now, then run the block code on the the child node.
|
18
17
|
def process
|
19
18
|
current_node = @instance.current_node
|
20
19
|
return unless current_node
|
@@ -3,17 +3,16 @@
|
|
3
3
|
module Synvert::Core
|
4
4
|
# WithinScope finds out nodes which match rules, then changes its scope to matching node.
|
5
5
|
class Rewriter::WithinScope < Rewriter::Scope
|
6
|
-
# Initialize a
|
6
|
+
# Initialize a WithinScope.
|
7
7
|
#
|
8
8
|
# @param instance [Synvert::Core::Rewriter::Instance]
|
9
9
|
# @param rules [Hash]
|
10
10
|
# @param options [Hash]
|
11
|
-
# @
|
11
|
+
# @yield run on all matching nodes
|
12
12
|
def initialize(instance, rules, options = {}, &block)
|
13
|
-
|
13
|
+
super(instance, &block)
|
14
14
|
@rules = rules
|
15
15
|
@options = options
|
16
|
-
@block = block
|
17
16
|
end
|
18
17
|
|
19
18
|
# Find out the matching nodes.
|
@@ -43,6 +42,8 @@ module Synvert::Core
|
|
43
42
|
private
|
44
43
|
|
45
44
|
# Find the matching nodes only in current or direct children.
|
45
|
+
#
|
46
|
+
# @param current_node [Parser::AST::Node]
|
46
47
|
def find_direct_matching_nodes(current_node)
|
47
48
|
matching_nodes = []
|
48
49
|
if current_node.is_a?(Parser::AST::Node)
|
@@ -62,6 +63,8 @@ module Synvert::Core
|
|
62
63
|
end
|
63
64
|
|
64
65
|
# Find matching nodes in all recursive children.
|
66
|
+
#
|
67
|
+
# @param current_node [Parser::AST::Node]
|
65
68
|
def find_recursive_matching_nodes(current_node)
|
66
69
|
matching_nodes = []
|
67
70
|
if current_node.is_a?(Parser::AST::Node)
|
@@ -81,6 +84,8 @@ module Synvert::Core
|
|
81
84
|
end
|
82
85
|
|
83
86
|
# Find matching nodes in recursive children but do not continue on matching nodes.
|
87
|
+
#
|
88
|
+
# @param current_node [Parser::AST::Node]
|
84
89
|
def find_matching_nodes(current_node)
|
85
90
|
matching_nodes = []
|
86
91
|
if current_node.is_a?(Parser::AST::Node)
|
@@ -3,5 +3,13 @@
|
|
3
3
|
module Synvert::Core
|
4
4
|
# Scope finds out nodes which match rules.
|
5
5
|
class Rewriter::Scope
|
6
|
+
# Initialize a Scope
|
7
|
+
#
|
8
|
+
# @param instance [Synvert::Core::Rewriter::Instance]
|
9
|
+
# @yield run on a scope
|
10
|
+
def initialize(instance, &block)
|
11
|
+
@instance = instance
|
12
|
+
@block = block
|
13
|
+
end
|
6
14
|
end
|
7
15
|
end
|