synvert-core 0.49.1 → 0.52.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: 7b694eae9a3ae1910d61accf8d93a52511c49cfa7493ccfb0d8d55f9c42d5b88
4
- data.tar.gz: fed8c019f692ad9a4846961558459bf302aa72266fe06c870ba4cdeb1f17d7a8
3
+ metadata.gz: 346c7567c1fec413a81afbe2ec5348f9cd66ac03ed08e8a6cf0fbf47ba049d08
4
+ data.tar.gz: c4a274d516c1301eb0be17777bd26a16561943077260508925cc3c5eae43e799
5
5
  SHA512:
6
- metadata.gz: fb38d31674706ffe1bece171664e05869a66b8362e1e5021b7981c52b04185709afa7b986fd8efcb1070d28bd4e405926a09f73553721f9b9af0c543293377d6
7
- data.tar.gz: 93eecc39d451a9d2cbff536db0f99e78dbb0eb405943743c78f39bd8827c002e022ce323e1641d72336158e9eb8e2f73135e2d7e3c9eb12455ce975a369dd854
6
+ metadata.gz: ee568051d2872db9f81c7d9a3609379eba74db82862ad55976b962e0c4b835dca9f7af74c67014554f6ee919edde2dab050a77fc248bc71ed2c4969009cede1d
7
+ data.tar.gz: 80dd4085d700581a02dd9507e88e0cbf28e978cbbd61d0e0906c73d2f713abbdd9393caec13d6854b3727d1b1fdd87a673d67323b4b315990a00f06fa23a1f44
data/CHANGELOG.md CHANGED
@@ -1,7 +1,19 @@
1
1
  # CHANGELOG
2
2
 
3
- ## 0.49.1 (2021-08-04)
3
+ ## 0.52.0 (2021-08-21)
4
4
 
5
+ * ``Node#child_node_range`` supports nested child
6
+ * Require `fileutils`
7
+ * Rename `Node#indent` to `Node#column`
8
+
9
+ ## 0.51.0 (2021-08-12)
10
+
11
+ * Add `wrap` action
12
+ * Add new dsl `redo_until_no_change`
13
+
14
+ ## 0.50.0 (2021-08-11)
15
+
16
+ * Support `:module` in `body`
5
17
  * Fix symbol match
6
18
 
7
19
  ## 0.49.0 (2021-08-04)
@@ -110,7 +110,7 @@ module Parser::AST
110
110
  case type
111
111
  when :begin
112
112
  children
113
- when :def, :block, :class
113
+ when :def, :block, :class, :module
114
114
  return [] if children[2].nil?
115
115
 
116
116
  :begin == children[2].type ? children[2].body : children[2..-1]
@@ -322,10 +322,10 @@ module Parser::AST
322
322
  loc.expression&.source
323
323
  end
324
324
 
325
- # Get the indent of current node.
325
+ # Get the column of current node.
326
326
  #
327
- # @return [Integer] indent.
328
- def indent
327
+ # @return [Integer] column.
328
+ def column
329
329
  loc.expression.column
330
330
  end
331
331
 
@@ -369,34 +369,35 @@ module Parser::AST
369
369
  Parser::Source::Range.new('(string)', loc.begin.begin_pos, loc.end.end_pos)
370
370
  end
371
371
  else
372
- if respond_to?(child_name)
373
- child_node = send(child_name)
374
- return nil if child_node.nil?
375
-
376
- if child_node.is_a?(Parser::AST::Node)
377
- return(
378
- Parser::Source::Range.new(
379
- '(string)',
380
- child_node.loc.expression.begin_pos,
381
- child_node.loc.expression.end_pos
382
- )
383
- )
372
+ child_node = self
373
+ child_name.to_s.split('.').each do |key|
374
+ if child_node.respond_to?(key)
375
+ child_node = child_node.send(key)
376
+ return nil if child_node.nil?
377
+ else
378
+ raise Synvert::Core::MethodNotSupported,
379
+ "child_node_range is not handled for #{child_node.debug_info}, child_name: #{child_name}"
384
380
  end
381
+ end
385
382
 
386
- # arguments
387
- return nil if child_node.empty?
388
-
383
+ if child_node.is_a?(Parser::AST::Node)
389
384
  return(
390
385
  Parser::Source::Range.new(
391
386
  '(string)',
392
- child_node.first.loc.expression.begin_pos,
393
- child_node.last.loc.expression.end_pos
387
+ child_node.loc.expression.begin_pos,
388
+ child_node.loc.expression.end_pos
394
389
  )
395
390
  )
396
391
  end
397
392
 
398
- raise Synvert::Core::MethodNotSupported,
399
- "child_node_range is not handled for #{debug_info}, child_name: #{child_name}"
393
+ # arguments
394
+ return nil if child_node.empty?
395
+
396
+ Parser::Source::Range.new(
397
+ '(string)',
398
+ child_node.first.loc.expression.begin_pos,
399
+ child_node.last.loc.expression.end_pos
400
+ )
400
401
  end
401
402
  end
402
403
 
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'fileutils'
4
+
3
5
  module Synvert::Core
4
6
  # Rewriter is the top level namespace in a snippet.
5
7
  #
@@ -18,14 +20,15 @@ module Synvert::Core
18
20
  class Rewriter
19
21
  autoload :Action, 'synvert/core/rewriter/action'
20
22
  autoload :AppendAction, 'synvert/core/rewriter/action/append_action'
21
- autoload :PrependAction, 'synvert/core/rewriter/action/prepend_action'
23
+ autoload :DeleteAction, 'synvert/core/rewriter/action/delete_action'
22
24
  autoload :InsertAction, 'synvert/core/rewriter/action/insert_action'
23
25
  autoload :InsertAfterAction, 'synvert/core/rewriter/action/insert_after_action'
24
- autoload :ReplaceWithAction, 'synvert/core/rewriter/action/replace_with_action'
26
+ autoload :RemoveAction, 'synvert/core/rewriter/action/remove_action'
27
+ autoload :PrependAction, 'synvert/core/rewriter/action/prepend_action'
25
28
  autoload :ReplaceAction, 'synvert/core/rewriter/action/replace_action'
26
29
  autoload :ReplaceErbStmtWithExprAction, 'synvert/core/rewriter/action/replace_erb_stmt_with_expr_action'
27
- autoload :RemoveAction, 'synvert/core/rewriter/action/remove_action'
28
- autoload :DeleteAction, 'synvert/core/rewriter/action/delete_action'
30
+ autoload :ReplaceWithAction, 'synvert/core/rewriter/action/replace_with_action'
31
+ autoload :WrapAction, 'synvert/core/rewriter/action/wrap_action'
29
32
 
30
33
  autoload :Warning, 'synvert/core/rewriter/warning'
31
34
 
@@ -175,13 +178,18 @@ module Synvert::Core
175
178
  @sub_snippets = []
176
179
  @warnings = []
177
180
  @affected_files = Set.new
181
+ @redo_until_no_change = false
178
182
  self.class.register(@group, @name, self)
179
183
  end
180
184
 
181
185
  # Process the rewriter.
182
186
  # It will call the block.
183
187
  def process
188
+ @affected_files = Set.new
184
189
  instance_eval(&@block)
190
+ if !@affected_files.empty? && @redo_until_no_change
191
+ process
192
+ end
185
193
  end
186
194
 
187
195
  # Process rewriter with sandbox mode.
@@ -314,5 +322,10 @@ module Synvert::Core
314
322
  @todo
315
323
  end
316
324
  end
325
+
326
+ # Rerun the snippet until no change.
327
+ def redo_until_no_change
328
+ @redo_until_no_change = true
329
+ end
317
330
  end
318
331
  end
@@ -12,7 +12,7 @@ module Synvert::Core
12
12
  if :begin == @node.type
13
13
  @node.loc.expression.end_pos
14
14
  else
15
- @node.loc.expression.end_pos - @node.indent - END_LENGTH
15
+ @node.loc.expression.end_pos - @node.column - END_LENGTH
16
16
  end
17
17
  end
18
18
 
@@ -31,9 +31,9 @@ module Synvert::Core
31
31
  # @return [String] n times whitesphace
32
32
  def indent(node)
33
33
  if %i[block class].include? node.type
34
- ' ' * (node.indent + DEFAULT_INDENT)
34
+ ' ' * (node.column + DEFAULT_INDENT)
35
35
  else
36
- ' ' * node.indent
36
+ ' ' * node.column
37
37
  end
38
38
  end
39
39
  end
@@ -4,10 +4,8 @@ module Synvert::Core
4
4
  # AddAction to add code to the node.
5
5
  class Rewriter::InsertAction < Rewriter::Action
6
6
  def initialize(instance, code, at:)
7
- @instance = instance
8
- @code = code
7
+ super(instance, code)
9
8
  @at = at
10
- @node = @instance.current_node
11
9
  end
12
10
 
13
11
  # Begin position to insert code.
@@ -24,7 +24,7 @@ module Synvert::Core
24
24
  # @param node [Parser::AST::Node]
25
25
  # @return [String] n times whitesphace
26
26
  def indent(node)
27
- ' ' * node.indent
27
+ ' ' * node.column
28
28
  end
29
29
  end
30
30
  end
@@ -38,9 +38,9 @@ module Synvert::Core
38
38
  # @return [String] n times whitesphace
39
39
  def indent(node)
40
40
  if %i[block class].include? node.type
41
- ' ' * (node.indent + DEFAULT_INDENT)
41
+ ' ' * (node.column + DEFAULT_INDENT)
42
42
  else
43
- ' ' * node.indent
43
+ ' ' * node.column
44
44
  end
45
45
  end
46
46
  end
@@ -4,10 +4,8 @@ module Synvert::Core
4
4
  # ReplaceAction to replace child node with code.
5
5
  class Rewriter::ReplaceAction < Rewriter::Action
6
6
  def initialize(instance, *selectors, with:)
7
- @instance = instance
7
+ super(instance, with)
8
8
  @selectors = selectors
9
- @code = with
10
- @node = @instance.current_node
11
9
  end
12
10
 
13
11
  # Begin position of code to replace.
@@ -24,7 +24,7 @@ module Synvert::Core
24
24
  if rewritten_source.include?("\n")
25
25
  new_code = []
26
26
  rewritten_source.split("\n").each_with_index do |line, index|
27
- new_code << (index == 0 ? line : indent(@node) + line)
27
+ new_code << (index == 0 ? line : indent + line)
28
28
  end
29
29
  new_code.join("\n")
30
30
  else
@@ -36,10 +36,9 @@ module Synvert::Core
36
36
 
37
37
  # Indent of the node
38
38
  #
39
- # @param node [Parser::AST::Node]
40
39
  # @return [String] n times whitesphace
41
- def indent(node)
42
- ' ' * node.indent
40
+ def indent
41
+ ' ' * @node.column
43
42
  end
44
43
  end
45
44
  end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Synvert::Core
4
+ # WrapAction to warp node within a block, class or module.
5
+ #
6
+ # Note: if WrapAction is conflicted with another action (begin_pos and end_pos are overlapped),
7
+ # we have to put those 2 actions into 2 within_file scopes.
8
+ class Rewriter::WrapAction < Rewriter::Action
9
+ def initialize(instance, with:, indent: nil)
10
+ super(instance, with)
11
+ @indent = indent || @node.column
12
+ end
13
+
14
+ # Begin position of code to wrap.
15
+ #
16
+ # @return [Integer] begin position.
17
+ def begin_pos
18
+ @node.loc.expression.begin_pos
19
+ end
20
+
21
+ # End position of code to wrap.
22
+ #
23
+ # @return [Integer] end position.
24
+ def end_pos
25
+ @node.loc.expression.end_pos
26
+ end
27
+
28
+ # The rewritten source code.
29
+ #
30
+ # @return [String] rewritten code.
31
+ def rewritten_code
32
+ "#{@code}\n#{' ' * @indent}" +
33
+ @node.to_source.split("\n").map { |line| " #{line}" }.join("\n") +
34
+ "\n#{' ' * @indent}end"
35
+ end
36
+ end
37
+ end
@@ -279,6 +279,15 @@ module Synvert::Core
279
279
  @actions << Rewriter::DeleteAction.new(self, *selectors)
280
280
  end
281
281
 
282
+ # Parse wrap with dsl, it creates a [Synvert::Core::Rewriter::WrapAction] to
283
+ # wrap current node with code.
284
+ #
285
+ # @param with [String] code need to be wrapped with.
286
+ # @param indent [Integer] number of whitespaces.
287
+ def wrap(with:, indent: nil)
288
+ @actions << Rewriter::WrapAction.new(self, with: with, indent: indent)
289
+ end
290
+
282
291
  # Parse warn dsl, it creates a [Synvert::Core::Rewriter::Warning] to save warning message.
283
292
  #
284
293
  # @param message [String] warning message.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Synvert::Core
4
- # WithinScope finds out nodes which match rules, then change its scope to matching node.
4
+ # WithinScope finds out nodes which match rules, then changes its scope to matching node.
5
5
  class Rewriter::WithinScope < Rewriter::Scope
6
6
  # Initialize a scope
7
7
  #
@@ -16,8 +16,9 @@ module Synvert::Core
16
16
  @block = block
17
17
  end
18
18
 
19
- # Find out the matching nodes. It checks the current node and iterates all child nodes,
20
- # then run the block code with each matching node.
19
+ # Find out the matching nodes.
20
+ # It checks the current node and iterates all child nodes,
21
+ # then run the block code on each matching node.
21
22
  def process
22
23
  current_node = @instance.current_node
23
24
  return unless current_node
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Synvert
4
4
  module Core
5
- VERSION = '0.49.1'
5
+ VERSION = '0.52.0'
6
6
  end
7
7
  end
@@ -151,6 +151,11 @@ describe Parser::AST::Node do
151
151
  expect(node.body).to be_empty
152
152
  end
153
153
 
154
+ it 'gets empty for module node' do
155
+ node = parse('module Admin; end')
156
+ expect(node.body).to be_empty
157
+ end
158
+
154
159
  it 'gets one line for class node' do
155
160
  node = parse('class User; attr_accessor :email; end')
156
161
  expect(node.body).to eq [parse('attr_accessor :email')]
@@ -354,10 +359,10 @@ describe Parser::AST::Node do
354
359
  end
355
360
  end
356
361
 
357
- describe '#indent' do
362
+ describe '#column' do
358
363
  it 'gets column number' do
359
364
  node = parse(' FactoryGirl.create :post')
360
- expect(node.indent).to eq 2
365
+ expect(node.column).to eq 2
361
366
  end
362
367
  end
363
368
 
@@ -515,6 +520,12 @@ describe Parser::AST::Node do
515
520
  range = node.child_node_range(:pipes)
516
521
  expect(range.to_range).to eq(24...30)
517
522
  end
523
+
524
+ it 'checks caller.receiver' do
525
+ node = parse('Factory.define :user do |user|; end')
526
+ range = node.child_node_range('caller.receiver')
527
+ expect(range.to_range).to eq(0...7)
528
+ end
518
529
  end
519
530
 
520
531
  context 'class node' do
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ module Synvert::Core
6
+ describe Rewriter::WrapAction do
7
+ subject {
8
+ source = "class Bar\nend"
9
+ node = Parser::CurrentRuby.parse(source)
10
+ instance = double(current_node: node)
11
+ Rewriter::WrapAction.new(instance, with: 'module Foo')
12
+ }
13
+
14
+ it 'gets begin_pos' do
15
+ expect(subject.begin_pos).to eq 0
16
+ end
17
+
18
+ it 'gets end_pos' do
19
+ expect(subject.end_pos).to eq "class Bar\nend".length
20
+ end
21
+
22
+ it 'gets rewritten_code' do
23
+ expect(subject.rewritten_code).to eq <<~EOS.strip
24
+ module Foo
25
+ class Bar
26
+ end
27
+ end
28
+ EOS
29
+ end
30
+ end
31
+ end
@@ -140,6 +140,11 @@ module Synvert::Core
140
140
  instance.delete :dot, :message
141
141
  end
142
142
 
143
+ it 'parses wrap with' do
144
+ expect(Rewriter::WrapAction).to receive(:new).with(instance, with: 'module Foo', indent: nil)
145
+ instance.wrap with: 'module Foo'
146
+ end
147
+
143
148
  it 'parses warn' do
144
149
  expect(Rewriter::Warning).to receive(:new).with(instance, 'foobar')
145
150
  instance.warn 'foobar'
@@ -214,6 +214,15 @@ module Synvert::Core
214
214
  expect(rewriter.todo).to eq "this rewriter doesn't do blah blah blah"
215
215
  end
216
216
 
217
+ it 'parses redo_until_no_change' do
218
+ rewriter =
219
+ Rewriter.new 'group', 'name' do
220
+ redo_until_no_change
221
+ end
222
+ rewriter.process
223
+ expect(rewriter.instance_variable_get('@redo_until_no_change')).to be_truthy
224
+ end
225
+
217
226
  describe 'class methods' do
218
227
  before :each do
219
228
  Rewriter.clear
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: synvert-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.49.1
4
+ version: 0.52.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-08-04 00:00:00.000000000 Z
11
+ date: 2021-08-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -155,6 +155,7 @@ files:
155
155
  - lib/synvert/core/rewriter/action/replace_action.rb
156
156
  - lib/synvert/core/rewriter/action/replace_erb_stmt_with_expr_action.rb
157
157
  - lib/synvert/core/rewriter/action/replace_with_action.rb
158
+ - lib/synvert/core/rewriter/action/wrap_action.rb
158
159
  - lib/synvert/core/rewriter/any_value.rb
159
160
  - lib/synvert/core/rewriter/condition.rb
160
161
  - lib/synvert/core/rewriter/condition/if_exist_condition.rb
@@ -182,6 +183,7 @@ files:
182
183
  - spec/synvert/core/rewriter/action/replace_action_spec.rb
183
184
  - spec/synvert/core/rewriter/action/replace_erb_stmt_with_expr_action_spec.rb
184
185
  - spec/synvert/core/rewriter/action/replace_with_action_spec.rb
186
+ - spec/synvert/core/rewriter/action/wrap_action_spec.rb
185
187
  - spec/synvert/core/rewriter/action_spec.rb
186
188
  - spec/synvert/core/rewriter/condition/if_exist_condition_spec.rb
187
189
  - spec/synvert/core/rewriter/condition/if_only_exist_condition_spec.rb
@@ -192,7 +194,7 @@ files:
192
194
  - spec/synvert/core/rewriter/instance_spec.rb
193
195
  - spec/synvert/core/rewriter/ruby_version_spec.rb
194
196
  - spec/synvert/core/rewriter/scope/goto_scope_spec.rb
195
- - spec/synvert/core/rewriter/scope/within_scope.rb
197
+ - spec/synvert/core/rewriter/scope/within_scope_spec.rb
196
198
  - spec/synvert/core/rewriter/scope_spec.rb
197
199
  - spec/synvert/core/rewriter/warning_spec.rb
198
200
  - spec/synvert/core/rewriter_spec.rb
@@ -216,7 +218,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
216
218
  - !ruby/object:Gem::Version
217
219
  version: '0'
218
220
  requirements: []
219
- rubygems_version: 3.1.6
221
+ rubygems_version: 3.2.22
220
222
  signing_key:
221
223
  specification_version: 4
222
224
  summary: convert ruby code to better syntax.
@@ -234,6 +236,7 @@ test_files:
234
236
  - spec/synvert/core/rewriter/action/replace_action_spec.rb
235
237
  - spec/synvert/core/rewriter/action/replace_erb_stmt_with_expr_action_spec.rb
236
238
  - spec/synvert/core/rewriter/action/replace_with_action_spec.rb
239
+ - spec/synvert/core/rewriter/action/wrap_action_spec.rb
237
240
  - spec/synvert/core/rewriter/action_spec.rb
238
241
  - spec/synvert/core/rewriter/condition/if_exist_condition_spec.rb
239
242
  - spec/synvert/core/rewriter/condition/if_only_exist_condition_spec.rb
@@ -244,7 +247,7 @@ test_files:
244
247
  - spec/synvert/core/rewriter/instance_spec.rb
245
248
  - spec/synvert/core/rewriter/ruby_version_spec.rb
246
249
  - spec/synvert/core/rewriter/scope/goto_scope_spec.rb
247
- - spec/synvert/core/rewriter/scope/within_scope.rb
250
+ - spec/synvert/core/rewriter/scope/within_scope_spec.rb
248
251
  - spec/synvert/core/rewriter/scope_spec.rb
249
252
  - spec/synvert/core/rewriter/warning_spec.rb
250
253
  - spec/synvert/core/rewriter_spec.rb