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 +4 -4
- data/CHANGELOG.md +17 -0
- data/lib/synvert/core/node_ext.rb +31 -32
- data/lib/synvert/core/rewriter.rb +2 -0
- data/lib/synvert/core/rewriter/any_value.rb +6 -0
- data/lib/synvert/core/rewriter/instance.rb +9 -4
- data/lib/synvert/core/rewriter/scope/goto_scope.rb +7 -4
- data/lib/synvert/core/version.rb +1 -1
- data/spec/synvert/core/node_ext_spec.rb +34 -5
- data/spec/synvert/core/rewriter/instance_spec.rb +2 -2
- data/spec/synvert/core/rewriter/scope/goto_scope_spec.rb +7 -8
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a1f74df180f3b7583a026a0549fe82d57a075fae69990b2dd4a20d22f391fcc5
|
4
|
+
data.tar.gz: 0a2159eb88c03c812b3a3a5a2d45e6cdfa79f899c70e820d538a90a6aa17cf9b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
81
|
+
children[1]
|
105
82
|
when :defs
|
106
|
-
|
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 :
|
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 :
|
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 -
|
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.
|
452
|
-
|
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
|
#
|
@@ -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
|
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(
|
187
|
-
Rewriter::GotoScope.new(self,
|
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
|
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
|
9
|
+
# @param *child_node_names [Array]
|
10
10
|
# @param block [Block]
|
11
|
-
def initialize(instance,
|
11
|
+
def initialize(instance, *child_node_names, &block)
|
12
12
|
@instance = instance
|
13
|
-
@
|
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 =
|
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
|
data/lib/synvert/core/version.rb
CHANGED
@@ -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.
|
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.
|
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.
|
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(
|
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
|
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
|
-
|
14
|
-
|
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 :
|
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.
|
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-
|
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
|