synvert-core 1.14.2 → 1.16.0

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