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
@@ -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,32 +555,38 @@ 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)
|
567
|
+
keywords = %i[any contain not in not_in gt gte lt lte]
|
490
568
|
flat_hash(rules).keys.all? do |multi_keys|
|
491
|
-
|
569
|
+
last_key = multi_keys.last
|
570
|
+
actual = keywords.include?(last_key) ? actual_value(multi_keys[0...-1]) : actual_value(multi_keys)
|
571
|
+
expected = expected_value(rules, multi_keys)
|
572
|
+
case last_key
|
492
573
|
when :any, :contain
|
493
|
-
|
494
|
-
expected = expected_value(rules, multi_keys)
|
495
|
-
actual_values.any? { |actual| match_value?(actual, expected) }
|
574
|
+
actual.any? { |actual_value| match_value?(actual_value, expected) }
|
496
575
|
when :not
|
497
|
-
actual = actual_value(self, multi_keys[0...-1])
|
498
|
-
expected = expected_value(rules, multi_keys)
|
499
576
|
!match_value?(actual, expected)
|
500
577
|
when :in
|
501
|
-
|
502
|
-
expected_values = expected_value(rules, multi_keys)
|
503
|
-
expected_values.any? { |expected| match_value?(actual, expected) }
|
578
|
+
expected.any? { |expected_value| match_value?(actual, expected_value) }
|
504
579
|
when :not_in
|
505
|
-
|
506
|
-
|
507
|
-
|
580
|
+
expected.all? { |expected_value| !match_value?(actual, expected_value) }
|
581
|
+
when :gt
|
582
|
+
actual > expected
|
583
|
+
when :gte
|
584
|
+
actual >= expected
|
585
|
+
when :lt
|
586
|
+
actual < expected
|
587
|
+
when :lte
|
588
|
+
actual <= expected
|
508
589
|
else
|
509
|
-
actual = actual_value(self, multi_keys)
|
510
|
-
expected = expected_value(rules, multi_keys)
|
511
590
|
match_value?(actual, expected)
|
512
591
|
end
|
513
592
|
end
|
@@ -515,11 +594,10 @@ module Parser::AST
|
|
515
594
|
|
516
595
|
# Get rewritten source code.
|
517
596
|
# @example
|
518
|
-
# node.rewritten_source("create({{arguments}})")
|
519
|
-
#
|
597
|
+
# node.rewritten_source("create({{arguments}})") # "create(:post)"
|
520
598
|
# @param code [String] raw code.
|
521
|
-
# @return [String] rewritten code, replace string in block {{ }} in raw code.
|
522
|
-
# @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.
|
523
601
|
def rewritten_source(code)
|
524
602
|
code.gsub(/{{(.*?)}}/m) do
|
525
603
|
old_code = Regexp.last_match(1)
|
@@ -561,42 +639,66 @@ module Parser::AST
|
|
561
639
|
end
|
562
640
|
end
|
563
641
|
|
564
|
-
#
|
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]
|
565
647
|
def strip_curly_braces
|
566
648
|
return to_source unless type == :hash
|
567
649
|
|
568
650
|
to_source.sub(/^{(.*)}$/) { Regexp.last_match(1).strip }
|
569
651
|
end
|
570
652
|
|
571
|
-
#
|
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]
|
572
658
|
def wrap_curly_braces
|
573
659
|
return to_source unless type == :hash
|
574
660
|
|
575
661
|
"{ #{to_source} }"
|
576
662
|
end
|
577
663
|
|
578
|
-
#
|
664
|
+
# Get single quote string.
|
665
|
+
# @example
|
666
|
+
# node # s(:str, "foobar")
|
667
|
+
# node.to_single_quote # "'foobar'"
|
668
|
+
# @return [String]
|
579
669
|
def to_single_quote
|
580
670
|
return to_source unless type == :str
|
581
671
|
|
582
672
|
"'#{to_value}'"
|
583
673
|
end
|
584
674
|
|
585
|
-
#
|
675
|
+
# Convert string to symbol.
|
676
|
+
# @example
|
677
|
+
# node # s(:str, "foobar")
|
678
|
+
# node.to_symbol # ":foobar"
|
679
|
+
# @return [String]
|
586
680
|
def to_symbol
|
587
681
|
return to_source unless type == :str
|
588
682
|
|
589
683
|
":#{to_value}"
|
590
684
|
end
|
591
685
|
|
592
|
-
#
|
686
|
+
# Convert symbol to string.
|
687
|
+
# @example
|
688
|
+
# node # s(:sym, :foobar)
|
689
|
+
# node.to_string # "foobar"
|
690
|
+
# @return [String]
|
593
691
|
def to_string
|
594
692
|
return to_source unless type == :sym
|
595
693
|
|
596
694
|
to_value.to_s
|
597
695
|
end
|
598
696
|
|
599
|
-
#
|
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]
|
600
702
|
def to_lambda_literal
|
601
703
|
if type == :block && caller.type == :send && caller.receiver.nil? && caller.message == :lambda
|
602
704
|
new_source = to_source
|
@@ -618,7 +720,7 @@ module Parser::AST
|
|
618
720
|
#
|
619
721
|
# @param actual [Object] actual value.
|
620
722
|
# @param expected [Object] expected value.
|
621
|
-
# @return [
|
723
|
+
# @return [Boolean]
|
622
724
|
# @raise [Synvert::Core::MethodNotSupported] if expected class is not supported.
|
623
725
|
def match_value?(actual, expected)
|
624
726
|
return true if actual == expected
|
@@ -676,7 +778,7 @@ module Parser::AST
|
|
676
778
|
#
|
677
779
|
# @example
|
678
780
|
# flat_hash(type: 'block', caller: {type: 'send', receiver: 'RSpec'})
|
679
|
-
#
|
781
|
+
# # {[:type] => 'block', [:caller, :type] => 'send', [:caller, :receiver] => 'RSpec'}
|
680
782
|
# @param h [Hash] original hash.
|
681
783
|
# @return flatten hash.
|
682
784
|
def flat_hash(h, k = [])
|
@@ -693,11 +795,10 @@ module Parser::AST
|
|
693
795
|
|
694
796
|
# Get actual value from the node.
|
695
797
|
#
|
696
|
-
# @param
|
697
|
-
# @param multi_keys [Array<Symbol>]
|
798
|
+
# @param multi_keys [Array<Symbol, String>]
|
698
799
|
# @return [Object] actual value.
|
699
|
-
def actual_value(
|
700
|
-
multi_keys.inject(
|
800
|
+
def actual_value(multi_keys)
|
801
|
+
multi_keys.inject(self) { |n, key| n.send(key) if n }
|
701
802
|
end
|
702
803
|
|
703
804
|
# Get expected value from rules.
|
@@ -709,6 +810,7 @@ module Parser::AST
|
|
709
810
|
multi_keys.inject(rules) { |o, key| o[key] }
|
710
811
|
end
|
711
812
|
|
813
|
+
# Wrap the string with single or double quote.
|
712
814
|
def wrap_quote(string)
|
713
815
|
if string.include?("'")
|
714
816
|
"\"#{string}\""
|
@@ -717,6 +819,7 @@ module Parser::AST
|
|
717
819
|
end
|
718
820
|
end
|
719
821
|
|
822
|
+
# Unwrap the quote from the string.
|
720
823
|
def unwrap_quote(string)
|
721
824
|
if (string[0] == '"' && string[-1] == '"') || (string[0] == "'" && string[-1] == "'")
|
722
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
|