synvert-core 0.60.0 → 0.62.0

Sign up to get free protection for your applications and to get access to all the features.
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