synvert-core 0.29.0 → 0.33.1

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: 31ee6b89cd48a4accb2dc71fdec2e487c534e8d6eb4a9bd6050817cd88f7ba3c
4
- data.tar.gz: cd4c005e0f7a21e52e984e5279a45d4325d341b92d67feedbbc455ddc062e0fc
3
+ metadata.gz: a1f74df180f3b7583a026a0549fe82d57a075fae69990b2dd4a20d22f391fcc5
4
+ data.tar.gz: 0a2159eb88c03c812b3a3a5a2d45e6cdfa79f899c70e820d538a90a6aa17cf9b
5
5
  SHA512:
6
- metadata.gz: 4d1e8642e682a155eedb03c6cdbabca55f53f22c258d4774da7200877159ec18c0a7d568823c5c379fd93810d0baf945a2bc139f8444423855c6279241acb0bc
7
- data.tar.gz: 73a369f23d1add90b21ce578faf37a3136a6ffcb384f47fa5b3881fd4241af4b087b19fb0d854143ed1e3d9b76f350fc41b2415cddc29671cde3afe0e46d4709
6
+ metadata.gz: bd505776d1d2f97f5acae2def15b808ee05536193f076e1d3ce683bdbf8ada56e89acf261db5247fc535bdf3444fb7ee8c58f2b142427ec20ac1325abdc31940
7
+ data.tar.gz: 971fcf29e04c1aebc6e32d5c434adc0ec12e18a6732ff415970e08318b4af885598b4925567c691cd7ce1d8dbd7b7802bed4426cf71ae6dfb21f5546d18c2c73
data/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 0.33.0 (2021-05-10)
4
+
5
+ * Add `body` for `class` node
6
+
7
+ ## 0.32.0 (2021-05-07)
8
+
9
+ * Remove `ArgumentsNode`
10
+
11
+ ## 0.31.0 (2021-04-27)
12
+
13
+ * Add `in` and `not_in` rules
14
+
15
+ ## 0.30.0 (2021-04-26)
16
+
17
+ * `goto_node` accepts multiple child node names
18
+ * Match any_value
19
+
3
20
  ## 0.29.0 (2021-04-25)
4
21
 
5
22
  * Make `child_name_range` support [:block, :pipe]
@@ -1,29 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Parser::AST
4
- # ArgumentsNode allows to handle all args as one node or handle all args as an array.
5
- class ArgumentsNode
6
- # Initialize
7
- #
8
- # @param node [Parser::AST::Node] args node.
9
- def initialize(node)
10
- @node = node
11
- end
12
-
13
- # If args node responds method itself, call method on args node.
14
- # If args children (array) responds method, call method on args children.
15
- # Otherwise raise method missing error.
16
- def method_missing(meth, *args, &block)
17
- if @node.respond_to?(meth)
18
- @node.send meth, *args, &block
19
- elsif @node.children.respond_to?(meth)
20
- @node.children.send meth, *args, &block
21
- else
22
- super
23
- end
24
- end
25
- end
26
-
27
4
  # Parser::AST::Node monkey patch.
28
5
  class Node
29
6
  # Get name node of :class, :module, :const, :mlhs, :def and :defs node.
@@ -101,9 +78,9 @@ module Parser::AST
101
78
  def arguments
102
79
  case type
103
80
  when :def, :block
104
- ArgumentsNode.new(children[1])
81
+ children[1]
105
82
  when :defs
106
- ArgumentsNode.new(children[2])
83
+ children[2]
107
84
  when :send
108
85
  children[2..-1]
109
86
  when :defined?
@@ -133,7 +110,7 @@ module Parser::AST
133
110
  case type
134
111
  when :begin
135
112
  children
136
- when :def, :block
113
+ when :def, :block, :class
137
114
  return [] if children[2].nil?
138
115
 
139
116
  :begin == children[2].type ? children[2].body : children[2..-1]
@@ -285,17 +262,23 @@ module Parser::AST
285
262
  # Current node is s(:hash, s(:pair, s(:sym, :number), s(:int, 10)))
286
263
  # node.number_value is 10
287
264
  def method_missing(method_name, *args, &block)
288
- if :hash == type && method_name.to_s.include?('_value')
265
+ if :args == type && children.respond_to?(method_name)
266
+ return children.send(method_name, *args, &block)
267
+ elsif :hash == type && method_name.to_s.include?('_value')
289
268
  key = method_name.to_s.sub('_value', '')
290
269
  return hash_value(key.to_sym)&.to_value if key?(key.to_sym)
291
270
  return hash_value(key.to_s)&.to_value if key?(key.to_s)
271
+
272
+ return nil
292
273
  end
293
274
 
294
275
  super
295
276
  end
296
277
 
297
278
  def respond_to_missing?(method_name, *args)
298
- if :hash == type && method_name.to_s.include?('_value')
279
+ if :args == type && children.respond_to?(method_name)
280
+ return true
281
+ elsif :hash == type && method_name.to_s.include?('_value')
299
282
  key = method_name.to_s.sub('_value', '')
300
283
  return true if key?(key.to_sym) || key?(key.to_s)
301
284
  end
@@ -348,6 +331,8 @@ module Parser::AST
348
331
  case [type, child_name]
349
332
  when %i[block pipe]
350
333
  Parser::Source::Range.new('(string)', arguments.loc.expression.begin_pos, arguments.loc.expression.end_pos)
334
+ 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)
351
336
  when %i[class name]
352
337
  loc.name
353
338
  when %i[def name]
@@ -357,7 +342,7 @@ module Parser::AST
357
342
  when %i[defs dot]
358
343
  loc.operator
359
344
  when %i[defs self]
360
- Parser::Source::Range.new('(string)', loc.operator.begin_pos - 4, loc.operator.begin_pos)
345
+ Parser::Source::Range.new('(string)', loc.operator.begin_pos - 'self'.length, loc.operator.begin_pos)
361
346
  when %i[send dot]
362
347
  loc.dot
363
348
  when %i[send message]
@@ -426,6 +411,14 @@ module Parser::AST
426
411
  actual = actual_value(self, multi_keys[0...-1])
427
412
  expected = expected_value(rules, multi_keys)
428
413
  !match_value?(actual, expected)
414
+ when :in
415
+ actual = actual_value(self, multi_keys[0...-1])
416
+ expected_values = expected_value(rules, multi_keys)
417
+ expected_values.any? { |expected| match_value?(actual, expected) }
418
+ when :not_in
419
+ actual = actual_value(self, multi_keys[0...-1])
420
+ expected_values = expected_value(rules, multi_keys)
421
+ expected_values.all? { |expected| !match_value?(actual, expected) }
429
422
  else
430
423
  actual = actual_value(self, multi_keys)
431
424
  expected = expected_value(rules, multi_keys)
@@ -448,8 +441,12 @@ module Parser::AST
448
441
  evaluated = instance_eval old_code
449
442
  case evaluated
450
443
  when Parser::AST::Node
451
- evaluated.loc.expression.source
452
- when Array, ArgumentsNode
444
+ if evaluated.type == :args
445
+ evaluated.loc.expression.source[1...-1]
446
+ else
447
+ evaluated.loc.expression.source
448
+ end
449
+ when Array
453
450
  if evaluated.size > 0
454
451
  file_source = evaluated.first.loc.expression.source_buffer.source
455
452
  source = file_source[evaluated.first.loc.expression.begin_pos...evaluated.last.loc.expression.end_pos]
@@ -465,7 +462,7 @@ module Parser::AST
465
462
  source
466
463
  end
467
464
  end
468
- when String, Symbol
465
+ when String, Symbol, Integer, Float
469
466
  evaluated
470
467
  when NilClass
471
468
  'nil'
@@ -525,6 +522,8 @@ module Parser::AST
525
522
  :false == actual.type
526
523
  when Parser::AST::Node
527
524
  actual == expected
525
+ when Synvert::Core::Rewriter::AnyValue
526
+ !actual.nil?
528
527
  else
529
528
  raise Synvert::Core::MethodNotSupported, "#{expected.class} is not handled for match_value?"
530
529
  end
@@ -44,6 +44,8 @@ module Synvert::Core
44
44
  autoload :RubyVersion, 'synvert/core/rewriter/ruby_version'
45
45
  autoload :GemSpec, 'synvert/core/rewriter/gem_spec'
46
46
 
47
+ autoload :AnyValue, 'synvert/core/rewriter/any_value'
48
+
47
49
  class << self
48
50
  # Execute the temporary rewriter without group and name.
49
51
  #
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Synvert::Core
4
+ class Rewriter::AnyValue
5
+ end
6
+ end
@@ -181,10 +181,10 @@ module Synvert::Core
181
181
  # Parse goto_node dsl, it creates a [Synvert::Core::Rewriter::GotoScope] to go to a child node,
182
182
  # then continue operating on the child node.
183
183
  #
184
- # @param child_node_name [String] the name of the child node.
184
+ # @param *child_node_names [Array] the name of the child nodes.
185
185
  # @param block [Block] block code to continue operating on the matching nodes.
186
- def goto_node(child_node_name, &block)
187
- Rewriter::GotoScope.new(self, child_node_name, &block).process
186
+ def goto_node(*child_node_names, &block)
187
+ Rewriter::GotoScope.new(self, *child_node_names, &block).process
188
188
  end
189
189
 
190
190
  # Parse if_exist_node dsl, it creates a [Synvert::Core::Rewriter::IfExistCondition] to check
@@ -285,6 +285,11 @@ module Synvert::Core
285
285
  @rewriter.add_warning Rewriter::Warning.new(self, message)
286
286
  end
287
287
 
288
+ # Any value but nil.
289
+ def any_value
290
+ Rewriter::AnyValue.new
291
+ end
292
+
288
293
  private
289
294
 
290
295
  # It changes source code from bottom to top, and it can change source code twice at the same time,
@@ -297,7 +302,7 @@ module Synvert::Core
297
302
 
298
303
  begin_pos = @actions[i].begin_pos
299
304
  while j > -1
300
- if begin_pos <= @actions[j].end_pos
305
+ if begin_pos < @actions[j].end_pos
301
306
  conflict_actions << @actions.delete_at(j)
302
307
  else
303
308
  i = j
@@ -6,11 +6,11 @@ module Synvert::Core
6
6
  # Initialize a scope
7
7
  #
8
8
  # @param instance [Synvert::Core::Rewriter::Instance]
9
- # @param child_node_name [String]
9
+ # @param *child_node_names [Array]
10
10
  # @param block [Block]
11
- def initialize(instance, child_node_name, &block)
11
+ def initialize(instance, *child_node_names, &block)
12
12
  @instance = instance
13
- @child_node_name = child_node_name
13
+ @child_node_names = child_node_names
14
14
  @block = block
15
15
  end
16
16
 
@@ -19,7 +19,10 @@ module Synvert::Core
19
19
  current_node = @instance.current_node
20
20
  return unless current_node
21
21
 
22
- child_node = @child_node_name.is_a?(Parser::AST::Node) ? @child_node_name : current_node.send(@child_node_name)
22
+ child_node = current_node
23
+ @child_node_names.each do |child_node_name|
24
+ child_node = child_node_name.is_a?(Parser::AST::Node) ? child_node_name : child_node.send(child_node_name)
25
+ end
23
26
  @instance.process_with_other_node child_node do
24
27
  @instance.instance_eval(&@block)
25
28
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Synvert
4
4
  module Core
5
- VERSION = '0.29.0'
5
+ VERSION = '0.33.1'
6
6
  end
7
7
  end
@@ -104,17 +104,17 @@ describe Parser::AST::Node do
104
104
  describe '#arguments' do
105
105
  it 'gets for def node' do
106
106
  node = parse('def test(foo, bar); foo + bar; end')
107
- expect(node.arguments.map { |argument| argument.to_source }).to eq %w[foo bar]
107
+ expect(node.arguments.type).to eq :args
108
108
  end
109
109
 
110
110
  it 'gets for defs node' do
111
111
  node = parse('def self.test(foo, bar); foo + bar; end')
112
- expect(node.arguments.map { |argument| argument.to_source }).to eq %w[foo bar]
112
+ expect(node.arguments.type).to eq :args
113
113
  end
114
114
 
115
115
  it 'gets for block node' do
116
116
  node = parse('RSpec.configure do |config|; end')
117
- expect(node.arguments.map { |argument| argument.to_source }).to eq ['config']
117
+ expect(node.arguments.type).to eq :args
118
118
  end
119
119
 
120
120
  it 'gets for send node' do
@@ -146,6 +146,21 @@ describe Parser::AST::Node do
146
146
  expect(node.body).to eq [parse('include EmailSpec::Helpers'), parse('include EmailSpec::Matchers')]
147
147
  end
148
148
 
149
+ it 'gets empty for class node' do
150
+ node = parse('class User; end')
151
+ expect(node.body).to be_empty
152
+ end
153
+
154
+ it 'gets one line for class node' do
155
+ node = parse('class User; attr_accessor :email; end')
156
+ expect(node.body).to eq [parse('attr_accessor :email')]
157
+ end
158
+
159
+ it 'gets one line for class node' do
160
+ node = parse('class User; attr_accessor :email; attr_accessor :username; end')
161
+ expect(node.body).to eq [parse('attr_accessor :email'), parse('attr_accessor :username')]
162
+ end
163
+
149
164
  it 'gets for begin node' do
150
165
  node = parse('foo; bar')
151
166
  expect(node.body).to eq [parse('foo'), parse('bar')]
@@ -335,11 +350,13 @@ describe Parser::AST::Node do
335
350
 
336
351
  describe 'key value by method_missing' do
337
352
  it 'gets for key value' do
338
- node = parse("{:foo => :bar}")
353
+ node = parse('{:foo => :bar}')
339
354
  expect(node.foo_value).to eq :bar
340
355
 
341
356
  node = parse("{'foo' => 'bar'}")
342
357
  expect(node.foo_value).to eq 'bar'
358
+
359
+ expect(node.bar_value).to be_nil
343
360
  end
344
361
  end
345
362
 
@@ -402,6 +419,18 @@ describe Parser::AST::Node do
402
419
  node = parse(source)
403
420
  expect(node).not_to be_match(type: 'class', name: { not: 'Synvert' })
404
421
  end
422
+
423
+ it 'matches in' do
424
+ source = 'FactoryBot.create(:user)'
425
+ node = parse(source)
426
+ expect(node).to be_match(type: 'send', message: { in: %i[create build] })
427
+ end
428
+
429
+ it 'matches not_in' do
430
+ source = 'FactoryBot.create(:user)'
431
+ node = parse(source)
432
+ expect(node).not_to be_match(type: 'send', message: { not_in: %i[create build] })
433
+ end
405
434
  end
406
435
 
407
436
  describe '#child_node_range' do
@@ -552,7 +581,7 @@ describe Parser::AST::Node do
552
581
  expect(node.rewritten_source('{{name}}')).to eq 'Synvert'
553
582
  end
554
583
 
555
- it 'rewrites for ArgumentsNode' do
584
+ it 'rewrites for arguments' do
556
585
  source = 'test { |a, b| }'
557
586
  node = parse(source)
558
587
  expect(node.rewritten_source('{{arguments}}')).to eq 'a, b'
@@ -54,9 +54,9 @@ module Synvert::Core
54
54
  it 'parses goto_node' do
55
55
  scope = double
56
56
  block = proc {}
57
- expect(Rewriter::GotoScope).to receive(:new).with(instance, :caller, &block).and_return(scope)
57
+ expect(Rewriter::GotoScope).to receive(:new).with(instance, :caller, :receiver, &block).and_return(scope)
58
58
  expect(scope).to receive(:process)
59
- instance.goto_node(:caller, &block)
59
+ instance.goto_node(:caller, :receiver, &block)
60
60
  end
61
61
 
62
62
  it 'parses if_exist_node' do
@@ -8,12 +8,11 @@ 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
- Factory.define :user do |user|
14
- end
15
- '
16
- }
11
+ let(:source) { <<~EOS }
12
+ Factory.define :user do |user|
13
+ end
14
+ EOS
15
+
17
16
  let(:node) { Parser::CurrentRuby.parse(source) }
18
17
  before do
19
18
  Rewriter::Instance.reset
@@ -25,13 +24,13 @@ end
25
24
  run = false
26
25
  type_in_scope = nil
27
26
  scope =
28
- Rewriter::GotoScope.new instance, :caller do
27
+ Rewriter::GotoScope.new instance, :caller, :receiver do
29
28
  run = true
30
29
  type_in_scope = node.type
31
30
  end
32
31
  scope.process
33
32
  expect(run).to be_truthy
34
- expect(type_in_scope).to eq :send
33
+ expect(type_in_scope).to eq :const
35
34
  expect(instance.current_node.type).to eq :block
36
35
  end
37
36
  end
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.29.0
4
+ version: 0.33.1
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-04-25 00:00:00.000000000 Z
11
+ date: 2021-05-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -154,6 +154,7 @@ files:
154
154
  - lib/synvert/core/rewriter/action/replace_action.rb
155
155
  - lib/synvert/core/rewriter/action/replace_erb_stmt_with_expr_action.rb
156
156
  - lib/synvert/core/rewriter/action/replace_with_action.rb
157
+ - lib/synvert/core/rewriter/any_value.rb
157
158
  - lib/synvert/core/rewriter/condition.rb
158
159
  - lib/synvert/core/rewriter/condition/if_exist_condition.rb
159
160
  - lib/synvert/core/rewriter/condition/if_only_exist_condition.rb