synvert-core 0.62.1 → 0.64.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/CHANGELOG.md +9 -1
- data/Gemfile +0 -2
- 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 +206 -103
- 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 +7 -4
- 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/spec_helper.rb +0 -3
- data/spec/synvert/core/node_ext_spec.rb +28 -7
- data/spec/synvert/core/rewriter/action_spec.rb +0 -4
- data/spec/synvert/core/rewriter/gem_spec_spec.rb +11 -10
- data/spec/synvert/core/rewriter/instance_spec.rb +7 -17
- data/synvert-core-ruby.gemspec +2 -1
- metadata +21 -7
@@ -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
|