synvert-core 0.35.0 → 0.40.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: 9c718983fb8e6e6216ac660fba2aa1b9beeacf96db451d65b4df3df827a396c0
4
- data.tar.gz: a6fd2918b8de9d92bfe4a50f1c135154d5b94eacd21b3e88c740e1869e4c4686
3
+ metadata.gz: 5c729d2f456550a622a39f2e43d6d6c7f701f8b1330af038c436a03ec162d828
4
+ data.tar.gz: 8f5e7642d9073bfa38798dbd237a416037047991d530f4ff862623007ffa81f7
5
5
  SHA512:
6
- metadata.gz: 8a828ec38b3d152a6620dd8fb5101a4fa0594da95eaede5612dd805f8b719bc52ebcaa1c00de48bb17fb306ebcf0cd6a7beb109dc91602afd5e305aafe521e47
7
- data.tar.gz: 496d20ef84817d2e8073573b67635f8cb520fc430a647eba909ff9a49dce8fa4f9f5c99245123aa390d7b7d0356c955ca1f78c8073ee17984e1dfa14a8914e51
6
+ metadata.gz: 1187929417e2611b85d95dad5cc2f985d86cc4a1638d0ebecc4baeacc8dfa124ed5ec6595845a941fe7fe13c1666255333aa9f4249f297899c84ab8518a1b809
7
+ data.tar.gz: 729ff991e4a120d655faaa5517915d6d2614396668f08268a93b70c86f00ce038ec12ff09cf7d5cc060e34b7af8604689f3e4948b32a26bf4fc85ae520da1d21
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 0.40.0 (2021-06-23)
4
+
5
+ * Rewrite `insert` action
6
+
7
+ ## 0.39.0 (2021-06-23)
8
+
9
+ * Add `prepend` action instead of `insert`
10
+
11
+ ## 0.38.0 (2021-06-21)
12
+
13
+ * Add `xxx_source` for `hash` node
14
+
15
+ ## 0.36.0 (2021-06-21)
16
+
17
+ * Require `active_support/core_ext/array`
18
+
3
19
  ## 0.35.0 (2021-05-17)
4
20
 
5
21
  * Add `contain` rule
data/lib/synvert/core.rb CHANGED
@@ -6,6 +6,7 @@ require 'parser'
6
6
  require 'parser/current'
7
7
  require 'ast'
8
8
  require 'active_support/core_ext/object'
9
+ require 'active_support/core_ext/array'
9
10
  require 'erubis'
10
11
  require 'set'
11
12
  require 'synvert/core/node_ext'
@@ -269,6 +269,12 @@ module Parser::AST
269
269
  return hash_value(key.to_sym)&.to_value if key?(key.to_sym)
270
270
  return hash_value(key.to_s)&.to_value if key?(key.to_s)
271
271
 
272
+ return nil
273
+ elsif :hash == type && method_name.to_s.include?('_source')
274
+ key = method_name.to_s.sub('_source', '')
275
+ return hash_value(key.to_sym)&.to_source if key?(key.to_sym)
276
+ return hash_value(key.to_s)&.to_source if key?(key.to_s)
277
+
272
278
  return nil
273
279
  end
274
280
 
@@ -281,6 +287,9 @@ module Parser::AST
281
287
  elsif :hash == type && method_name.to_s.include?('_value')
282
288
  key = method_name.to_s.sub('_value', '')
283
289
  return true if key?(key.to_sym) || key?(key.to_s)
290
+ elsif :hash == type && method_name.to_s.include?('_source')
291
+ key = method_name.to_s.sub('_source', '')
292
+ return true if key?(key.to_sym) || key?(key.to_s)
284
293
  end
285
294
 
286
295
  super
@@ -332,7 +341,11 @@ module Parser::AST
332
341
  when %i[block pipes], %i[def parentheses], %i[defs parentheses]
333
342
  Parser::Source::Range.new('(string)', arguments.loc.expression.begin_pos, arguments.loc.expression.end_pos)
334
343
  when %i[block arguments], %i[def arguments], %i[defs arguments]
335
- Parser::Source::Range.new('(string)', arguments.first.loc.expression.begin_pos, arguments.last.loc.expression.end_pos)
344
+ Parser::Source::Range.new(
345
+ '(string)',
346
+ arguments.first.loc.expression.begin_pos,
347
+ arguments.last.loc.expression.end_pos
348
+ )
336
349
  when %i[class name], %i[def name], %i[defs name]
337
350
  loc.name
338
351
  when %i[defs dot]
@@ -18,6 +18,7 @@ module Synvert::Core
18
18
  class Rewriter
19
19
  autoload :Action, 'synvert/core/rewriter/action'
20
20
  autoload :AppendAction, 'synvert/core/rewriter/action/append_action'
21
+ autoload :PrependAction, 'synvert/core/rewriter/action/prepend_action'
21
22
  autoload :InsertAction, 'synvert/core/rewriter/action/insert_action'
22
23
  autoload :InsertAfterAction, 'synvert/core/rewriter/action/insert_after_action'
23
24
  autoload :ReplaceWithAction, 'synvert/core/rewriter/action/replace_with_action'
@@ -1,26 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Synvert::Core
4
- # InsertAction to insert code to the top of node body.
4
+ # AddAction to add code to the node.
5
5
  class Rewriter::InsertAction < Rewriter::Action
6
- DO_LENGTH = ' do'.length
7
-
8
6
  # Begin position to insert code.
9
7
  #
10
8
  # @return [Integer] begin position.
11
9
  def begin_pos
12
- case @node.type
13
- when :block
14
- if @node.children[1].children.empty?
15
- @node.children[0].loc.expression.end_pos + DO_LENGTH
16
- else
17
- @node.children[1].loc.expression.end_pos
18
- end
19
- when :class
20
- @node.children[1] ? @node.children[1].loc.expression.end_pos : @node.children[0].loc.expression.end_pos
21
- else
22
- @node.children.last.loc.expression.end_pos
23
- end
10
+ @node.loc.expression.end_pos
24
11
  end
25
12
 
26
13
  # End position, always same to begin position.
@@ -30,18 +17,11 @@ module Synvert::Core
30
17
  begin_pos
31
18
  end
32
19
 
33
- private
34
-
35
- # Indent of the node.
20
+ # The rewritten source code.
36
21
  #
37
- # @param node [Parser::AST::Node]
38
- # @return [String] n times whitesphace
39
- def indent(node)
40
- if %i[block class].include? node.type
41
- ' ' * (node.indent + DEFAULT_INDENT)
42
- else
43
- ' ' * node.indent
44
- end
22
+ # @return [String] rewritten code.
23
+ def rewritten_code
24
+ rewritten_source
45
25
  end
46
26
  end
47
27
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Synvert::Core
4
+ # PrependAction to prepend code to the top of node body.
5
+ class Rewriter::PrependAction < Rewriter::Action
6
+ DO_LENGTH = ' do'.length
7
+
8
+ # Begin position to prepend code.
9
+ #
10
+ # @return [Integer] begin position.
11
+ def begin_pos
12
+ case @node.type
13
+ when :block
14
+ if @node.children[1].children.empty?
15
+ @node.children[0].loc.expression.end_pos + DO_LENGTH
16
+ else
17
+ @node.children[1].loc.expression.end_pos
18
+ end
19
+ when :class
20
+ @node.children[1] ? @node.children[1].loc.expression.end_pos : @node.children[0].loc.expression.end_pos
21
+ else
22
+ @node.children.last.loc.expression.end_pos
23
+ end
24
+ end
25
+
26
+ # End position, always same to begin position.
27
+ #
28
+ # @return [Integer] end position.
29
+ def end_pos
30
+ begin_pos
31
+ end
32
+
33
+ private
34
+
35
+ # Indent of the node.
36
+ #
37
+ # @param node [Parser::AST::Node]
38
+ # @return [String] n times whitesphace
39
+ def indent(node)
40
+ if %i[block class].include? node.type
41
+ ' ' * (node.indent + DEFAULT_INDENT)
42
+ else
43
+ ' ' * node.indent
44
+ end
45
+ end
46
+ end
47
+ end
@@ -224,6 +224,15 @@ module Synvert::Core
224
224
  @actions << Rewriter::AppendAction.new(self, code, options)
225
225
  end
226
226
 
227
+ # Parse prepend dsl, it creates a [Synvert::Core::Rewriter::PrependAction] to
228
+ # prepend the code to the top of current node body.
229
+ #
230
+ # @param code [String] code need to be prepended.
231
+ # @param options [Hash] action options.
232
+ def prepend(code, options = {})
233
+ @actions << Rewriter::PrependAction.new(self, code, options)
234
+ end
235
+
227
236
  # Parse insert dsl, it creates a [Synvert::Core::Rewriter::InsertAction] to
228
237
  # insert the code to the top of current node body.
229
238
  #
@@ -37,9 +37,18 @@ module Synvert::Core
37
37
  def find_matching_nodes(current_node)
38
38
  matching_nodes = []
39
39
  if @options[:recursive]
40
- matching_nodes << current_node if current_node.match? @rules
41
- current_node.recursive_children do |child_node|
42
- matching_nodes << child_node if child_node.match? @rules
40
+ if current_node.is_a?(Parser::AST::Node)
41
+ matching_nodes << current_node if current_node.match? @rules
42
+ current_node.recursive_children do |child_node|
43
+ matching_nodes << child_node if child_node.match? @rules
44
+ end
45
+ else
46
+ current_node.each do |node|
47
+ matching_nodes << node if node.match? @rules
48
+ node.recursive_children do |child_node|
49
+ matching_nodes << child_node if child_node.match? @rules
50
+ end
51
+ end
43
52
  end
44
53
  elsif current_node.is_a?(Parser::AST::Node)
45
54
  if current_node.type == :begin
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Synvert
4
4
  module Core
5
- VERSION = '0.35.0'
5
+ VERSION = '0.40.0'
6
6
  end
7
7
  end
@@ -360,6 +360,18 @@ describe Parser::AST::Node do
360
360
  end
361
361
  end
362
362
 
363
+ describe 'key value source by method_missing' do
364
+ it 'gets for key value source' do
365
+ node = parse('{:foo => :bar}')
366
+ expect(node.foo_source).to eq ':bar'
367
+
368
+ node = parse("{'foo' => 'bar'}")
369
+ expect(node.foo_source).to eq "'bar'"
370
+
371
+ expect(node.bar_source).to be_nil
372
+ end
373
+ end
374
+
363
375
  describe '#recursive_children' do
364
376
  it 'iterates all children recursively' do
365
377
  node = parse('class Synvert; def current_node; @node; end; end')
@@ -4,88 +4,23 @@ require 'spec_helper'
4
4
 
5
5
  module Synvert::Core
6
6
  describe Rewriter::InsertAction do
7
- describe 'block node without args' do
8
- subject {
9
- source = "Synvert::Application.configure do\nend"
10
- block_node = Parser::CurrentRuby.parse(source)
11
- instance = double(current_node: block_node)
12
- Rewriter::InsertAction.new(instance, 'config.eager_load = true')
13
- }
14
-
15
- it 'gets begin_pos' do
16
- expect(subject.begin_pos).to eq 'Synvert::Application.configure do'.length
17
- end
18
-
19
- it 'gets end_pos' do
20
- expect(subject.end_pos).to eq 'Synvert::Application.configure do'.length
21
- end
22
-
23
- it 'gets rewritten_code' do
24
- expect(subject.rewritten_code).to eq "\n config.eager_load = true"
25
- end
26
- end
27
-
28
- describe 'block node with args' do
29
- subject {
30
- source = "RSpec.configure do |config|\nend"
31
- block_node = Parser::CurrentRuby.parse(source)
32
- instance = double(current_node: block_node)
33
- Rewriter::InsertAction.new(instance, '{{arguments.first}}.include FactoryGirl::Syntax::Methods')
34
- }
35
-
36
- it 'gets begin_pos' do
37
- expect(subject.begin_pos).to eq 'RSpec.configure do |config|'.length
38
- end
39
-
40
- it 'gets end_pos' do
41
- expect(subject.end_pos).to eq 'RSpec.configure do |config|'.length
42
- end
43
-
44
- it 'gets rewritten_code' do
45
- expect(subject.rewritten_code).to eq "\n config.include FactoryGirl::Syntax::Methods"
46
- end
7
+ subject {
8
+ source = "User.where(username: 'Richard')"
9
+ node = Parser::CurrentRuby.parse(source)
10
+ instance = double(current_node: node)
11
+ Rewriter::InsertAction.new(instance, '.first')
12
+ }
13
+
14
+ it 'gets begin_pos' do
15
+ expect(subject.begin_pos).to eq "User.where(username: 'Richard')".length
47
16
  end
48
17
 
49
- describe 'class node without superclass' do
50
- subject {
51
- source = "class User\n has_many :posts\nend"
52
- class_node = Parser::CurrentRuby.parse(source)
53
- instance = double(current_node: class_node)
54
- Rewriter::InsertAction.new(instance, 'include Deletable')
55
- }
56
-
57
- it 'gets begin_pos' do
58
- expect(subject.begin_pos).to eq 'class User'.length
59
- end
60
-
61
- it 'gets end_pos' do
62
- expect(subject.end_pos).to eq 'class User'.length
63
- end
64
-
65
- it 'gets rewritten_code' do
66
- expect(subject.rewritten_code).to eq "\n include Deletable"
67
- end
18
+ it 'gets end_pos' do
19
+ expect(subject.end_pos).to eq "User.where(username: 'Richard')".length
68
20
  end
69
21
 
70
- describe 'class node with superclass' do
71
- subject {
72
- source = "class User < ActiveRecord::Base\n has_many :posts\nend"
73
- class_node = Parser::CurrentRuby.parse(source)
74
- instance = double(current_node: class_node)
75
- Rewriter::InsertAction.new(instance, 'include Deletable')
76
- }
77
-
78
- it 'gets begin_pos' do
79
- expect(subject.begin_pos).to eq 'class User < ActionRecord::Base'.length
80
- end
81
-
82
- it 'gets end_pos' do
83
- expect(subject.end_pos).to eq 'class User < ActionRecord::Base'.length
84
- end
85
-
86
- it 'gets rewritten_code' do
87
- expect(subject.rewritten_code).to eq "\n include Deletable"
88
- end
22
+ it 'gets rewritten_code' do
23
+ expect(subject.rewritten_code).to eq ".first"
89
24
  end
90
25
  end
91
26
  end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ module Synvert::Core
6
+ describe Rewriter::PrependAction do
7
+ describe 'block node without args' do
8
+ subject {
9
+ source = "Synvert::Application.configure do\nend"
10
+ block_node = Parser::CurrentRuby.parse(source)
11
+ instance = double(current_node: block_node)
12
+ Rewriter::PrependAction.new(instance, 'config.eager_load = true')
13
+ }
14
+
15
+ it 'gets begin_pos' do
16
+ expect(subject.begin_pos).to eq 'Synvert::Application.configure do'.length
17
+ end
18
+
19
+ it 'gets end_pos' do
20
+ expect(subject.end_pos).to eq 'Synvert::Application.configure do'.length
21
+ end
22
+
23
+ it 'gets rewritten_code' do
24
+ expect(subject.rewritten_code).to eq "\n config.eager_load = true"
25
+ end
26
+ end
27
+
28
+ describe 'block node with args' do
29
+ subject {
30
+ source = "RSpec.configure do |config|\nend"
31
+ block_node = Parser::CurrentRuby.parse(source)
32
+ instance = double(current_node: block_node)
33
+ Rewriter::PrependAction.new(instance, '{{arguments.first}}.include FactoryGirl::Syntax::Methods')
34
+ }
35
+
36
+ it 'gets begin_pos' do
37
+ expect(subject.begin_pos).to eq 'RSpec.configure do |config|'.length
38
+ end
39
+
40
+ it 'gets end_pos' do
41
+ expect(subject.end_pos).to eq 'RSpec.configure do |config|'.length
42
+ end
43
+
44
+ it 'gets rewritten_code' do
45
+ expect(subject.rewritten_code).to eq "\n config.include FactoryGirl::Syntax::Methods"
46
+ end
47
+ end
48
+
49
+ describe 'class node without superclass' do
50
+ subject {
51
+ source = "class User\n has_many :posts\nend"
52
+ class_node = Parser::CurrentRuby.parse(source)
53
+ instance = double(current_node: class_node)
54
+ Rewriter::PrependAction.new(instance, 'include Deletable')
55
+ }
56
+
57
+ it 'gets begin_pos' do
58
+ expect(subject.begin_pos).to eq 'class User'.length
59
+ end
60
+
61
+ it 'gets end_pos' do
62
+ expect(subject.end_pos).to eq 'class User'.length
63
+ end
64
+
65
+ it 'gets rewritten_code' do
66
+ expect(subject.rewritten_code).to eq "\n include Deletable"
67
+ end
68
+ end
69
+
70
+ describe 'class node with superclass' do
71
+ subject {
72
+ source = "class User < ActiveRecord::Base\n has_many :posts\nend"
73
+ class_node = Parser::CurrentRuby.parse(source)
74
+ instance = double(current_node: class_node)
75
+ Rewriter::PrependAction.new(instance, 'include Deletable')
76
+ }
77
+
78
+ it 'gets begin_pos' do
79
+ expect(subject.begin_pos).to eq 'class User < ActionRecord::Base'.length
80
+ end
81
+
82
+ it 'gets end_pos' do
83
+ expect(subject.end_pos).to eq 'class User < ActionRecord::Base'.length
84
+ end
85
+
86
+ it 'gets rewritten_code' do
87
+ expect(subject.rewritten_code).to eq "\n include Deletable"
88
+ end
89
+ end
90
+ end
91
+ end
@@ -94,13 +94,22 @@ module Synvert::Core
94
94
  instance.append 'include FactoryGirl::Syntax::Methods'
95
95
  end
96
96
 
97
+ it 'parses prepend' do
98
+ expect(Rewriter::PrependAction).to receive(:new).with(
99
+ instance,
100
+ '{{arguments.first}}.include FactoryGirl::Syntax::Methods',
101
+ {}
102
+ )
103
+ instance.prepend '{{arguments.first}}.include FactoryGirl::Syntax::Methods'
104
+ end
105
+
97
106
  it 'parses insert' do
98
107
  expect(Rewriter::InsertAction).to receive(:new).with(
99
108
  instance,
100
- '{{arguments.first}}.include FactoryGirl::Syntax::Methods',
109
+ '.first',
101
110
  {}
102
111
  )
103
- instance.insert '{{arguments.first}}.include FactoryGirl::Syntax::Methods'
112
+ instance.insert '.first'
104
113
  end
105
114
 
106
115
  it 'parses insert_after' do
@@ -8,16 +8,16 @@ module Synvert::Core
8
8
  rewriter = Rewriter.new('foo', 'bar')
9
9
  Rewriter::Instance.new(rewriter, 'file pattern')
10
10
  }
11
- let(:source) {
12
- "
13
- describe Post do
14
- it 'gets post' do
15
- FactoryGirl.create :post
16
- end
17
- end
18
- "
19
- }
11
+ let(:source) { <<~EOS }
12
+ describe Post do
13
+ it 'gets post' do
14
+ FactoryGirl.create :post
15
+ end
16
+ end
17
+ EOS
18
+
20
19
  let(:node) { Parser::CurrentRuby.parse(source) }
20
+
21
21
  before do
22
22
  Rewriter::Instance.reset
23
23
  instance.current_node = node
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.35.0
4
+ version: 0.40.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-05-17 00:00:00.000000000 Z
11
+ date: 2021-06-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -150,6 +150,7 @@ files:
150
150
  - lib/synvert/core/rewriter/action/delete_action.rb
151
151
  - lib/synvert/core/rewriter/action/insert_action.rb
152
152
  - lib/synvert/core/rewriter/action/insert_after_action.rb
153
+ - lib/synvert/core/rewriter/action/prepend_action.rb
153
154
  - lib/synvert/core/rewriter/action/remove_action.rb
154
155
  - lib/synvert/core/rewriter/action/replace_action.rb
155
156
  - lib/synvert/core/rewriter/action/replace_erb_stmt_with_expr_action.rb
@@ -176,6 +177,7 @@ files:
176
177
  - spec/synvert/core/rewriter/action/delete_action_spec.rb
177
178
  - spec/synvert/core/rewriter/action/insert_action_spec.rb
178
179
  - spec/synvert/core/rewriter/action/insert_after_action_spec.rb
180
+ - spec/synvert/core/rewriter/action/prepend_action_spec.rb
179
181
  - spec/synvert/core/rewriter/action/remove_action_spec.rb
180
182
  - spec/synvert/core/rewriter/action/replace_action_spec.rb
181
183
  - spec/synvert/core/rewriter/action/replace_erb_stmt_with_expr_action_spec.rb
@@ -227,6 +229,7 @@ test_files:
227
229
  - spec/synvert/core/rewriter/action/delete_action_spec.rb
228
230
  - spec/synvert/core/rewriter/action/insert_action_spec.rb
229
231
  - spec/synvert/core/rewriter/action/insert_after_action_spec.rb
232
+ - spec/synvert/core/rewriter/action/prepend_action_spec.rb
230
233
  - spec/synvert/core/rewriter/action/remove_action_spec.rb
231
234
  - spec/synvert/core/rewriter/action/replace_action_spec.rb
232
235
  - spec/synvert/core/rewriter/action/replace_erb_stmt_with_expr_action_spec.rb