synvert-core 1.14.2 → 1.16.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 +4 -4
- data/CHANGELOG.md +10 -0
- data/Gemfile.lock +7 -7
- data/lib/synvert/core/node_ext.rb +1 -1
- data/lib/synvert/core/rewriter/instance.rb +72 -117
- data/lib/synvert/core/rewriter/warning.rb +1 -1
- data/lib/synvert/core/rewriter.rb +55 -3
- data/lib/synvert/core/snippet_not_found_error.rb +4 -0
- data/lib/synvert/core/utils.rb +29 -3
- data/lib/synvert/core/version.rb +1 -1
- data/lib/synvert/core.rb +1 -0
- data/spec/synvert/core/rewriter/instance_spec.rb +23 -28
- data/spec/synvert/core/rewriter/warning_spec.rb +1 -1
- data/spec/synvert/core/rewriter_spec.rb +5 -1
- data/spec/synvert/core/utils_spec.rb +44 -17
- data/synvert-core-ruby.gemspec +2 -2
- metadata +8 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0fddb0e5f9a0308d8dbf4af383000ff6e7249697cc22986dad4e2ead63d833f5
|
4
|
+
data.tar.gz: 9e15b511b6bc4dc20f8b8cfe32beb0b57d1bc5ec505800c88d121c3849b866f4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 75a0e4992bc623f897294bf603ebaf5b1a713cac9b349e7d4b2a53bb7be3ccc024313957b232049dcb377d412944e8858b66e59ef6a3d00d58a766473f7bc836
|
7
|
+
data.tar.gz: daa75723d1e22c1a3d0bd91016dae1cd5f1bd863c750a22d7c897b087f726fd9dd1c35b3ae8695b614fe26cfa502f05263773f1cecc1843c76a10e9c580273c8
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## 1.16.0 (2022-12-29)
|
4
|
+
|
5
|
+
* Add `Instance#query_adapter` and `Instance#mutation_adapter`
|
6
|
+
* One instance handle only one file
|
7
|
+
* Use `instance.file_path` instead of `instance.current_file`
|
8
|
+
|
9
|
+
## 1.15.0 (2022-11-30)
|
10
|
+
|
11
|
+
* Load snippet from github
|
12
|
+
|
3
13
|
## 1.14.2 (2022-11-19)
|
4
14
|
|
5
15
|
* Specify `node_query`, `node_mutation` and `parser_node_ext` versions
|
data/Gemfile.lock
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
synvert-core (1.
|
4
|
+
synvert-core (1.16.0)
|
5
5
|
activesupport (< 7.0.0)
|
6
6
|
erubis
|
7
|
-
node_mutation (>= 1.
|
8
|
-
node_query (>= 1.
|
7
|
+
node_mutation (>= 1.8.1)
|
8
|
+
node_query (>= 1.11.0)
|
9
9
|
parallel
|
10
10
|
parser
|
11
11
|
parser_node_ext (>= 0.4.1)
|
@@ -50,18 +50,18 @@ GEM
|
|
50
50
|
method_source (1.0.0)
|
51
51
|
minitest (5.16.3)
|
52
52
|
nenv (0.3.0)
|
53
|
-
node_mutation (1.
|
53
|
+
node_mutation (1.8.1)
|
54
54
|
activesupport (< 7.0.0)
|
55
55
|
erubis
|
56
|
-
node_query (1.
|
56
|
+
node_query (1.11.0)
|
57
57
|
activesupport (< 7.0.0)
|
58
58
|
notiffany (0.1.3)
|
59
59
|
nenv (~> 0.1)
|
60
60
|
shellany (~> 0.0)
|
61
61
|
parallel (1.22.1)
|
62
|
-
parser (3.1.
|
62
|
+
parser (3.1.3.0)
|
63
63
|
ast (~> 2.4.1)
|
64
|
-
parser_node_ext (0.
|
64
|
+
parser_node_ext (0.5.1)
|
65
65
|
parser
|
66
66
|
pry (0.14.1)
|
67
67
|
coderay (~> 1.1)
|
@@ -27,7 +27,7 @@ module Parser::AST
|
|
27
27
|
# +type: 'send', receiver: { type: 'send', receiver: { type: 'send', message: 'config' }, message: 'active_record' }, message: 'identity_map='+
|
28
28
|
#
|
29
29
|
# Source Code to Ast Node
|
30
|
-
# {https://
|
30
|
+
# {https://playground.synvert.net/ruby}
|
31
31
|
class Node
|
32
32
|
# Get the file name of node.
|
33
33
|
#
|
@@ -1,5 +1,4 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require 'parallel'
|
3
2
|
|
4
3
|
module Synvert::Core
|
5
4
|
# Instance is an execution unit, it finds specified ast nodes,
|
@@ -12,12 +11,12 @@ module Synvert::Core
|
|
12
11
|
# Initialize an Instance.
|
13
12
|
#
|
14
13
|
# @param rewriter [Synvert::Core::Rewriter]
|
15
|
-
# @param
|
14
|
+
# @param file_path [Array<String>]
|
16
15
|
# @yield block code to find nodes, match conditions and rewrite code.
|
17
|
-
def initialize(rewriter,
|
16
|
+
def initialize(rewriter, file_path, &block)
|
18
17
|
@rewriter = rewriter
|
19
18
|
@actions = []
|
20
|
-
@
|
19
|
+
@file_path = file_path
|
21
20
|
@block = block
|
22
21
|
strategy = NodeMutation::Strategy::KEEP_RUNNING
|
23
22
|
if rewriter.options[:strategy] == Strategy::ALLOW_INSERT_AT_SAME_POSITION
|
@@ -27,20 +26,56 @@ module Synvert::Core
|
|
27
26
|
rewriter.helpers.each { |helper| singleton_class.send(:define_method, helper[:name], &helper[:block]) }
|
28
27
|
end
|
29
28
|
|
29
|
+
# @!attribute [r] file_path
|
30
|
+
# @return file path
|
30
31
|
# @!attribute [rw] current_node
|
31
|
-
# @return current
|
32
|
-
# @!attribute [
|
33
|
-
# @return current filename
|
34
|
-
# @!attribute [rw] current_mutation
|
32
|
+
# @return current ast node
|
33
|
+
# @!attribute [r] current_mutation
|
35
34
|
# @return current mutation
|
36
|
-
|
35
|
+
# @!attribute [r] query_adapter
|
36
|
+
# @return NodeQuery Adapter
|
37
|
+
# @!attribute [r] mutation_adapter
|
38
|
+
# @return NodeMutation Adapter
|
39
|
+
attr_reader :file_path, :current_node, :current_mutation, :query_adapter, :mutation_adapter
|
40
|
+
attr_accessor :current_node
|
37
41
|
|
38
42
|
# Process the instance.
|
39
43
|
# It finds specified files, for each file, it executes the block code, rewrites the original code,
|
40
44
|
# then writes the code back to the original file.
|
41
45
|
def process
|
42
|
-
|
43
|
-
|
46
|
+
puts @file_path if Configuration.show_run_process
|
47
|
+
|
48
|
+
absolute_file_path = File.join(Configuration.root_path, @file_path)
|
49
|
+
while true
|
50
|
+
source = read_source(absolute_file_path)
|
51
|
+
@current_mutation = NodeMutation.new(source)
|
52
|
+
@mutation_adapter = NodeMutation.adapter
|
53
|
+
@query_adapter = NodeQuery.adapter
|
54
|
+
begin
|
55
|
+
node = parse_code(@file_path, source)
|
56
|
+
|
57
|
+
process_with_node(node) do
|
58
|
+
instance_eval(&@block)
|
59
|
+
rescue NoMethodError => e
|
60
|
+
puts [
|
61
|
+
"error: #{e.message}",
|
62
|
+
"file: #{file_path}",
|
63
|
+
"source: #{source}",
|
64
|
+
"line: #{current_node.line}"
|
65
|
+
].join("\n")
|
66
|
+
raise
|
67
|
+
end
|
68
|
+
|
69
|
+
result = @current_mutation.process
|
70
|
+
if result.affected?
|
71
|
+
@rewriter.add_affected_file(file_path)
|
72
|
+
write_source(absolute_file_path, result.new_source)
|
73
|
+
end
|
74
|
+
break unless result.conflicted?
|
75
|
+
rescue Parser::SyntaxError
|
76
|
+
puts "[Warn] file #{file_path} was not parsed correctly."
|
77
|
+
# do nothing, iterate next file
|
78
|
+
end
|
44
79
|
end
|
45
80
|
end
|
46
81
|
|
@@ -48,17 +83,36 @@ module Synvert::Core
|
|
48
83
|
# It finds specified files, for each file, it executes the block code, tests the original code,
|
49
84
|
# then returns the actions.
|
50
85
|
def test
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
86
|
+
absolute_file_path = File.join(Configuration.root_path, file_path)
|
87
|
+
source = read_source(absolute_file_path)
|
88
|
+
@current_mutation = NodeMutation.new(source)
|
89
|
+
@mutation_adapter = NodeMutation.adapter
|
90
|
+
@query_adapter = NodeQuery.adapter
|
91
|
+
begin
|
92
|
+
node = parse_code(file_path, source)
|
93
|
+
|
94
|
+
process_with_node(node) do
|
95
|
+
instance_eval(&@block)
|
96
|
+
rescue NoMethodError => e
|
97
|
+
puts [
|
98
|
+
"error: #{e.message}",
|
99
|
+
"file: #{file_path}",
|
100
|
+
"source: #{source}",
|
101
|
+
"line: #{current_node.line}"
|
102
|
+
].join("\n")
|
103
|
+
raise
|
58
104
|
end
|
105
|
+
|
106
|
+
result = @current_mutation.test
|
107
|
+
result.file_path = file_path
|
108
|
+
result
|
109
|
+
rescue Parser::SyntaxError
|
110
|
+
puts "[Warn] file #{file_path} was not parsed correctly."
|
111
|
+
# do nothing, iterate next file
|
59
112
|
end
|
60
113
|
end
|
61
114
|
|
115
|
+
|
62
116
|
# Gets current node, it allows to get current node in block code.
|
63
117
|
#
|
64
118
|
# @return [Parser::AST::Node]
|
@@ -363,105 +417,6 @@ module Synvert::Core
|
|
363
417
|
|
364
418
|
private
|
365
419
|
|
366
|
-
# Process one file.
|
367
|
-
#
|
368
|
-
# @param file_path [String]
|
369
|
-
def process_file(file_path)
|
370
|
-
puts file_path if Configuration.show_run_process
|
371
|
-
|
372
|
-
@current_file = File.join(Configuration.root_path, file_path)
|
373
|
-
while true
|
374
|
-
source = read_source(@current_file)
|
375
|
-
@current_mutation = NodeMutation.new(source)
|
376
|
-
begin
|
377
|
-
node = parse_code(file_path, source)
|
378
|
-
|
379
|
-
process_with_node(node) do
|
380
|
-
instance_eval(&@block)
|
381
|
-
rescue NoMethodError => e
|
382
|
-
puts [
|
383
|
-
"error: #{e.message}",
|
384
|
-
"file: #{file_path}",
|
385
|
-
"source: #{source}",
|
386
|
-
"line: #{current_node.line}"
|
387
|
-
].join("\n")
|
388
|
-
raise
|
389
|
-
end
|
390
|
-
|
391
|
-
result = @current_mutation.process
|
392
|
-
if result.affected?
|
393
|
-
@rewriter.add_affected_file(file_path)
|
394
|
-
write_source(@current_file, result.new_source)
|
395
|
-
end
|
396
|
-
break unless result.conflicted?
|
397
|
-
rescue Parser::SyntaxError
|
398
|
-
puts "[Warn] file #{file_path} was not parsed correctly."
|
399
|
-
# do nothing, iterate next file
|
400
|
-
end
|
401
|
-
end
|
402
|
-
end
|
403
|
-
|
404
|
-
# Test one file.
|
405
|
-
#
|
406
|
-
# @param file_path [String]
|
407
|
-
def test_file(file_path)
|
408
|
-
@current_file = File.join(Configuration.root_path, file_path)
|
409
|
-
source = read_source(@current_file)
|
410
|
-
@current_mutation = NodeMutation.new(source)
|
411
|
-
begin
|
412
|
-
node = parse_code(@current_file, source)
|
413
|
-
|
414
|
-
process_with_node(node) do
|
415
|
-
instance_eval(&@block)
|
416
|
-
rescue NoMethodError => e
|
417
|
-
puts [
|
418
|
-
"error: #{e.message}",
|
419
|
-
"file: #{file_path}",
|
420
|
-
"source: #{source}",
|
421
|
-
"line: #{current_node.line}"
|
422
|
-
].join("\n")
|
423
|
-
raise
|
424
|
-
end
|
425
|
-
|
426
|
-
result = @current_mutation.test
|
427
|
-
result.file_path = file_path
|
428
|
-
result
|
429
|
-
rescue Parser::SyntaxError
|
430
|
-
puts "[Warn] file #{file_path} was not parsed correctly."
|
431
|
-
# do nothing, iterate next file
|
432
|
-
end
|
433
|
-
end
|
434
|
-
|
435
|
-
# Get file paths.
|
436
|
-
# @return [Array<String>] file paths
|
437
|
-
def get_file_paths
|
438
|
-
Dir.chdir(Configuration.root_path) do
|
439
|
-
only_paths = Configuration.only_paths.size > 0 ? Configuration.only_paths : ["."]
|
440
|
-
only_paths.flat_map do |only_path|
|
441
|
-
@file_patterns.flat_map do |file_pattern|
|
442
|
-
pattern = only_path == "." ? file_pattern : File.join(only_path, file_pattern)
|
443
|
-
Dir.glob(pattern)
|
444
|
-
end
|
445
|
-
end - get_skip_files
|
446
|
-
end
|
447
|
-
end
|
448
|
-
|
449
|
-
# Get skip files.
|
450
|
-
# @return [Array<String>] skip files
|
451
|
-
def get_skip_files
|
452
|
-
Configuration.skip_paths.flat_map do |skip_path|
|
453
|
-
if File.directory?(skip_path)
|
454
|
-
Dir.glob(File.join(skip_path, "**/*"))
|
455
|
-
elsif File.file?(skip_path)
|
456
|
-
[skip_path]
|
457
|
-
elsif skip_path.end_with?("**") || skip_path.end_with?("**/")
|
458
|
-
Dir.glob(File.join(skip_path, "*"))
|
459
|
-
else
|
460
|
-
Dir.glob(skip_path)
|
461
|
-
end
|
462
|
-
end
|
463
|
-
end
|
464
|
-
|
465
420
|
# Read file source.
|
466
421
|
# @param file_path [String] file path
|
467
422
|
# @return [String] file source
|
@@ -8,7 +8,7 @@ module Synvert::Core
|
|
8
8
|
# @param instance [Synvert::Core::Rewriter::Instance]
|
9
9
|
# @param message [String] warning message.
|
10
10
|
def initialize(instance, message)
|
11
|
-
@file_path = instance.
|
11
|
+
@file_path = instance.file_path
|
12
12
|
@line = instance.current_node.loc.expression.line
|
13
13
|
@message = message
|
14
14
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'parallel'
|
3
4
|
require 'fileutils'
|
4
5
|
|
5
6
|
module Synvert::Core
|
@@ -223,11 +224,16 @@ module Synvert::Core
|
|
223
224
|
return if @ruby_version && !@ruby_version.match?
|
224
225
|
return if @gem_spec && !@gem_spec.match?
|
225
226
|
|
226
|
-
instance = Rewriter::Instance.new(self, Array(file_patterns), &block)
|
227
227
|
if @options[:write_to_file]
|
228
|
-
|
228
|
+
handle_one_file(Array(file_patterns)) do |file_path|
|
229
|
+
instance = Rewriter::Instance.new(self, file_path, &block)
|
230
|
+
instance.process
|
231
|
+
end
|
229
232
|
else
|
230
|
-
results =
|
233
|
+
results = handle_one_file(Array(file_patterns)) do |file_path|
|
234
|
+
instance = Rewriter::Instance.new(self, file_path, &block)
|
235
|
+
instance.test
|
236
|
+
end
|
231
237
|
merge_test_results(results)
|
232
238
|
end
|
233
239
|
end
|
@@ -357,6 +363,52 @@ module Synvert::Core
|
|
357
363
|
|
358
364
|
private
|
359
365
|
|
366
|
+
# Handle one file.
|
367
|
+
# @param file_patterns [String] file patterns to find files.
|
368
|
+
# @yield [file_path] block to handle file.
|
369
|
+
# @yieldparam file_path [String] file path.
|
370
|
+
def handle_one_file(file_patterns)
|
371
|
+
if Configuration.number_of_workers > 1
|
372
|
+
Parallel.map(get_file_paths(file_patterns), in_processes: Configuration.number_of_workers) do |file_path|
|
373
|
+
yield(file_path)
|
374
|
+
end
|
375
|
+
else
|
376
|
+
get_file_paths(file_patterns).map do |file_path|
|
377
|
+
yield(file_path)
|
378
|
+
end
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
# Get file paths.
|
383
|
+
# @return [Array<String>] file paths
|
384
|
+
def get_file_paths(file_patterns)
|
385
|
+
Dir.chdir(Configuration.root_path) do
|
386
|
+
only_paths = Configuration.only_paths.size > 0 ? Configuration.only_paths : ["."]
|
387
|
+
only_paths.flat_map do |only_path|
|
388
|
+
file_patterns.flat_map do |file_pattern|
|
389
|
+
pattern = only_path == "." ? file_pattern : File.join(only_path, file_pattern)
|
390
|
+
Dir.glob(pattern)
|
391
|
+
end
|
392
|
+
end - get_skip_files
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
# Get skip files.
|
397
|
+
# @return [Array<String>] skip files
|
398
|
+
def get_skip_files
|
399
|
+
Configuration.skip_paths.flat_map do |skip_path|
|
400
|
+
if File.directory?(skip_path)
|
401
|
+
Dir.glob(File.join(skip_path, "**/*"))
|
402
|
+
elsif File.file?(skip_path)
|
403
|
+
[skip_path]
|
404
|
+
elsif skip_path.end_with?("**") || skip_path.end_with?("**/")
|
405
|
+
Dir.glob(File.join(skip_path, "*"))
|
406
|
+
else
|
407
|
+
Dir.glob(skip_path)
|
408
|
+
end
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
360
412
|
def merge_test_results(results)
|
361
413
|
@test_results += results.select { |result| result.affected? }
|
362
414
|
end
|
data/lib/synvert/core/utils.rb
CHANGED
@@ -1,18 +1,29 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'net/http'
|
3
4
|
require 'uri'
|
5
|
+
require 'open-uri'
|
4
6
|
|
5
7
|
module Synvert::Core
|
6
8
|
class Utils
|
7
9
|
class << self
|
8
10
|
def eval_snippet(snippet_name)
|
11
|
+
eval(load_snippet(snippet_name))
|
12
|
+
end
|
13
|
+
|
14
|
+
def load_snippet(snippet_name)
|
9
15
|
if is_valid_url?(snippet_name)
|
10
16
|
uri = URI.parse(format_url(snippet_name))
|
11
|
-
|
17
|
+
return uri.open.read if remote_snippet_exists?(uri)
|
18
|
+
raise SnippetNotFoundError.new("#{snippet_name} nout found")
|
12
19
|
elsif is_valid_file?(snippet_name)
|
13
|
-
|
20
|
+
return File.read(snippet_name)
|
14
21
|
else
|
15
|
-
|
22
|
+
snippet_path = snippet_expand_path(snippet_name)
|
23
|
+
return File.read(snippet_path) if File.exist?(snippet_path)
|
24
|
+
snippet_uri = URI.parse(format_url(remote_snippet_url(snippet_name)))
|
25
|
+
return snippet_uri.open.read if remote_snippet_exists?(snippet_uri)
|
26
|
+
raise SnippetNotFoundError.new("#{snippet_name} nout found")
|
16
27
|
end
|
17
28
|
end
|
18
29
|
|
@@ -26,10 +37,25 @@ module Synvert::Core
|
|
26
37
|
File.exist?(path)
|
27
38
|
end
|
28
39
|
|
40
|
+
def remote_snippet_exists?(uri)
|
41
|
+
req = Net::HTTP.new(uri.host, uri.port)
|
42
|
+
req.use_ssl = uri.scheme == 'https'
|
43
|
+
res = req.request_head(uri.path)
|
44
|
+
res.code == "200"
|
45
|
+
end
|
46
|
+
|
47
|
+
def snippet_expand_path(snippet_name)
|
48
|
+
File.join(default_snippets_home(), 'lib', "#{snippet_name}.rb")
|
49
|
+
end
|
50
|
+
|
29
51
|
def default_snippets_home
|
30
52
|
ENV['SYNVERT_SNIPPETS_HOME'] || File.join(ENV['HOME'], '.synvert-ruby')
|
31
53
|
end
|
32
54
|
|
55
|
+
def remote_snippet_url(snippet_name)
|
56
|
+
"https://github.com/xinminlabs/synvert-snippets-ruby/blob/main/lib/#{snippet_name}.rb"
|
57
|
+
end
|
58
|
+
|
33
59
|
def format_url(url)
|
34
60
|
convert_to_github_raw_url(url)
|
35
61
|
end
|
data/lib/synvert/core/version.rb
CHANGED
data/lib/synvert/core.rb
CHANGED
@@ -6,7 +6,7 @@ module Synvert::Core
|
|
6
6
|
describe Rewriter::Instance do
|
7
7
|
let(:instance) {
|
8
8
|
rewriter = Rewriter.new('foo', 'bar')
|
9
|
-
Rewriter::Instance.new(rewriter,
|
9
|
+
Rewriter::Instance.new(rewriter, 'code.rb')
|
10
10
|
}
|
11
11
|
|
12
12
|
it 'parses find_node' do
|
@@ -97,35 +97,35 @@ module Synvert::Core
|
|
97
97
|
end
|
98
98
|
|
99
99
|
it 'parses append' do
|
100
|
-
instance.current_mutation
|
100
|
+
instance.instance_variable_set(:@current_mutation, double)
|
101
101
|
instance.current_node = double
|
102
102
|
expect(instance.current_mutation).to receive(:append).with(instance.current_node, 'Foobar')
|
103
103
|
instance.append 'Foobar'
|
104
104
|
end
|
105
105
|
|
106
106
|
it 'parses prepend' do
|
107
|
-
instance.current_mutation
|
107
|
+
instance.instance_variable_set(:@current_mutation, double)
|
108
108
|
instance.current_node = double
|
109
109
|
expect(instance.current_mutation).to receive(:prepend).with(instance.current_node, 'Foobar')
|
110
110
|
instance.prepend 'Foobar'
|
111
111
|
end
|
112
112
|
|
113
113
|
it 'parses insert at end' do
|
114
|
-
instance.current_mutation
|
114
|
+
instance.instance_variable_set(:@current_mutation, double)
|
115
115
|
instance.current_node = double
|
116
116
|
expect(instance.current_mutation).to receive(:insert).with(instance.current_node, 'Foobar', at: 'end', to: 'receiver')
|
117
117
|
instance.insert 'Foobar', to: 'receiver'
|
118
118
|
end
|
119
119
|
|
120
120
|
it 'parses insert at beginning' do
|
121
|
-
instance.current_mutation
|
121
|
+
instance.instance_variable_set(:@current_mutation, double)
|
122
122
|
instance.current_node = double
|
123
123
|
expect(instance.current_mutation).to receive(:insert).with(instance.current_node, 'Foobar', at: 'beginning', to: nil)
|
124
124
|
instance.insert 'Foobar', at: 'beginning'
|
125
125
|
end
|
126
126
|
|
127
127
|
it 'parses insert_after' do
|
128
|
-
instance.current_mutation
|
128
|
+
instance.instance_variable_set(:@current_mutation, double)
|
129
129
|
instance.current_node = double
|
130
130
|
expect(NodeMutation).to receive_message_chain(:adapter, :get_start_loc, :column).and_return(2)
|
131
131
|
expect(instance.current_mutation).to receive(:insert).with(instance.current_node, "\n Foobar", at: 'end', to: nil)
|
@@ -133,7 +133,7 @@ module Synvert::Core
|
|
133
133
|
end
|
134
134
|
|
135
135
|
it 'parses insert_before' do
|
136
|
-
instance.current_mutation
|
136
|
+
instance.instance_variable_set(:@current_mutation, double)
|
137
137
|
instance.current_node = double
|
138
138
|
expect(NodeMutation).to receive_message_chain(:adapter, :get_start_loc, :column).and_return(2)
|
139
139
|
expect(instance.current_mutation).to receive(:insert).with(instance.current_node, "Foobar\n ", at: 'beginning', to: nil)
|
@@ -141,7 +141,7 @@ module Synvert::Core
|
|
141
141
|
end
|
142
142
|
|
143
143
|
it 'parses replace_erb_stmt_with_expr' do
|
144
|
-
instance.current_mutation
|
144
|
+
instance.instance_variable_set(:@current_mutation, double)
|
145
145
|
instance.current_node = double
|
146
146
|
action = double
|
147
147
|
expect(instance.current_mutation).to receive(:actions).and_return([])
|
@@ -151,42 +151,42 @@ module Synvert::Core
|
|
151
151
|
end
|
152
152
|
|
153
153
|
it 'parses replace_with' do
|
154
|
-
instance.current_mutation
|
154
|
+
instance.instance_variable_set(:@current_mutation, double)
|
155
155
|
instance.current_node = double
|
156
156
|
expect(instance.current_mutation).to receive(:replace_with).with(instance.current_node, 'Foobar')
|
157
157
|
instance.replace_with 'Foobar'
|
158
158
|
end
|
159
159
|
|
160
160
|
it 'parses replace with' do
|
161
|
-
instance.current_mutation
|
161
|
+
instance.instance_variable_set(:@current_mutation, double)
|
162
162
|
instance.current_node = double
|
163
163
|
expect(instance.current_mutation).to receive(:replace).with(instance.current_node, :message, with: 'Foobar')
|
164
164
|
instance.replace :message, with: 'Foobar'
|
165
165
|
end
|
166
166
|
|
167
167
|
it 'parses remove' do
|
168
|
-
instance.current_mutation
|
168
|
+
instance.instance_variable_set(:@current_mutation, double)
|
169
169
|
instance.current_node = double
|
170
170
|
expect(instance.current_mutation).to receive(:remove).with(instance.current_node, and_comma: true)
|
171
171
|
instance.remove and_comma: true
|
172
172
|
end
|
173
173
|
|
174
174
|
it 'parses delete' do
|
175
|
-
instance.current_mutation
|
175
|
+
instance.instance_variable_set(:@current_mutation, double)
|
176
176
|
instance.current_node = double
|
177
177
|
expect(instance.current_mutation).to receive(:delete).with(instance.current_node, :dot, :message, and_comma: true)
|
178
178
|
instance.delete :dot, :message, and_comma: true
|
179
179
|
end
|
180
180
|
|
181
181
|
it 'parses wrap with' do
|
182
|
-
instance.current_mutation
|
182
|
+
instance.instance_variable_set(:@current_mutation, double)
|
183
183
|
instance.current_node = double
|
184
184
|
expect(instance.current_mutation).to receive(:wrap).with(instance.current_node, with: 'module Foobar')
|
185
185
|
instance.wrap with: 'module Foobar'
|
186
186
|
end
|
187
187
|
|
188
188
|
it 'parses noop' do
|
189
|
-
instance.current_mutation
|
189
|
+
instance.instance_variable_set(:@current_mutation, double)
|
190
190
|
instance.current_node = double
|
191
191
|
expect(instance.current_mutation).to receive(:noop).with(instance.current_node)
|
192
192
|
instance.noop
|
@@ -206,7 +206,7 @@ module Synvert::Core
|
|
206
206
|
|
207
207
|
it 'writes new code to file' do
|
208
208
|
instance =
|
209
|
-
Rewriter::Instance.new rewriter,
|
209
|
+
Rewriter::Instance.new rewriter, 'spec/models/post_spec.rb' do
|
210
210
|
with_node type: 'send', receiver: 'FactoryGirl', message: 'create' do
|
211
211
|
replace_with 'create {{arguments}}'
|
212
212
|
end
|
@@ -225,7 +225,6 @@ module Synvert::Core
|
|
225
225
|
assert post.valid?
|
226
226
|
end
|
227
227
|
EOS
|
228
|
-
expect(Dir).to receive(:glob).with('spec/**/*_spec.rb').and_return(['spec/models/post_spec.rb'])
|
229
228
|
expect(File).to receive(:read).with('./spec/models/post_spec.rb', encoding: 'UTF-8').and_return(input)
|
230
229
|
expect(File).to receive(:write).with('./spec/models/post_spec.rb', output)
|
231
230
|
instance.process
|
@@ -233,7 +232,7 @@ module Synvert::Core
|
|
233
232
|
|
234
233
|
it 'does not write if file content is not changed' do
|
235
234
|
instance =
|
236
|
-
Rewriter::Instance.new rewriter,
|
235
|
+
Rewriter::Instance.new rewriter, 'spec/spec_helper.rb' do
|
237
236
|
with_node type: 'block', caller: { receiver: 'RSpec', message: 'configure' } do
|
238
237
|
unless_exist_node type: 'send', message: 'include', arguments: ['FactoryGirl::Syntax::Methods'] do
|
239
238
|
insert '{{arguments.first}}.include FactoryGirl::Syntax::Methods'
|
@@ -250,7 +249,6 @@ module Synvert::Core
|
|
250
249
|
config.include FactoryGirl::Syntax::Methods
|
251
250
|
end
|
252
251
|
EOS
|
253
|
-
expect(Dir).to receive(:glob).with('spec/spec_helper.rb').and_return(['spec/spec_helper.rb'])
|
254
252
|
expect(File).to receive(:read).with('./spec/spec_helper.rb', encoding: 'UTF-8').and_return(input)
|
255
253
|
expect(File).not_to receive(:write).with('./spec/spec_helper.rb', output)
|
256
254
|
instance.process
|
@@ -258,7 +256,7 @@ module Synvert::Core
|
|
258
256
|
|
259
257
|
it 'updates file_source and file_ast when writing a file' do
|
260
258
|
instance =
|
261
|
-
Rewriter::Instance.new rewriter,
|
259
|
+
Rewriter::Instance.new rewriter, 'spec/models/post_spec.rb' do
|
262
260
|
with_node type: 'send', receiver: 'FactoryGirl', message: 'create' do
|
263
261
|
replace_with 'create {{arguments}}'
|
264
262
|
end
|
@@ -277,7 +275,6 @@ module Synvert::Core
|
|
277
275
|
assert post.valid?
|
278
276
|
end
|
279
277
|
EOS
|
280
|
-
expect(Dir).to receive(:glob).with('spec/**/*_spec.rb').and_return(['spec/models/post_spec.rb']).twice
|
281
278
|
expect(File).to receive(:read).with('./spec/models/post_spec.rb', encoding: 'UTF-8').and_return(input)
|
282
279
|
expect(File).to receive(:write).with('./spec/models/post_spec.rb', output)
|
283
280
|
expect(File).to receive(:read).with('./spec/models/post_spec.rb', encoding: 'UTF-8').and_return(output)
|
@@ -292,7 +289,7 @@ module Synvert::Core
|
|
292
289
|
|
293
290
|
it 'writes new code to file' do
|
294
291
|
instance =
|
295
|
-
Rewriter::Instance.new rewriter,
|
292
|
+
Rewriter::Instance.new rewriter, 'spec/models/post_spec.rb' do
|
296
293
|
with_node type: 'send', receiver: 'FactoryGirl', message: 'create' do
|
297
294
|
replace_with 'create {{arguments}}'
|
298
295
|
end
|
@@ -304,11 +301,10 @@ module Synvert::Core
|
|
304
301
|
assert post.valid?
|
305
302
|
end
|
306
303
|
EOS
|
307
|
-
expect(Dir).to receive(:glob).with('spec/**/*_spec.rb').and_return(['spec/models/post_spec.rb'])
|
308
304
|
expect(File).to receive(:read).with('./spec/models/post_spec.rb', encoding: 'UTF-8').and_return(input)
|
309
305
|
results = instance.test
|
310
|
-
expect(results
|
311
|
-
expect(results
|
306
|
+
expect(results.file_path).to eq 'spec/models/post_spec.rb'
|
307
|
+
expect(results.actions).to eq [
|
312
308
|
OpenStruct.new(start: 35, end: 59, new_code: 'create :user'),
|
313
309
|
OpenStruct.new(start: 69, end: 105, new_code: 'create :post, user: user')
|
314
310
|
]
|
@@ -316,7 +312,7 @@ module Synvert::Core
|
|
316
312
|
|
317
313
|
it 'does not write if file content is not changed' do
|
318
314
|
instance =
|
319
|
-
Rewriter::Instance.new rewriter,
|
315
|
+
Rewriter::Instance.new rewriter, 'spec/spec_helper.rb' do
|
320
316
|
with_node type: 'block', caller: { receiver: 'RSpec', message: 'configure' } do
|
321
317
|
unless_exist_node type: 'send', message: 'include', arguments: ['FactoryGirl::Syntax::Methods'] do
|
322
318
|
insert '{{arguments.first}}.include FactoryGirl::Syntax::Methods'
|
@@ -328,11 +324,10 @@ module Synvert::Core
|
|
328
324
|
config.include FactoryGirl::Syntax::Methods
|
329
325
|
end
|
330
326
|
EOS
|
331
|
-
expect(Dir).to receive(:glob).with('spec/spec_helper.rb').and_return(['spec/spec_helper.rb'])
|
332
327
|
expect(File).to receive(:read).with('./spec/spec_helper.rb', encoding: 'UTF-8').and_return(input)
|
333
328
|
result = instance.test
|
334
|
-
expect(result
|
335
|
-
expect(result
|
329
|
+
expect(result.file_path).to eq 'spec/spec_helper.rb'
|
330
|
+
expect(result.actions).to eq []
|
336
331
|
end
|
337
332
|
end
|
338
333
|
|
@@ -7,7 +7,7 @@ module Synvert::Core
|
|
7
7
|
subject {
|
8
8
|
source = "def test\n debugger\nend"
|
9
9
|
send_node = Parser::CurrentRuby.parse(source).body.first
|
10
|
-
instance = double(current_node: send_node,
|
10
|
+
instance = double(current_node: send_node, file_path: 'app/test.rb')
|
11
11
|
Rewriter::Warning.new(instance, 'remove debugger')
|
12
12
|
}
|
13
13
|
|
@@ -86,6 +86,7 @@ module Synvert::Core
|
|
86
86
|
end
|
87
87
|
|
88
88
|
it 'delegates process to instances if if_ruby matches' do
|
89
|
+
expect(Dir).to receive(:glob).with('config/routes.rb').and_return(['config/routes.rb'])
|
89
90
|
expect(File).to receive(:exist?).with('./.ruby-version').and_return(true)
|
90
91
|
expect(File).to receive(:read).with('./.ruby-version').and_return('2.0.0')
|
91
92
|
expect_any_instance_of(Rewriter::Instance).to receive(:process)
|
@@ -111,6 +112,7 @@ module Synvert::Core
|
|
111
112
|
end
|
112
113
|
|
113
114
|
it 'delegates process to instances if if_gem matches' do
|
115
|
+
expect(Dir).to receive(:glob).with('config/routes.rb').and_return(['config/routes.rb'])
|
114
116
|
expect_any_instance_of(Rewriter::GemSpec).to receive(:match?).and_return(true)
|
115
117
|
expect_any_instance_of(Rewriter::Instance).to receive(:process)
|
116
118
|
rewriter =
|
@@ -123,6 +125,7 @@ module Synvert::Core
|
|
123
125
|
end
|
124
126
|
|
125
127
|
it 'delegates process to instances if if_ruby and if_gem do not exist' do
|
128
|
+
expect(Dir).to receive(:glob).with('config/routes.rb').and_return(['config/routes.rb'])
|
126
129
|
expect_any_instance_of(Rewriter::Instance).to receive(:process)
|
127
130
|
rewriter =
|
128
131
|
Rewriter.new 'group', 'name' do
|
@@ -221,7 +224,8 @@ module Synvert::Core
|
|
221
224
|
end
|
222
225
|
|
223
226
|
it 'adds snippet by http url' do
|
224
|
-
|
227
|
+
expect(Utils).to receive(:remote_snippet_exists?).with(URI.parse('http://synvert.net/foo/bar.rb')).and_return(true)
|
228
|
+
expect_any_instance_of(URI::HTTP).to receive(:open).and_return(StringIO.new("Rewriter.new 'group', 'sub_rewriter' do\nend"))
|
225
229
|
rewriter = Rewriter.new 'group', 'rewriter' do
|
226
230
|
add_snippet 'http://synvert.net/foo/bar.rb'
|
227
231
|
end
|
@@ -3,27 +3,54 @@ require 'spec_helper'
|
|
3
3
|
module Synvert::Core
|
4
4
|
RSpec.describe Utils do
|
5
5
|
describe '.eval_snippet' do
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
context "by http url" do
|
7
|
+
it 'evals snippet' do
|
8
|
+
expect(described_class).to receive(:remote_snippet_exists?).with(URI.parse('http://example.com/rewriter.rb')).and_return(true)
|
9
|
+
expect_any_instance_of(URI::HTTP).to receive(:open).and_return(StringIO.new("Rewriter.new 'group', 'name' do\nend"))
|
10
|
+
rewriter = described_class.eval_snippet('http://example.com/rewriter.rb')
|
11
|
+
expect(rewriter.group).to eq 'group'
|
12
|
+
expect(rewriter.name).to eq 'name'
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'raises error' do
|
16
|
+
expect(described_class).to receive(:remote_snippet_exists?).and_return(false)
|
17
|
+
expect do
|
18
|
+
described_class.eval_snippet('http://example.com/rewriter.rb')
|
19
|
+
end.to raise_error(SnippetNotFoundError)
|
20
|
+
end
|
11
21
|
end
|
12
22
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
23
|
+
context 'by file path' do
|
24
|
+
it 'evals snippet' do
|
25
|
+
expect(File).to receive(:exist?).and_return(true)
|
26
|
+
expect(File).to receive(:read).and_return("Rewriter.new 'group', 'name' do\nend")
|
27
|
+
rewriter = described_class.eval_snippet('/home/richard/foo/bar.rb')
|
28
|
+
expect(rewriter.group).to eq 'group'
|
29
|
+
expect(rewriter.name).to eq 'name'
|
30
|
+
end
|
19
31
|
end
|
20
32
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
33
|
+
context 'by snippet name' do
|
34
|
+
it 'evals snippet as file' do
|
35
|
+
expect(File).to receive(:exist?).with("group/name").and_return(false)
|
36
|
+
expect(described_class).to receive(:default_snippets_home).and_return('/home/richard/.synvert-ruby')
|
37
|
+
expect(File).to receive(:exist?).with("/home/richard/.synvert-ruby/lib/group/name.rb").and_return(true)
|
38
|
+
expect(File).to receive(:read).and_return("Rewriter.new 'group', 'name' do\nend")
|
39
|
+
rewriter = described_class.eval_snippet('group/name')
|
40
|
+
expect(rewriter.group).to eq 'group'
|
41
|
+
expect(rewriter.name).to eq 'name'
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'evals snippet as github url' do
|
45
|
+
expect(File).to receive(:exist?).with("group/name").and_return(false)
|
46
|
+
expect(described_class).to receive(:default_snippets_home).and_return('/home/richard/.synvert-ruby')
|
47
|
+
expect(File).to receive(:exist?).with("/home/richard/.synvert-ruby/lib/group/name.rb").and_return(false)
|
48
|
+
expect(described_class).to receive(:remote_snippet_exists?).with(URI.parse("https://raw.githubusercontent.com/xinminlabs/synvert-snippets-ruby/main/lib/group/name.rb")).and_return(true)
|
49
|
+
expect_any_instance_of(URI::HTTP).to receive(:open).and_return(StringIO.new("Rewriter.new 'group', 'name' do\nend"))
|
50
|
+
rewriter = described_class.eval_snippet('group/name')
|
51
|
+
expect(rewriter.group).to eq 'group'
|
52
|
+
expect(rewriter.name).to eq 'name'
|
53
|
+
end
|
27
54
|
end
|
28
55
|
end
|
29
56
|
end
|
data/synvert-core-ruby.gemspec
CHANGED
@@ -21,8 +21,8 @@ Gem::Specification.new do |spec|
|
|
21
21
|
|
22
22
|
spec.add_runtime_dependency "activesupport", "< 7.0.0"
|
23
23
|
spec.add_runtime_dependency "erubis"
|
24
|
-
spec.add_runtime_dependency "node_query", ">= 1.
|
25
|
-
spec.add_runtime_dependency "node_mutation", ">= 1.
|
24
|
+
spec.add_runtime_dependency "node_query", ">= 1.11.0"
|
25
|
+
spec.add_runtime_dependency "node_mutation", ">= 1.8.1"
|
26
26
|
spec.add_runtime_dependency "parser"
|
27
27
|
spec.add_runtime_dependency "parser_node_ext", ">= 0.4.1"
|
28
28
|
spec.add_runtime_dependency "parallel"
|
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: 1.
|
4
|
+
version: 1.16.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: 2022-
|
11
|
+
date: 2022-12-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -44,28 +44,28 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 1.
|
47
|
+
version: 1.11.0
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 1.
|
54
|
+
version: 1.11.0
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: node_mutation
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 1.
|
61
|
+
version: 1.8.1
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: 1.
|
68
|
+
version: 1.8.1
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: parser
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -145,6 +145,7 @@ files:
|
|
145
145
|
- lib/synvert/core/rewriter/scope/goto_scope.rb
|
146
146
|
- lib/synvert/core/rewriter/scope/within_scope.rb
|
147
147
|
- lib/synvert/core/rewriter/warning.rb
|
148
|
+
- lib/synvert/core/snippet_not_found_error.rb
|
148
149
|
- lib/synvert/core/strategy.rb
|
149
150
|
- lib/synvert/core/utils.rb
|
150
151
|
- lib/synvert/core/version.rb
|
@@ -187,7 +188,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
187
188
|
- !ruby/object:Gem::Version
|
188
189
|
version: '0'
|
189
190
|
requirements: []
|
190
|
-
rubygems_version: 3.
|
191
|
+
rubygems_version: 3.4.1
|
191
192
|
signing_key:
|
192
193
|
specification_version: 4
|
193
194
|
summary: convert ruby code to better syntax.
|