synvert-core 0.29.0 → 0.33.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|