synvert-core 0.34.0 → 0.39.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: 34cd9673c3a822eb4c9b41930aa069b8c8494d6e81091c37b0184864f302f94d
4
- data.tar.gz: 852ff317acabb0d20528a168d6639b10b9ac576f1c70f64af2e17923762addaa
3
+ metadata.gz: bd079f46cc8d4a8097a794b11c02e98294c217d801538e4c9dafa4305fd3b6d8
4
+ data.tar.gz: 81018b9a711fca607aa4b2dc3170e9172531140392172b5cd27d4118383a6c31
5
5
  SHA512:
6
- metadata.gz: 9a23ba7d43b7eef7a6508925a6d9aa2c925e12cd392999f0d2e263be5a5df7c934a735cb00e584f4cddbdccd8779d6eed1dddd338d9d1f9838d9d983c21f74dc
7
- data.tar.gz: 92008bfc0d05c3d71d9948e0db6a3c8c09ca05b4aff4d2a1cafb6fd93fb0308554a738f2447d962d4751b82827f22aeee9f81d2c7727fb63190018984a7a8a6e
6
+ metadata.gz: 78fd6e0b7b28661b5d352a6835f35b713ca829a2a9ae4260e605541b00e9eb151b66b45018a954e1b98682b45bbbddaac359a582281904dd784b2004ded00c9b
7
+ data.tar.gz: 6a4a33419eafeac609f92d68593ee12b5e5608c24865289cd53f6bb631ef047dc83f1cb7648984d70fded95c9141b6c4a58056280675b55f321836e2b3005dbd
data/CHANGELOG.md CHANGED
@@ -1,9 +1,25 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 0.39.0 (2021-06-23)
4
+
5
+ * Add `prepend` dsl instead of `insert`
6
+
7
+ ## 0.38.0 (2021-06-21)
8
+
9
+ * Add `xxx_source` for `hash` node
10
+
11
+ ## 0.36.0 (2021-06-21)
12
+
13
+ * Require `active_support/core_ext/array`
14
+
15
+ ## 0.35.0 (2021-05-17)
16
+
17
+ * Add `contain` rule
18
+
3
19
  ## 0.34.0 (2021-05-16)
4
20
 
5
21
  * `child_node_name` supports [:def, :parentheses] and [:defs, :parentheses]
6
- * rename `pipe` to `pipes`
22
+ * Rename `pipe` to `pipes`
7
23
 
8
24
  ## 0.33.0 (2021-05-10)
9
25
 
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]
@@ -399,7 +412,7 @@ module Parser::AST
399
412
  def match?(rules)
400
413
  flat_hash(rules).keys.all? do |multi_keys|
401
414
  case multi_keys.last
402
- when :any
415
+ when :any, :contain
403
416
  actual_values = actual_value(self, multi_keys[0...-1])
404
417
  expected = expected_value(rules, multi_keys)
405
418
  actual_values.any? { |actual| match_value?(actual, expected) }
@@ -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'
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Synvert::Core
4
+ # AddAction to add code to the node.
5
+ class Rewriter::AddAction < Rewriter::Action
6
+ # Begin position to insert code.
7
+ #
8
+ # @return [Integer] begin position.
9
+ def begin_pos
10
+ @node.loc.expression.end_pos
11
+ end
12
+
13
+ # End position, always same to begin position.
14
+ #
15
+ # @return [Integer] end position.
16
+ def end_pos
17
+ begin_pos
18
+ end
19
+
20
+ private
21
+
22
+ # The rewritten source code.
23
+ #
24
+ # @return [String] rewritten code.
25
+ def rewritten_code
26
+ rewritten_source
27
+ end
28
+ end
29
+ 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.34.0'
5
+ VERSION = '0.39.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')
@@ -414,6 +426,12 @@ describe Parser::AST::Node do
414
426
  expect(node).to be_match(type: 'send', arguments: { any: 'Lifo::Cache' })
415
427
  end
416
428
 
429
+ it 'matches arguments contain' do
430
+ source = 'def slow(foo, bar, &block); end'
431
+ node = parse(source)
432
+ expect(node).to be_match(type: 'def', arguments: { contain: '&block' })
433
+ end
434
+
417
435
  it 'matches not' do
418
436
  source = 'class Synvert; end'
419
437
  node = parse(source)
@@ -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,6 +94,15 @@ 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,
@@ -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.34.0
4
+ version: 0.39.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-16 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
@@ -146,10 +146,12 @@ files:
146
146
  - lib/synvert/core/node_ext.rb
147
147
  - lib/synvert/core/rewriter.rb
148
148
  - lib/synvert/core/rewriter/action.rb
149
+ - lib/synvert/core/rewriter/action/add_action.rb
149
150
  - lib/synvert/core/rewriter/action/append_action.rb
150
151
  - lib/synvert/core/rewriter/action/delete_action.rb
151
152
  - lib/synvert/core/rewriter/action/insert_action.rb
152
153
  - lib/synvert/core/rewriter/action/insert_after_action.rb
154
+ - lib/synvert/core/rewriter/action/prepend_action.rb
153
155
  - lib/synvert/core/rewriter/action/remove_action.rb
154
156
  - lib/synvert/core/rewriter/action/replace_action.rb
155
157
  - lib/synvert/core/rewriter/action/replace_erb_stmt_with_expr_action.rb
@@ -176,6 +178,7 @@ files:
176
178
  - spec/synvert/core/rewriter/action/delete_action_spec.rb
177
179
  - spec/synvert/core/rewriter/action/insert_action_spec.rb
178
180
  - spec/synvert/core/rewriter/action/insert_after_action_spec.rb
181
+ - spec/synvert/core/rewriter/action/prepend_action_spec.rb
179
182
  - spec/synvert/core/rewriter/action/remove_action_spec.rb
180
183
  - spec/synvert/core/rewriter/action/replace_action_spec.rb
181
184
  - spec/synvert/core/rewriter/action/replace_erb_stmt_with_expr_action_spec.rb
@@ -227,6 +230,7 @@ test_files:
227
230
  - spec/synvert/core/rewriter/action/delete_action_spec.rb
228
231
  - spec/synvert/core/rewriter/action/insert_action_spec.rb
229
232
  - spec/synvert/core/rewriter/action/insert_after_action_spec.rb
233
+ - spec/synvert/core/rewriter/action/prepend_action_spec.rb
230
234
  - spec/synvert/core/rewriter/action/remove_action_spec.rb
231
235
  - spec/synvert/core/rewriter/action/replace_action_spec.rb
232
236
  - spec/synvert/core/rewriter/action/replace_erb_stmt_with_expr_action_spec.rb