synvert-core 0.63.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 +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
@@ -1,11 +1,41 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Parser::AST
|
4
|
-
# Parser::AST::Node
|
4
|
+
# Extend Parser::AST::Node.
|
5
|
+
# {https://github.com/whitequark/parser/blob/master/lib/parser/ast/node.rb}
|
6
|
+
#
|
7
|
+
# Rules
|
8
|
+
#
|
9
|
+
# Synvert compares ast nodes with key / value pairs, each ast node has
|
10
|
+
# multiple attributes, e.g. +receiver+, +message+ and +arguments+, it
|
11
|
+
# matches only when all of key / value pairs match.
|
12
|
+
#
|
13
|
+
# +type: 'send', message: :include, arguments: ['FactoryGirl::Syntax::Methods']+
|
14
|
+
#
|
15
|
+
# Synvert does comparison based on the value type
|
16
|
+
#
|
17
|
+
# 1. if value is a symbol, then compares ast node value as symbol, e.g. +message: :include+
|
18
|
+
# 2. if value is a string, then compares ast node original source code, e.g. +name: 'Synvert::Application'+
|
19
|
+
# 3. if value is a regexp, then compares ast node original source code, e.g. +message: /find_all_by_/+
|
20
|
+
# 4. if value is an array, then compares each ast node, e.g. +arguments: ['FactoryGirl::Syntax::Methods']+
|
21
|
+
# 5. if value is nil, then check if ast node is nil, e.g. +arguments: [nil]+
|
22
|
+
# 6. if value is true or false, then check if ast node is :true or :false, e.g. +arguments: [false]+
|
23
|
+
# 7. if value is ast, then compare ast node directly, e.g. +to_ast: Parser::CurrentRuby.parse("self.class.serialized_attributes")+
|
24
|
+
#
|
25
|
+
# It can also compare nested key / value pairs, like
|
26
|
+
#
|
27
|
+
# +type: 'send', receiver: { type: 'send', receiver: { type: 'send', message: 'config' }, message: 'active_record' }, message: 'identity_map='+
|
28
|
+
#
|
29
|
+
# Source Code to Ast Node
|
30
|
+
# {https://synvert-playground.xinminlabs.com}
|
5
31
|
class Node
|
6
|
-
# Get name
|
7
|
-
#
|
8
|
-
#
|
32
|
+
# Get the name of node.
|
33
|
+
# It supports :arg, :blockarg, :class, :const, :cvar, :def, :defs, :ivar,
|
34
|
+
# :lvar, :mlhs, :module and :restarg nodes.
|
35
|
+
# @example
|
36
|
+
# node # => s(:class, s(:const, nil, :Synvert), nil, nil)
|
37
|
+
# node.name # => s(:const, nil, :Synvert)
|
38
|
+
# @return [Parser::AST::Node] name of node.
|
9
39
|
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
10
40
|
def name
|
11
41
|
case type
|
@@ -20,9 +50,12 @@ module Parser::AST
|
|
20
50
|
end
|
21
51
|
end
|
22
52
|
|
23
|
-
# Get parent_class
|
24
|
-
#
|
25
|
-
# @
|
53
|
+
# Get parent_class of node.
|
54
|
+
# It supports :class node.
|
55
|
+
# @example
|
56
|
+
# node # s(:class, s(:const, nil, :Post), s(:const, s(:const, nil, :ActiveRecord), :Base), nil)
|
57
|
+
# node.parent_class # s(:const, s(:const, nil, :ActiveRecord), :Base)
|
58
|
+
# @return [Parser::AST::Node] parent_class of node.
|
26
59
|
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
27
60
|
def parent_class
|
28
61
|
if :class == type
|
@@ -32,9 +65,12 @@ module Parser::AST
|
|
32
65
|
end
|
33
66
|
end
|
34
67
|
|
35
|
-
# Get parent constant
|
36
|
-
#
|
37
|
-
# @
|
68
|
+
# Get parent constant of node.
|
69
|
+
# It supports :const node.
|
70
|
+
# @example
|
71
|
+
# node # s(:const, s(:const, nil, :Synvert), :Node)
|
72
|
+
# node.parent_const # s(:const, nil, :Synvert)
|
73
|
+
# @return [Parser::AST::Node] parent const of node.
|
38
74
|
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
39
75
|
def parent_const
|
40
76
|
if :const == type
|
@@ -44,9 +80,12 @@ module Parser::AST
|
|
44
80
|
end
|
45
81
|
end
|
46
82
|
|
47
|
-
# Get receiver
|
48
|
-
#
|
49
|
-
# @
|
83
|
+
# Get receiver of node.
|
84
|
+
# It support :csend and :send nodes.
|
85
|
+
# @example
|
86
|
+
# node # s(:send, s(:const, nil, :FactoryGirl), :create, s(:sym, :post))
|
87
|
+
# node.receiver # s(:const, nil, :FactoryGirl)
|
88
|
+
# @return [Parser::AST::Node] receiver of node.
|
50
89
|
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
51
90
|
def receiver
|
52
91
|
if %i[csend send].include?(type)
|
@@ -56,9 +95,12 @@ module Parser::AST
|
|
56
95
|
end
|
57
96
|
end
|
58
97
|
|
59
|
-
# Get message
|
60
|
-
#
|
61
|
-
# @
|
98
|
+
# Get message of node.
|
99
|
+
# It support :csend, :send, :super and :zsuper nodes.
|
100
|
+
# @example
|
101
|
+
# node # s(:send, s(:const, nil, :FactoryGirl), :create, s(:sym, :post))
|
102
|
+
# node.message # :create
|
103
|
+
# @return [Symbol] mesage of node.
|
62
104
|
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
63
105
|
def message
|
64
106
|
case type
|
@@ -71,9 +113,12 @@ module Parser::AST
|
|
71
113
|
end
|
72
114
|
end
|
73
115
|
|
74
|
-
# Get arguments
|
75
|
-
#
|
76
|
-
# @
|
116
|
+
# Get arguments of node.
|
117
|
+
# It supports :block, :csend, :def, :defined?, :defs and :send nodes.
|
118
|
+
# @example
|
119
|
+
# node # s(:send, s(:const, nil, :FactoryGirl), :create, s(:sym, :post), s(:hash, s(:pair, s(:sym, :title), s(:str, "post"))))
|
120
|
+
# node.arguments # [s(:sym, :post), s(:hash, s(:pair, s(:sym, :title), s(:str, "post")))]
|
121
|
+
# @return [Array<Parser::AST::Node>] arguments of node.
|
77
122
|
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
78
123
|
def arguments
|
79
124
|
case type
|
@@ -90,9 +135,12 @@ module Parser::AST
|
|
90
135
|
end
|
91
136
|
end
|
92
137
|
|
93
|
-
# Get caller
|
94
|
-
#
|
95
|
-
# @
|
138
|
+
# Get caller of node.
|
139
|
+
# It support :block node.
|
140
|
+
# @example
|
141
|
+
# node # s(:block, s(:send, s(:const, nil, :RSpec), :configure), s(:args, s(:arg, :config)), nil)
|
142
|
+
# node.caller # s(:send, s(:const, nil, :RSpec), :configure)
|
143
|
+
# @return [Parser::AST::Node] caller of node.
|
96
144
|
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
97
145
|
def caller
|
98
146
|
if :block == type
|
@@ -102,9 +150,12 @@ module Parser::AST
|
|
102
150
|
end
|
103
151
|
end
|
104
152
|
|
105
|
-
# Get body
|
106
|
-
#
|
107
|
-
# @
|
153
|
+
# Get body of node.
|
154
|
+
# It supports :begin, :block, :class, :def, :defs and :module node.
|
155
|
+
# @example
|
156
|
+
# node # s(:block, s(:send, s(:const, nil, :RSpec), :configure), s(:args, s(:arg, :config)), s(:send, nil, :include, s(:const, s(:const, nil, :EmailSpec), :Helpers)))
|
157
|
+
# node.body # [s(:send, nil, :include, s(:const, s(:const, nil, :EmailSpec), :Helpers))]
|
158
|
+
# @return [Array<Parser::AST::Node>] body of node.
|
108
159
|
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
109
160
|
def body
|
110
161
|
case type
|
@@ -123,9 +174,12 @@ module Parser::AST
|
|
123
174
|
end
|
124
175
|
end
|
125
176
|
|
126
|
-
# Get condition
|
127
|
-
#
|
128
|
-
# @
|
177
|
+
# Get condition of node.
|
178
|
+
# It supports :if node.
|
179
|
+
# @example
|
180
|
+
# node # s(:if, s(:defined?, s(:const, nil, :Bundler)), nil, nil)
|
181
|
+
# node.condition # s(:defined?, s(:const, nil, :Bundler))
|
182
|
+
# @return [Parser::AST::Node] condition of node.
|
129
183
|
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
130
184
|
def condition
|
131
185
|
if :if == type
|
@@ -135,9 +189,11 @@ module Parser::AST
|
|
135
189
|
end
|
136
190
|
end
|
137
191
|
|
138
|
-
# Get keys
|
139
|
-
#
|
140
|
-
#
|
192
|
+
# Get keys of :hash node.
|
193
|
+
# @example
|
194
|
+
# node # s(:hash, s(:pair, s(:sym, :foo), s(:sym, :bar)), s(:pair, s(:str, "foo"), s(:str, "bar")))
|
195
|
+
# node.keys # [s(:sym, :foo), s(:str, "foo")]
|
196
|
+
# @return [Array<Parser::AST::Node>] keys of node.
|
141
197
|
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
142
198
|
def keys
|
143
199
|
if :hash == type
|
@@ -147,9 +203,11 @@ module Parser::AST
|
|
147
203
|
end
|
148
204
|
end
|
149
205
|
|
150
|
-
# Get values
|
151
|
-
#
|
152
|
-
#
|
206
|
+
# Get values of :hash node.
|
207
|
+
# @example
|
208
|
+
# node # s(:hash, s(:pair, s(:sym, :foo), s(:sym, :bar)), s(:pair, s(:str, "foo"), s(:str, "bar")))
|
209
|
+
# node.values # [s(:sym, :bar), s(:str, "bar")]
|
210
|
+
# @return [Array<Parser::AST::Node>] values of node.
|
153
211
|
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
154
212
|
def values
|
155
213
|
if :hash == type
|
@@ -159,9 +217,11 @@ module Parser::AST
|
|
159
217
|
end
|
160
218
|
end
|
161
219
|
|
162
|
-
#
|
163
|
-
#
|
164
|
-
#
|
220
|
+
# Check if :hash node contains specified key.
|
221
|
+
# @example
|
222
|
+
# node # s(:hash, s(:pair, s(:sym, :foo), s(:sym, :bar)))
|
223
|
+
# node.key?(:foo) # true
|
224
|
+
# @param [Symbol, String] key value.
|
165
225
|
# @return [Boolean] true if specified key exists.
|
166
226
|
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
167
227
|
def key?(key)
|
@@ -172,10 +232,12 @@ module Parser::AST
|
|
172
232
|
end
|
173
233
|
end
|
174
234
|
|
175
|
-
# Get hash value node according to specified key.
|
176
|
-
#
|
177
|
-
#
|
178
|
-
#
|
235
|
+
# Get :hash value node according to specified key.
|
236
|
+
# @example
|
237
|
+
# node # s(:hash, s(:pair, s(:sym, :foo), s(:sym, :bar)))
|
238
|
+
# node.hash_value(:foo) # s(:sym, :bar)
|
239
|
+
# @param [Symbol, String] key value.
|
240
|
+
# @return [Parser::AST::Node] hash value of node.
|
179
241
|
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
180
242
|
def hash_value(key)
|
181
243
|
if :hash == type
|
@@ -187,8 +249,10 @@ module Parser::AST
|
|
187
249
|
end
|
188
250
|
|
189
251
|
# Get key node of hash :pair node.
|
190
|
-
#
|
191
|
-
#
|
252
|
+
# @example
|
253
|
+
# node # s(:pair, s(:sym, :foo), s(:str, "bar"))
|
254
|
+
# node.key # s(:sym, :foo)
|
255
|
+
# @return [Parser::AST::Node] key of node.
|
192
256
|
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
193
257
|
def key
|
194
258
|
if :pair == type
|
@@ -199,8 +263,10 @@ module Parser::AST
|
|
199
263
|
end
|
200
264
|
|
201
265
|
# Get value node of hash :pair node.
|
202
|
-
#
|
203
|
-
#
|
266
|
+
# @example
|
267
|
+
# node # s(:pair, s(:sym, :foo), s(:str, "bar"))
|
268
|
+
# node.value # s(:str, "bar")
|
269
|
+
# @return [Parser::AST::Node] value of node.
|
204
270
|
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
205
271
|
def value
|
206
272
|
if :pair == type
|
@@ -210,9 +276,12 @@ module Parser::AST
|
|
210
276
|
end
|
211
277
|
end
|
212
278
|
|
213
|
-
# Return the left value.
|
214
|
-
#
|
215
|
-
# @
|
279
|
+
# Return the left value of node.
|
280
|
+
# It supports :and, :cvagn, :lvasgn, :masgn, :or and :or_asgn nodes.
|
281
|
+
# @example
|
282
|
+
# node # s(:masgn, s(:mlhs, s(:lvasgn, :a), s(:lvasgn, :b)), s(:array, s(:int, 1), s(:int, 2)))
|
283
|
+
# node.left_value # s(:mlhs, s(:lvasgn, :a), s(:lvasgn, :b))
|
284
|
+
# @return [Parser::AST::Node] left value of node.
|
216
285
|
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
217
286
|
def left_value
|
218
287
|
if %i[masgn lvasgn ivasgn cvasgn and or].include? type
|
@@ -224,9 +293,12 @@ module Parser::AST
|
|
224
293
|
end
|
225
294
|
end
|
226
295
|
|
227
|
-
# Return the right value.
|
228
|
-
#
|
229
|
-
# @
|
296
|
+
# Return the right value of node.
|
297
|
+
# It supports :cvasgn, :ivasgn, :lvasgn, :masgn, :or and :or_asgn nodes.
|
298
|
+
# @example
|
299
|
+
# node # s(:masgn, s(:mlhs, s(:lvasgn, :a), s(:lvasgn, :b)), s(:array, s(:int, 1), s(:int, 2)))
|
300
|
+
# node.right_value # s(:array, s(:int, 1), s(:int, 2))
|
301
|
+
# @return [Array<Parser::AST::Node>] right value of node.
|
230
302
|
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
231
303
|
def right_value
|
232
304
|
if %i[masgn lvasgn ivasgn cvasgn or_asgn and or].include? type
|
@@ -236,8 +308,11 @@ module Parser::AST
|
|
236
308
|
end
|
237
309
|
end
|
238
310
|
|
239
|
-
# Return the exact value.
|
240
|
-
#
|
311
|
+
# Return the exact value of node.
|
312
|
+
# It supports :array, :begin, :erange, :false, :float, :irange, :int, :str, :sym and :true nodes.
|
313
|
+
# @example
|
314
|
+
# node # s(:array, s(:str, "str"), s(:sym, :str)) ["str", :str]
|
315
|
+
# node.to_value # ['str', :str]
|
241
316
|
# @return [Object] exact value.
|
242
317
|
# @raise [Synvert::Core::MethodNotSupported] if calls on other node.
|
243
318
|
def to_value
|
@@ -261,10 +336,11 @@ module Parser::AST
|
|
261
336
|
end
|
262
337
|
end
|
263
338
|
|
264
|
-
# Respond key value for hash node, e.g.
|
265
|
-
#
|
266
|
-
#
|
267
|
-
#
|
339
|
+
# Respond key value and source for hash node, e.g.
|
340
|
+
# @example
|
341
|
+
# node # s(:hash, s(:pair, s(:sym, :foo), s(:sym, :bar)))
|
342
|
+
# node.foo_value # :bar
|
343
|
+
# node.foo_source # ":bar"
|
268
344
|
def method_missing(method_name, *args, &block)
|
269
345
|
if :args == type && children.respond_to?(method_name)
|
270
346
|
return children.send(method_name, *args, &block)
|
@@ -299,12 +375,9 @@ module Parser::AST
|
|
299
375
|
super
|
300
376
|
end
|
301
377
|
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
end
|
306
|
-
end
|
307
|
-
|
378
|
+
# Return the debug info.
|
379
|
+
#
|
380
|
+
# @return [String] file, line, source and node.
|
308
381
|
def debug_info
|
309
382
|
"\n" +
|
310
383
|
[
|
@@ -315,37 +388,37 @@ module Parser::AST
|
|
315
388
|
].join("\n")
|
316
389
|
end
|
317
390
|
|
318
|
-
# Get the file name of
|
391
|
+
# Get the file name of node.
|
319
392
|
#
|
320
393
|
# @return [String] file name.
|
321
394
|
def filename
|
322
395
|
loc.expression&.source_buffer.name
|
323
396
|
end
|
324
397
|
|
325
|
-
# Get the source code of
|
398
|
+
# Get the source code of node.
|
326
399
|
#
|
327
400
|
# @return [String] source code.
|
328
401
|
def to_source
|
329
402
|
loc.expression&.source
|
330
403
|
end
|
331
404
|
|
332
|
-
# Get the column of
|
405
|
+
# Get the column of node.
|
333
406
|
#
|
334
407
|
# @return [Integer] column.
|
335
408
|
def column
|
336
409
|
loc.expression.column
|
337
410
|
end
|
338
411
|
|
339
|
-
# Get the line of
|
412
|
+
# Get the line of node.
|
340
413
|
#
|
341
414
|
# @return [Integer] line.
|
342
415
|
def line
|
343
416
|
loc.expression.line
|
344
417
|
end
|
345
418
|
|
346
|
-
# Get child node by
|
419
|
+
# Get child node by the name.
|
347
420
|
#
|
348
|
-
# @param [String] name of child node.
|
421
|
+
# @param child_name [String] name of child node.
|
349
422
|
# @return [Parser::AST::Node] the child node.
|
350
423
|
def child_node_by_name(child_name)
|
351
424
|
direct_child_name, nested_child_name = child_name.to_s.split('.', 2)
|
@@ -382,7 +455,7 @@ module Parser::AST
|
|
382
455
|
|
383
456
|
# Get the source range of child node.
|
384
457
|
#
|
385
|
-
# @param [String] name of child node.
|
458
|
+
# @param child_name [String] name of child node.
|
386
459
|
# @return [Parser::Source::Range] source range of child node.
|
387
460
|
def child_node_range(child_name)
|
388
461
|
case [type, child_name.to_sym]
|
@@ -469,7 +542,7 @@ module Parser::AST
|
|
469
542
|
end
|
470
543
|
end
|
471
544
|
|
472
|
-
# Recursively iterate all child nodes of
|
545
|
+
# Recursively iterate all child nodes of node.
|
473
546
|
#
|
474
547
|
# @yield [child] Gives a child node.
|
475
548
|
# @yieldparam child [Parser::AST::Node] child node
|
@@ -482,8 +555,12 @@ module Parser::AST
|
|
482
555
|
end
|
483
556
|
end
|
484
557
|
|
485
|
-
# Match
|
486
|
-
#
|
558
|
+
# Match node with rules.
|
559
|
+
# It provides some additional keywords to match rules, +any+, +contain+, +not+, +in+, +not_in+, +gt+, +gte+, +lt+, +lte+.
|
560
|
+
# @example
|
561
|
+
# type: 'send', arguments: { any: 'Lifo::ShowExceptions' }
|
562
|
+
# type: { in: ['send', 'csend'] }
|
563
|
+
# type: :send, arguments: { length: { gt: 2 } }
|
487
564
|
# @param rules [Hash] rules to match.
|
488
565
|
# @return true if matches.
|
489
566
|
def match?(rules)
|
@@ -517,11 +594,10 @@ module Parser::AST
|
|
517
594
|
|
518
595
|
# Get rewritten source code.
|
519
596
|
# @example
|
520
|
-
# node.rewritten_source("create({{arguments}})")
|
521
|
-
#
|
597
|
+
# node.rewritten_source("create({{arguments}})") # "create(:post)"
|
522
598
|
# @param code [String] raw code.
|
523
|
-
# @return [String] rewritten code, replace string in block {{ }} in raw code.
|
524
|
-
# @raise [Synvert::Core::MethodNotSupported] if string in block {{ }} does not support.
|
599
|
+
# @return [String] rewritten code, replace string in block !{{ }} in raw code.
|
600
|
+
# @raise [Synvert::Core::MethodNotSupported] if string in block !{{ }} does not support.
|
525
601
|
def rewritten_source(code)
|
526
602
|
code.gsub(/{{(.*?)}}/m) do
|
527
603
|
old_code = Regexp.last_match(1)
|
@@ -563,42 +639,66 @@ module Parser::AST
|
|
563
639
|
end
|
564
640
|
end
|
565
641
|
|
566
|
-
#
|
642
|
+
# Strip curly braces for hash.
|
643
|
+
# @example
|
644
|
+
# node # s(:hash, s(:pair, s(:sym, :foo), s(:str, "bar")))
|
645
|
+
# node.strip_curly_braces # "foo: 'bar'"
|
646
|
+
# @return [String]
|
567
647
|
def strip_curly_braces
|
568
648
|
return to_source unless type == :hash
|
569
649
|
|
570
650
|
to_source.sub(/^{(.*)}$/) { Regexp.last_match(1).strip }
|
571
651
|
end
|
572
652
|
|
573
|
-
#
|
653
|
+
# Wrap curly braces for hash.
|
654
|
+
# @example
|
655
|
+
# node # s(:hash, s(:pair, s(:sym, :foo), s(:str, "bar")))
|
656
|
+
# node.wrap_curly_braces # "{ foo: 'bar' }"
|
657
|
+
# @return [String]
|
574
658
|
def wrap_curly_braces
|
575
659
|
return to_source unless type == :hash
|
576
660
|
|
577
661
|
"{ #{to_source} }"
|
578
662
|
end
|
579
663
|
|
580
|
-
#
|
664
|
+
# Get single quote string.
|
665
|
+
# @example
|
666
|
+
# node # s(:str, "foobar")
|
667
|
+
# node.to_single_quote # "'foobar'"
|
668
|
+
# @return [String]
|
581
669
|
def to_single_quote
|
582
670
|
return to_source unless type == :str
|
583
671
|
|
584
672
|
"'#{to_value}'"
|
585
673
|
end
|
586
674
|
|
587
|
-
#
|
675
|
+
# Convert string to symbol.
|
676
|
+
# @example
|
677
|
+
# node # s(:str, "foobar")
|
678
|
+
# node.to_symbol # ":foobar"
|
679
|
+
# @return [String]
|
588
680
|
def to_symbol
|
589
681
|
return to_source unless type == :str
|
590
682
|
|
591
683
|
":#{to_value}"
|
592
684
|
end
|
593
685
|
|
594
|
-
#
|
686
|
+
# Convert symbol to string.
|
687
|
+
# @example
|
688
|
+
# node # s(:sym, :foobar)
|
689
|
+
# node.to_string # "foobar"
|
690
|
+
# @return [String]
|
595
691
|
def to_string
|
596
692
|
return to_source unless type == :sym
|
597
693
|
|
598
694
|
to_value.to_s
|
599
695
|
end
|
600
696
|
|
601
|
-
#
|
697
|
+
# Convert lambda {} to -> {}
|
698
|
+
# @example
|
699
|
+
# node # s(:block, s(:send, nil, :lambda), s(:args), s(:send, nil, :foobar))
|
700
|
+
# node.to_lambda_literal # "-> { foobar }"
|
701
|
+
# @return [String]
|
602
702
|
def to_lambda_literal
|
603
703
|
if type == :block && caller.type == :send && caller.receiver.nil? && caller.message == :lambda
|
604
704
|
new_source = to_source
|
@@ -620,7 +720,7 @@ module Parser::AST
|
|
620
720
|
#
|
621
721
|
# @param actual [Object] actual value.
|
622
722
|
# @param expected [Object] expected value.
|
623
|
-
# @return [
|
723
|
+
# @return [Boolean]
|
624
724
|
# @raise [Synvert::Core::MethodNotSupported] if expected class is not supported.
|
625
725
|
def match_value?(actual, expected)
|
626
726
|
return true if actual == expected
|
@@ -678,7 +778,7 @@ module Parser::AST
|
|
678
778
|
#
|
679
779
|
# @example
|
680
780
|
# flat_hash(type: 'block', caller: {type: 'send', receiver: 'RSpec'})
|
681
|
-
#
|
781
|
+
# # {[:type] => 'block', [:caller, :type] => 'send', [:caller, :receiver] => 'RSpec'}
|
682
782
|
# @param h [Hash] original hash.
|
683
783
|
# @return flatten hash.
|
684
784
|
def flat_hash(h, k = [])
|
@@ -695,8 +795,7 @@ module Parser::AST
|
|
695
795
|
|
696
796
|
# Get actual value from the node.
|
697
797
|
#
|
698
|
-
# @param
|
699
|
-
# @param multi_keys [Array<Symbol>]
|
798
|
+
# @param multi_keys [Array<Symbol, String>]
|
700
799
|
# @return [Object] actual value.
|
701
800
|
def actual_value(multi_keys)
|
702
801
|
multi_keys.inject(self) { |n, key| n.send(key) if n }
|
@@ -711,6 +810,7 @@ module Parser::AST
|
|
711
810
|
multi_keys.inject(rules) { |o, key| o[key] }
|
712
811
|
end
|
713
812
|
|
813
|
+
# Wrap the string with single or double quote.
|
714
814
|
def wrap_quote(string)
|
715
815
|
if string.include?("'")
|
716
816
|
"\"#{string}\""
|
@@ -719,6 +819,7 @@ module Parser::AST
|
|
719
819
|
end
|
720
820
|
end
|
721
821
|
|
822
|
+
# Unwrap the quote from the string.
|
722
823
|
def unwrap_quote(string)
|
723
824
|
if (string[0] == '"' && string[-1] == '"') || (string[0] == "'" && string[-1] == "'")
|
724
825
|
string[1...-1]
|
@@ -1,17 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Synvert::Core
|
4
|
-
# AppendAction
|
4
|
+
# AppendAction appends code to the bottom of node body.
|
5
5
|
class Rewriter::AppendAction < Rewriter::Action
|
6
|
+
private
|
7
|
+
|
6
8
|
END_LENGTH = "\nend".length
|
7
9
|
|
10
|
+
# Calculate the begin the end positions.
|
8
11
|
def calculate_position
|
9
12
|
@begin_pos = :begin == @node.type ? @node.loc.expression.end_pos : @node.loc.expression.end_pos - @node.column - END_LENGTH
|
10
13
|
@end_pos = @begin_pos
|
11
14
|
end
|
12
15
|
|
13
|
-
private
|
14
|
-
|
15
16
|
# Indent of the node.
|
16
17
|
#
|
17
18
|
# @param node [Parser::AST::Node]
|
@@ -1,23 +1,30 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Synvert::Core
|
4
|
-
# DeleteAction
|
4
|
+
# DeleteAction deletes child nodes.
|
5
5
|
class Rewriter::DeleteAction < Rewriter::Action
|
6
|
+
# Initialize a DeleteAction.
|
7
|
+
#
|
8
|
+
# @param instance [Synvert::Core::Rewriter::Instance]
|
9
|
+
# @param selectors [Array<Symbol, String>] used to select child nodes
|
6
10
|
def initialize(instance, *selectors)
|
7
11
|
super(instance, nil)
|
8
12
|
@selectors = selectors
|
9
13
|
end
|
10
14
|
|
15
|
+
# The rewritten code, always empty string.
|
16
|
+
def rewritten_code
|
17
|
+
''
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
# Calculate the begin and end positions.
|
11
23
|
def calculate_position
|
12
24
|
@begin_pos = @selectors.map { |selector| @node.child_node_range(selector) }.compact.map(&:begin_pos).min
|
13
25
|
@end_pos = @selectors.map { |selector| @node.child_node_range(selector) }.compact.map(&:end_pos).max
|
14
26
|
squeeze_spaces
|
15
27
|
remove_comma
|
16
28
|
end
|
17
|
-
|
18
|
-
# The rewritten code, always empty string.
|
19
|
-
def rewritten_code
|
20
|
-
''
|
21
|
-
end
|
22
29
|
end
|
23
30
|
end
|
@@ -3,23 +3,32 @@
|
|
3
3
|
module Synvert::Core
|
4
4
|
# InsertAction to add code to the node.
|
5
5
|
class Rewriter::InsertAction < Rewriter::Action
|
6
|
-
|
6
|
+
# Initialize an InsertAction.
|
7
|
+
#
|
8
|
+
# @param instance [Synvert::Core::Rewriter::Instance]
|
9
|
+
# @param code [String] to be inserted
|
10
|
+
# @param at [String] position to insert, beginning or end
|
11
|
+
# @param to [<Symbol|String>] name of child node
|
12
|
+
def initialize(instance, code, at: 'end', to: nil)
|
7
13
|
super(instance, code)
|
8
14
|
@at = at
|
9
15
|
@to = to
|
10
16
|
end
|
11
17
|
|
12
|
-
def calculate_position
|
13
|
-
node_range = @to ? @node.child_node_range(@to) : @node.loc.expression
|
14
|
-
@begin_pos = @at == 'end' ? node_range.end_pos : node_range.begin_pos
|
15
|
-
@end_pos = @begin_pos
|
16
|
-
end
|
17
|
-
|
18
18
|
# The rewritten source code.
|
19
19
|
#
|
20
20
|
# @return [String] rewritten code.
|
21
21
|
def rewritten_code
|
22
22
|
rewritten_source
|
23
23
|
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# Calculate the begin and end positions.
|
28
|
+
def calculate_position
|
29
|
+
node_range = @to ? @node.child_node_range(@to) : @node.loc.expression
|
30
|
+
@begin_pos = @at == 'end' ? node_range.end_pos : node_range.begin_pos
|
31
|
+
@end_pos = @begin_pos
|
32
|
+
end
|
24
33
|
end
|
25
34
|
end
|
@@ -3,13 +3,14 @@
|
|
3
3
|
module Synvert::Core
|
4
4
|
# InsertAfterAction to insert code next to the node.
|
5
5
|
class Rewriter::InsertAfterAction < Rewriter::Action
|
6
|
+
private
|
7
|
+
|
8
|
+
# Calculate the begin and end positions.
|
6
9
|
def calculate_position
|
7
10
|
@begin_pos = @node.loc.expression.end_pos
|
8
11
|
@end_pos = @begin_pos
|
9
12
|
end
|
10
13
|
|
11
|
-
private
|
12
|
-
|
13
14
|
# Indent of the node.
|
14
15
|
#
|
15
16
|
# @param node [Parser::AST::Node]
|
@@ -3,8 +3,11 @@
|
|
3
3
|
module Synvert::Core
|
4
4
|
# PrependAction to prepend code to the top of node body.
|
5
5
|
class Rewriter::PrependAction < Rewriter::Action
|
6
|
+
private
|
7
|
+
|
6
8
|
DO_LENGTH = ' do'.length
|
7
9
|
|
10
|
+
# Calculate the begin and end positions.
|
8
11
|
def calculate_position
|
9
12
|
@begin_pos =
|
10
13
|
case @node.type
|
@@ -26,8 +29,6 @@ module Synvert::Core
|
|
26
29
|
@end_pos = @begin_pos
|
27
30
|
end
|
28
31
|
|
29
|
-
private
|
30
|
-
|
31
32
|
# Indent of the node.
|
32
33
|
#
|
33
34
|
# @param node [Parser::AST::Node]
|