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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -1
  3. data/Gemfile +0 -2
  4. data/README.md +73 -33
  5. data/lib/synvert/core/configuration.rb +12 -0
  6. data/lib/synvert/core/exceptions.rb +0 -4
  7. data/lib/synvert/core/node_ext.rb +206 -103
  8. data/lib/synvert/core/rewriter/action/append_action.rb +4 -3
  9. data/lib/synvert/core/rewriter/action/delete_action.rb +13 -6
  10. data/lib/synvert/core/rewriter/action/insert_action.rb +16 -7
  11. data/lib/synvert/core/rewriter/action/insert_after_action.rb +3 -2
  12. data/lib/synvert/core/rewriter/action/prepend_action.rb +3 -2
  13. data/lib/synvert/core/rewriter/action/remove_action.rb +16 -10
  14. data/lib/synvert/core/rewriter/action/replace_action.rb +13 -5
  15. data/lib/synvert/core/rewriter/action/replace_erb_stmt_with_expr_action.rb +18 -11
  16. data/lib/synvert/core/rewriter/action/replace_with_action.rb +6 -5
  17. data/lib/synvert/core/rewriter/action/wrap_action.rb +13 -5
  18. data/lib/synvert/core/rewriter/action.rb +20 -9
  19. data/lib/synvert/core/rewriter/any_value.rb +1 -0
  20. data/lib/synvert/core/rewriter/condition/if_exist_condition.rb +4 -0
  21. data/lib/synvert/core/rewriter/condition/if_only_exist_condition.rb +4 -0
  22. data/lib/synvert/core/rewriter/condition/unless_exist_condition.rb +4 -0
  23. data/lib/synvert/core/rewriter/condition.rb +11 -3
  24. data/lib/synvert/core/rewriter/gem_spec.rb +7 -4
  25. data/lib/synvert/core/rewriter/helper.rb +2 -2
  26. data/lib/synvert/core/rewriter/instance.rb +195 -94
  27. data/lib/synvert/core/rewriter/ruby_version.rb +4 -4
  28. data/lib/synvert/core/rewriter/scope/goto_scope.rb +5 -6
  29. data/lib/synvert/core/rewriter/scope/within_scope.rb +9 -4
  30. data/lib/synvert/core/rewriter/scope.rb +8 -0
  31. data/lib/synvert/core/rewriter/warning.rb +1 -1
  32. data/lib/synvert/core/rewriter.rb +90 -43
  33. data/lib/synvert/core/version.rb +1 -1
  34. data/lib/synvert/core.rb +0 -1
  35. data/spec/spec_helper.rb +0 -3
  36. data/spec/synvert/core/node_ext_spec.rb +28 -7
  37. data/spec/synvert/core/rewriter/action_spec.rb +0 -4
  38. data/spec/synvert/core/rewriter/gem_spec_spec.rb +11 -10
  39. data/spec/synvert/core/rewriter/instance_spec.rb +7 -17
  40. data/synvert-core-ruby.gemspec +2 -1
  41. metadata +21 -7
@@ -1,11 +1,41 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Parser::AST
4
- # Parser::AST::Node monkey patch.
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 node of :class, :module, :const, :mlhs, :def and :defs node.
7
- #
8
- # @return [Parser::AST::Node] name node.
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 node of :class node.
24
- #
25
- # @return [Parser::AST::Node] parent_class node.
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 node of :const node.
36
- #
37
- # @return [Parser::AST::Node] parent const node.
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 node of :send node.
48
- #
49
- # @return [Parser::AST::Node] receiver node.
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 node of :super or :send node.
60
- #
61
- # @return [Parser::AST::Node] mesage node.
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 node of :send, :block or :defined? node.
75
- #
76
- # @return [Array<Parser::AST::Node>] arguments node.
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 node of :block node.
94
- #
95
- # @return [Parser::AST::Node] caller node.
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 node of :begin or :block node.
106
- #
107
- # @return [Array<Parser::AST::Node>] body node.
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 node of :if node.
127
- #
128
- # @return [Parser::AST::Node] condition node.
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 node of :hash node.
139
- #
140
- # @return [Array<Parser::AST::Node>] keys node.
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 node of :hash node.
151
- #
152
- # @return [Array<Parser::AST::Node>] values node.
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
- # Test if hash node contains specified key.
163
- #
164
- # @param [Object] key value.
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
- # @param [Object] key value.
178
- # @return [Parser::AST::Node] value node.
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
- # @return [Parser::AST::Node] key node.
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
- # @return [Parser::AST::Node] value node.
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
- # @return [Parser::AST::Node] variable nodes.
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
- # @return [Array<Parser::AST::Node>] variable nodes.
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
- # Current node is s(:hash, s(:pair, s(:sym, :number), s(:int, 10)))
267
- # node.number_value is 10
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
- def to_s
303
- if :mlhs == type
304
- "(#{children.map(&:name).join(', ')})"
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 the current node.
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 current node.
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 current node.
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 current node.
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 child name.
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 current node.
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 current node with rules.
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
- case multi_keys.last
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
- actual_values = actual_value(self, multi_keys[0...-1])
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
- actual = actual_value(self, multi_keys[0...-1])
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
- actual = actual_value(self, multi_keys[0...-1])
506
- expected_values = expected_value(rules, multi_keys)
507
- expected_values.all? { |expected| !match_value?(actual, expected) }
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}})") #=> "create(:post)"
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
- # strip curly braces for hash
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
- # wrap curly braces for hash
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
- # get single quote string
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
- # convert string to symbol
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
- # convert symbol to string
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
- # convert lambda {} to -> {}
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 [Integer] -1, 0 or 1.
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
- # #=> {[:type] => 'block', [:caller, :type] => 'send', [:caller, :receiver] => 'RSpec'}
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 node [Parser::AST::Node]
697
- # @param multi_keys [Array<Symbol>]
798
+ # @param multi_keys [Array<Symbol, String>]
698
799
  # @return [Object] actual value.
699
- def actual_value(node, multi_keys)
700
- multi_keys.inject(node) { |n, key| n.send(key) if n }
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 to append code to the bottom of node body.
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 to delete child nodes.
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
- def initialize(instance, code, at:, to: nil)
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