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.
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