synvert-core 0.62.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 +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
|