synvert-core 0.60.0 → 0.62.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 91e00ecd8d7f5d6ff82a17580d088cc323d0e94b53a1488e6be50cbeb4a44b13
4
- data.tar.gz: 9e3f9dbb81cb07a27fdb8d0f2888d1c7827270d9b5bf9434ff0f649245de65a5
3
+ metadata.gz: 4e6217815771ca45d3fc81030b42ae126252ab800e127518e72c2f2b4dd2eb5c
4
+ data.tar.gz: 266cc5cda364f6df8100a290d393f879075b433acfd7ee70c780b37d23a83292
5
5
  SHA512:
6
- metadata.gz: 6c777f93827fa6485a6636571500f8def9cd0c8b7d910f61da7c309a84124e70415d8d86e97037ec4ee574ae783936267e446e6e1b870523fdb0ea4abea09f03
7
- data.tar.gz: 4fa8ef96adce5932eed3d927d0f878684c1bff3896829c9297df8cb20eda98f4324aed12a066e8c5b2b60996f87929cd31d911b2961414dc2e8c0356edfb3f35
6
+ metadata.gz: 89c3f93da22298305839c57fadb4963ea0973e16de10b2d2260c76e63927d25c302bbcd2c74515e79adeb24d2440ecba53025aaeeab0b173c6176adccb5d0875
7
+ data.tar.gz: df7a75da7a8bbecee35d4cc1afb862f6aa0184e96d484a6f207a88510dfac70098ea17cca794aefaac0938e37e96d8a91f7ba21738f2f116554238f02344e4c1
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 0.62.0 (2021-12-24)
4
+
5
+ * Support `csend` node
6
+ * Restrict `activesupport` version to `~> 6`
7
+ * Fix `prepend` action for `def` and `defs` nodes
8
+ * Fix `append` action for `def` and `defs` nodes
9
+
10
+ ## 0.61.0 (2021-12-10)
11
+
12
+ * Add `Node#child_node_by_name`
13
+ * Fix `Node#child_node_range` for array
14
+
3
15
  ## 0.60.0 (2021-12-02)
4
16
 
5
17
  * Add `to_string` to `sym` node
@@ -49,7 +49,7 @@ module Parser::AST
49
49
  # @return [Parser::AST::Node] receiver node.
50
50
  # @raise [Synvert::Core::MethodNotSupported] if calls on other node.
51
51
  def receiver
52
- if :send == type
52
+ if %i[csend send].include?(type)
53
53
  children[0]
54
54
  else
55
55
  raise Synvert::Core::MethodNotSupported, "receiver is not handled for #{debug_info}"
@@ -64,7 +64,7 @@ module Parser::AST
64
64
  case type
65
65
  when :super, :zsuper
66
66
  :super
67
- when :send
67
+ when :send, :csend
68
68
  children[1]
69
69
  else
70
70
  raise Synvert::Core::MethodNotSupported, "message is not handled for #{debug_info}"
@@ -81,7 +81,7 @@ module Parser::AST
81
81
  children[1]
82
82
  when :defs
83
83
  children[2]
84
- when :send
84
+ when :send, :csend
85
85
  children[2..-1]
86
86
  when :defined?
87
87
  children
@@ -343,6 +343,43 @@ module Parser::AST
343
343
  loc.expression.line
344
344
  end
345
345
 
346
+ # Get child node by child name.
347
+ #
348
+ # @param [String] name of child node.
349
+ # @return [Parser::AST::Node] the child node.
350
+ def child_node_by_name(child_name)
351
+ direct_child_name, nested_child_name = child_name.to_s.split('.', 2)
352
+ if respond_to?(direct_child_name)
353
+ child_node = send(direct_child_name)
354
+
355
+ if nested_child_name
356
+ if child_node.is_a?(Array)
357
+ child_direct_child_name, child_nested_child_name = nested_child_name.split('.', 2)
358
+ child_direct_child_node = child_direct_child_name =~ /\A\d+\z/ ? child_node[child_direct_child_name.to_i - 1] : child_node.send(child_direct_child_name)
359
+ return child_direct_child_node.child_node_by_name(child_nested_child_name) if child_nested_child_name
360
+ return child_direct_child_node if child_direct_child_node
361
+
362
+ raise Synvert::Core::MethodNotSupported,
363
+ "child_node_by_name is not handled for #{debug_info}, child_name: #{child_name}"
364
+ end
365
+
366
+ return child_node.child_node_by_name(nested_child_name)
367
+ end
368
+
369
+ return nil if child_node.nil?
370
+
371
+ return child_node if child_node.is_a?(Parser::AST::Node)
372
+
373
+ # arguments
374
+ return nil if child_node.empty?
375
+
376
+ return child_node
377
+ end
378
+
379
+ raise Synvert::Core::MethodNotSupported,
380
+ "child_node_by_name is not handled for #{debug_info}, child_name: #{child_name}"
381
+ end
382
+
346
383
  # Get the source range of child node.
347
384
  #
348
385
  # @param [String] name of child node.
@@ -363,15 +400,15 @@ module Parser::AST
363
400
  loc.operator
364
401
  when %i[defs self]
365
402
  Parser::Source::Range.new('(string)', loc.operator.begin_pos - 'self'.length, loc.operator.begin_pos)
366
- when %i[send dot]
403
+ when %i[send dot], %i[csend dot]
367
404
  loc.dot
368
- when %i[send message]
405
+ when %i[send message], %i[csend message]
369
406
  if loc.operator
370
407
  Parser::Source::Range.new('(string)', loc.selector.begin_pos, loc.operator.end_pos)
371
408
  else
372
409
  loc.selector
373
410
  end
374
- when %i[send parentheses]
411
+ when %i[send parentheses], %i[csend parentheses]
375
412
  if loc.begin && loc.end
376
413
  Parser::Source::Range.new('(string)', loc.begin.begin_pos, loc.end.end_pos)
377
414
  end
@@ -382,10 +419,10 @@ module Parser::AST
382
419
 
383
420
  if nested_child_name
384
421
  if child_node.is_a?(Array)
385
- child_direct_child_name, *child_nested_child_name = nested_child_name
386
- child_direct_child_node = child_direct_child_name =~ /\A\d+\z/ ? child_node[child_direct_child_name] : child_node.send(child_direct_child_name)
387
- if child_nested_child_name.length > 0
388
- return child_direct_child_node.child_node_range(child_nested_child_name.join('.'))
422
+ child_direct_child_name, child_nested_child_name = nested_child_name.split('.', 2)
423
+ child_direct_child_node = child_direct_child_name =~ /\A\d+\z/ ? child_node[child_direct_child_name.to_i - 1] : child_node.send(child_direct_child_name)
424
+ if child_nested_child_name
425
+ return child_direct_child_node.child_node_range(child_nested_child_name)
389
426
  elsif child_direct_child_node
390
427
  return (
391
428
  Parser::Source::Range.new(
@@ -486,8 +523,8 @@ module Parser::AST
486
523
  def rewritten_source(code)
487
524
  code.gsub(/{{(.*?)}}/m) do
488
525
  old_code = Regexp.last_match(1)
489
- if respond_to? old_code.split(/\.|\[/).first
490
- evaluated = instance_eval old_code
526
+ if respond_to?(old_code.split('.').first)
527
+ evaluated = child_node_by_name(old_code)
491
528
  case evaluated
492
529
  when Parser::AST::Node
493
530
  if evaluated.type == :args
@@ -556,7 +593,7 @@ module Parser::AST
556
593
  def to_string
557
594
  return to_source unless type == :sym
558
595
 
559
- "#{to_value}"
596
+ to_value.to_s
560
597
  end
561
598
 
562
599
  # convert lambda {} to -> {}
@@ -17,7 +17,7 @@ module Synvert::Core
17
17
  # @param node [Parser::AST::Node]
18
18
  # @return [String] n times whitesphace
19
19
  def indent(node)
20
- if %i[block class].include? node.type
20
+ if %i[block class def defs].include? node.type
21
21
  ' ' * (node.column + DEFAULT_INDENT)
22
22
  else
23
23
  ' ' * node.column
@@ -16,6 +16,10 @@ module Synvert::Core
16
16
  end
17
17
  when :class
18
18
  @node.children[1] ? @node.children[1].loc.expression.end_pos : @node.children[0].loc.expression.end_pos
19
+ when :def
20
+ @node.children[1].empty? ? @node.loc.name.end_pos : @node.children[1].loc.expression.end_pos
21
+ when :defs
22
+ @node.children[2].empty? ? @node.loc.name.end_pos : @node.children[2].loc.expression.end_pos
19
23
  else
20
24
  @node.children.last.loc.expression.end_pos
21
25
  end
@@ -29,7 +33,7 @@ module Synvert::Core
29
33
  # @param node [Parser::AST::Node]
30
34
  # @return [String] n times whitesphace
31
35
  def indent(node)
32
- if %i[block class].include? node.type
36
+ if %i[block class def defs].include?(node.type)
33
37
  ' ' * (node.column + DEFAULT_INDENT)
34
38
  else
35
39
  ' ' * node.column
@@ -81,11 +81,10 @@ module Synvert::Core
81
81
  def fetch(group, name)
82
82
  group = group.to_s
83
83
  name = name.to_s
84
- if rewriters[group] && rewriters[group][name]
85
- rewriters[group][name]
86
- else
87
- raise RewriterNotFound, "Rewriter #{group} #{name} not found"
88
- end
84
+ rewriter = rewriters.dig(group, name)
85
+ raise RewriterNotFound, "Rewriter #{group} #{name} not found" unless rewriter
86
+
87
+ rewriter
89
88
  end
90
89
 
91
90
  # Get a registered rewriter by group and name, then process that rewriter.
@@ -166,9 +165,8 @@ module Synvert::Core
166
165
  def process
167
166
  @affected_files = Set.new
168
167
  instance_eval(&@block)
169
- if !@affected_files.empty? && @redo_until_no_change
170
- process
171
- end
168
+
169
+ process if !@affected_files.empty? && @redo_until_no_change # redo
172
170
  end
173
171
 
174
172
  # Process rewriter with sandbox mode.
@@ -236,9 +234,10 @@ module Synvert::Core
236
234
  def within_files(file_patterns, &block)
237
235
  return if @sandbox
238
236
 
239
- if (!@ruby_version || @ruby_version.match?) && (!@gem_spec || @gem_spec.match?)
240
- Rewriter::Instance.new(self, Array(file_patterns), &block).process
241
- end
237
+ return if @ruby_version && !@ruby_version.match?
238
+ return if @gem_spec && !@gem_spec.match?
239
+
240
+ Rewriter::Instance.new(self, Array(file_patterns), &block).process
242
241
  end
243
242
 
244
243
  # Parse within_file dsl, it finds a specifiled file.
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Synvert
4
4
  module Core
5
- VERSION = '0.60.0'
5
+ VERSION = '0.62.0'
6
6
  end
7
7
  end
@@ -80,6 +80,11 @@ describe Parser::AST::Node do
80
80
  node = parse('FactoryGirl.create :post')
81
81
  expect(node.receiver).to eq parse('FactoryGirl')
82
82
  end
83
+
84
+ it 'gets for csend node' do
85
+ node = parse('user&.update(name: name)')
86
+ expect(node.receiver).to eq parse('user')
87
+ end
83
88
  end
84
89
 
85
90
  describe '#message' do
@@ -88,6 +93,11 @@ describe Parser::AST::Node do
88
93
  expect(node.message).to eq :create
89
94
  end
90
95
 
96
+ it 'gets for csend node' do
97
+ node = parse('user&.update(name: name)')
98
+ expect(node.message).to eq :update
99
+ end
100
+
91
101
  it 'gets for super node' do
92
102
  node = parse('super(params)')
93
103
  expect(node.message).to eq :super
@@ -137,6 +147,11 @@ describe Parser::AST::Node do
137
147
  expect(node.arguments).to eq parse("[:post, title: 'post']").children
138
148
  end
139
149
 
150
+ it 'gets for csend node' do
151
+ node = parse('user&.update(name: name)')
152
+ expect(node.arguments).to eq parse('[name: name]').children
153
+ end
154
+
140
155
  it 'gets for defined? node' do
141
156
  node = parse('defined?(Bundler)')
142
157
  expect(node.arguments).to eq [parse('Bundler')]
@@ -554,6 +569,54 @@ describe Parser::AST::Node do
554
569
  end
555
570
  end
556
571
 
572
+ describe '#child_node_by_name' do
573
+ context 'block node' do
574
+ it 'checks caller' do
575
+ node = parse('Factory.define :user do |user|; end')
576
+ child_node = node.child_node_by_name(:caller)
577
+ expect(child_node).to eq node.caller
578
+ end
579
+
580
+ it 'checks arguments' do
581
+ node = parse('Factory.define :user do |user|; end')
582
+ child_node = node.child_node_by_name(:arguments)
583
+ expect(child_node).to eq node.arguments
584
+ end
585
+
586
+ it 'checks caller.receiver' do
587
+ node = parse('Factory.define :user do |user|; end')
588
+ child_node = node.child_node_by_name('caller.receiver')
589
+ expect(child_node).to eq node.caller.receiver
590
+ end
591
+
592
+ it 'checks caller.message' do
593
+ node = parse('Factory.define :user do |user|; end')
594
+ child_node = node.child_node_by_name('caller.message')
595
+ expect(child_node).to eq node.caller.message
596
+ end
597
+ end
598
+
599
+ context 'array' do
600
+ it 'checks array by index' do
601
+ node = parse('factory :admin, class: User do; end')
602
+ child_node = node.child_node_by_name('caller.arguments.2')
603
+ expect(child_node).to eq node.caller.arguments[1]
604
+ end
605
+
606
+ it 'checks array by method' do
607
+ node = parse('factory :admin, class: User do; end')
608
+ child_node = node.child_node_by_name('caller.arguments.second')
609
+ expect(child_node).to eq node.caller.arguments[1]
610
+ end
611
+
612
+ it "checks array' value" do
613
+ node = parse('factory :admin, class: User do; end')
614
+ child_node = node.child_node_by_name('caller.arguments.second.class_value')
615
+ expect(child_node).to eq node.caller.arguments[1].class_value
616
+ end
617
+ end
618
+ end
619
+
557
620
  describe '#child_node_range' do
558
621
  context 'block node' do
559
622
  it 'checks caller' do
@@ -605,6 +668,50 @@ describe Parser::AST::Node do
605
668
  end
606
669
  end
607
670
 
671
+ context 'csend node' do
672
+ it 'checks receiver' do
673
+ node = parse('foo&.bar(test)')
674
+ range = node.child_node_range(:receiver)
675
+ expect(range.to_range).to eq(0...3)
676
+ end
677
+
678
+ it 'checks dot' do
679
+ node = parse('foo&.bar(test)')
680
+ range = node.child_node_range(:dot)
681
+ expect(range.to_range).to eq(3...5)
682
+ end
683
+
684
+ it 'checks message' do
685
+ node = parse('foo&.bar(test)')
686
+ range = node.child_node_range(:message)
687
+ expect(range.to_range).to eq(5...8)
688
+
689
+ node = parse('foo&.bar = test')
690
+ range = node.child_node_range(:message)
691
+ expect(range.to_range).to eq(5...10)
692
+ end
693
+
694
+ it 'checks arguments' do
695
+ node = parse('foo&.bar(test)')
696
+ range = node.child_node_range(:arguments)
697
+ expect(range.to_range).to eq(9...13)
698
+
699
+ node = parse('foo&.bar')
700
+ range = node.child_node_range(:arguments)
701
+ expect(range).to be_nil
702
+ end
703
+
704
+ it 'checks parentheses' do
705
+ node = parse('foo&.bar(test)')
706
+ range = node.child_node_range(:parentheses)
707
+ expect(range.to_range).to eq(8...14)
708
+
709
+ node = parse('foo&.bar')
710
+ range = node.child_node_range(:parentheses)
711
+ expect(range).to be_nil
712
+ end
713
+ end
714
+
608
715
  context 'def node' do
609
716
  it 'checks name' do
610
717
  node = parse('def foo(bar); end')
@@ -720,6 +827,26 @@ describe Parser::AST::Node do
720
827
  expect(range).to be_nil
721
828
  end
722
829
  end
830
+
831
+ context 'array' do
832
+ it 'checks array by index' do
833
+ node = parse('factory :admin, class: User do; end')
834
+ range = node.child_node_range('caller.arguments.2')
835
+ expect(range.to_range).to eq(16...27)
836
+ end
837
+
838
+ it 'checks array by method' do
839
+ node = parse('factory :admin, class: User do; end')
840
+ range = node.child_node_range('caller.arguments.second')
841
+ expect(range.to_range).to eq(16...27)
842
+ end
843
+
844
+ it "checks array' value" do
845
+ node = parse('factory :admin, class: User do; end')
846
+ range = node.child_node_range('caller.arguments.second.class_value')
847
+ expect(range.to_range).to eq(23...27)
848
+ end
849
+ end
723
850
  end
724
851
 
725
852
  describe '#rewritten_source' do
@@ -45,5 +45,26 @@ module Synvert::Core
45
45
  expect(subject.rewritten_code).to eq "\ngem 'twitter'"
46
46
  end
47
47
  end
48
+
49
+ describe 'def node' do
50
+ subject do
51
+ source = "def teardown\n do_something\nend"
52
+ class_node = Parser::CurrentRuby.parse(source)
53
+ instance = double(current_node: class_node)
54
+ Rewriter::AppendAction.new(instance, 'super').process
55
+ end
56
+
57
+ it 'gets begin_pos' do
58
+ expect(subject.begin_pos).to eq "def teardown\n do_something".length
59
+ end
60
+
61
+ it 'gets end_pos' do
62
+ expect(subject.end_pos).to eq "def teardown\n do_something".length
63
+ end
64
+
65
+ it 'gets rewritten_code' do
66
+ expect(subject.rewritten_code).to eq "\n super"
67
+ end
68
+ end
48
69
  end
49
70
  end
@@ -87,5 +87,89 @@ module Synvert::Core
87
87
  expect(subject.rewritten_code).to eq "\n include Deletable"
88
88
  end
89
89
  end
90
+
91
+ describe 'def node without args' do
92
+ subject do
93
+ source = "def setup\n do_something\nend"
94
+ def_node = Parser::CurrentRuby.parse(source)
95
+ instance = double(current_node: def_node)
96
+ Rewriter::PrependAction.new(instance, 'super').process
97
+ end
98
+
99
+ it 'gets begin_pos' do
100
+ expect(subject.begin_pos).to eq 'def setup'.length
101
+ end
102
+
103
+ it 'gets end_pos' do
104
+ expect(subject.end_pos).to eq 'def setup'.length
105
+ end
106
+
107
+ it 'gets rewritten_code' do
108
+ expect(subject.rewritten_code).to eq "\n super"
109
+ end
110
+ end
111
+
112
+ describe 'def node with args' do
113
+ subject do
114
+ source = "def setup(foobar)\n do_something\nend"
115
+ def_node = Parser::CurrentRuby.parse(source)
116
+ instance = double(current_node: def_node)
117
+ Rewriter::PrependAction.new(instance, 'super').process
118
+ end
119
+
120
+ it 'gets begin_pos' do
121
+ expect(subject.begin_pos).to eq 'def setup(foobar)'.length
122
+ end
123
+
124
+ it 'gets end_pos' do
125
+ expect(subject.end_pos).to eq 'def setup(foobar)'.length
126
+ end
127
+
128
+ it 'gets rewritten_code' do
129
+ expect(subject.rewritten_code).to eq "\n super"
130
+ end
131
+ end
132
+
133
+ describe 'defs node without args' do
134
+ subject do
135
+ source = "def self.foo\n do_something\nend"
136
+ def_node = Parser::CurrentRuby.parse(source)
137
+ instance = double(current_node: def_node)
138
+ Rewriter::PrependAction.new(instance, 'do_something_first').process
139
+ end
140
+
141
+ it 'gets begin_pos' do
142
+ expect(subject.begin_pos).to eq 'def self.foo'.length
143
+ end
144
+
145
+ it 'gets end_pos' do
146
+ expect(subject.end_pos).to eq 'def self.foo'.length
147
+ end
148
+
149
+ it 'gets rewritten_code' do
150
+ expect(subject.rewritten_code).to eq "\n do_something_first"
151
+ end
152
+ end
153
+
154
+ describe 'defs node with args' do
155
+ subject do
156
+ source = "def self.foo(bar)\n do_something\nend"
157
+ def_node = Parser::CurrentRuby.parse(source)
158
+ instance = double(current_node: def_node)
159
+ Rewriter::PrependAction.new(instance, 'do_something_first').process
160
+ end
161
+
162
+ it 'gets begin_pos' do
163
+ expect(subject.begin_pos).to eq 'def self.foo(bar)'.length
164
+ end
165
+
166
+ it 'gets end_pos' do
167
+ expect(subject.end_pos).to eq 'def self.foo(bar)'.length
168
+ end
169
+
170
+ it 'gets rewritten_code' do
171
+ expect(subject.rewritten_code).to eq "\n do_something_first"
172
+ end
173
+ end
90
174
  end
91
175
  end
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
20
  spec.require_paths = ["lib"]
21
21
 
22
- spec.add_runtime_dependency "activesupport"
22
+ spec.add_runtime_dependency "activesupport", "~> 6"
23
23
  spec.add_runtime_dependency "erubis"
24
24
  spec.add_runtime_dependency "parser"
25
25
 
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: synvert-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.60.0
4
+ version: 0.62.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Huang
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-02 00:00:00.000000000 Z
11
+ date: 2021-12-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: '6'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: '6'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: erubis
29
29
  requirement: !ruby/object:Gem::Requirement