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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cf73847a243ca7bed5a7838e67f7ca4841818d6fa71645e5d6e5ab752be5c2e0
4
- data.tar.gz: 6b1acefc43253e642ea3ce012665a8288b9064927590e7b7a5a7410c43db14d6
3
+ metadata.gz: 0fddb0e5f9a0308d8dbf4af383000ff6e7249697cc22986dad4e2ead63d833f5
4
+ data.tar.gz: 9e15b511b6bc4dc20f8b8cfe32beb0b57d1bc5ec505800c88d121c3849b866f4
5
5
  SHA512:
6
- metadata.gz: 808cebc5d15d61324aa00407e8932857ea93928cc2bf6948a253870f6cb5bc9e7a59e09e8172d01fdce61f01ee28667d4eae92ac09993a33bb769e34e2d31b8a
7
- data.tar.gz: 30c5e89a55fd489948e8aa7e3867fb9188b9b12abb8eb81ed5c106c6ae277f954fab9b7bca2a332a5a323c4e8508510c1b178a307e3fa3056581c1845fd00a71
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.14.2)
4
+ synvert-core (1.16.0)
5
5
  activesupport (< 7.0.0)
6
6
  erubis
7
- node_mutation (>= 1.7.1)
8
- node_query (>= 1.10.0)
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.7.1)
53
+ node_mutation (1.8.1)
54
54
  activesupport (< 7.0.0)
55
55
  erubis
56
- node_query (1.10.0)
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.2.1)
62
+ parser (3.1.3.0)
63
63
  ast (~> 2.4.1)
64
- parser_node_ext (0.4.1)
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://synvert-playground.xinminlabs.com/ruby}
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 file_patterns [Array<String>] pattern list to find files, e.g. ['spec/**/*_spec.rb']
14
+ # @param file_path [Array<String>]
16
15
  # @yield block code to find nodes, match conditions and rewrite code.
17
- def initialize(rewriter, file_patterns, &block)
16
+ def initialize(rewriter, file_path, &block)
18
17
  @rewriter = rewriter
19
18
  @actions = []
20
- @file_patterns = file_patterns
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 parsing node
32
- # @!attribute [rw] current_file
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
- attr_accessor :current_node, :current_file, :current_mutation
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
- get_file_paths.each do |file_path|
43
- process_file(file_path)
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
- if Configuration.number_of_workers > 1
52
- Parallel.map(get_file_paths, in_processes: Configuration.number_of_workers) do |file_path|
53
- test_file(file_path)
54
- end
55
- else
56
- get_file_paths.map do |file_path|
57
- test_file(file_path)
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.current_file
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
- instance.process
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 = instance.test
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
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SnippetNotFoundError < StandardError
4
+ end
@@ -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
- eval(uri.open.read)
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
- eval(File.read(snippet_name))
20
+ return File.read(snippet_name)
14
21
  else
15
- eval(File.read(File.join(default_snippets_home, 'lib', "#{snippet_name}.rb")))
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
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Synvert
4
4
  module Core
5
- VERSION = '1.14.2'
5
+ VERSION = '1.16.0'
6
6
  end
7
7
  end
data/lib/synvert/core.rb CHANGED
@@ -19,6 +19,7 @@ module Synvert
19
19
  autoload :Engine, 'synvert/core/engine'
20
20
  autoload :Utils, 'synvert/core/utils'
21
21
  autoload :Strategy, 'synvert/core/strategy'
22
+ autoload :SnippetNotFoundError, 'synvert/core/snippet_not_found_error'
22
23
  end
23
24
  end
24
25
 
@@ -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, ['file pattern'])
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 = double
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 = double
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 = double
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 = double
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 = double
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 = double
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 = double
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 = double
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 = double
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 = double
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 = double
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 = double
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 = double
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, ['spec/**/*_spec.rb'] do
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, ['spec/spec_helper.rb'] do
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, ['spec/**/*_spec.rb'] do
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, ['spec/**/*_spec.rb'] do
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[0].file_path).to eq 'spec/models/post_spec.rb'
311
- expect(results[0].actions).to eq [
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, ['spec/spec_helper.rb'] do
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[0].file_path).to eq 'spec/spec_helper.rb'
335
- expect(result[0].actions).to eq []
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, current_file: 'app/test.rb')
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
- expect_any_instance_of(URI).to receive(:open).and_return(StringIO.new("Rewriter.new 'group', 'sub_rewriter' do\nend"))
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
- it 'evals snippet by http url' do
7
- expect_any_instance_of(URI).to receive(:open).and_return(StringIO.new("Rewriter.new 'group', 'name' do\nend"))
8
- rewriter = described_class.eval_snippet('http://example.com/rewriter.rb')
9
- expect(rewriter.group).to eq 'group'
10
- expect(rewriter.name).to eq 'name'
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
- it 'adds snippet by file path' do
14
- expect(File).to receive(:exist?).and_return(true)
15
- expect(File).to receive(:read).and_return("Rewriter.new 'group', 'name' do\nend")
16
- rewriter = described_class.eval_snippet('/home/richard/foo/bar.rb')
17
- expect(rewriter.group).to eq 'group'
18
- expect(rewriter.name).to eq 'name'
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
- it 'adds snippet by snippet name' do
22
- expect(File).to receive(:exist?).and_return(false)
23
- expect(File).to receive(:read).and_return("Rewriter.new 'group', 'name' do\nend")
24
- rewriter = described_class.eval_snippet('/home/richard/foo/bar.rb')
25
- expect(rewriter.group).to eq 'group'
26
- expect(rewriter.name).to eq 'name'
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
@@ -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.10.0"
25
- spec.add_runtime_dependency "node_mutation", ">= 1.7.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.14.2
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-19 00:00:00.000000000 Z
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.10.0
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.10.0
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.7.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.7.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.3.22
191
+ rubygems_version: 3.4.1
191
192
  signing_key:
192
193
  specification_version: 4
193
194
  summary: convert ruby code to better syntax.