synvert-core 1.6.0 → 1.7.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 +5 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +6 -4
- data/lib/synvert/core/rewriter/instance.rb +47 -1
- data/lib/synvert/core/rewriter.rb +36 -12
- data/lib/synvert/core/version.rb +1 -1
- data/spec/spec_helper.rb +2 -0
- data/spec/synvert/core/rewriter/instance_spec.rb +49 -0
- data/spec/synvert/core/rewriter_spec.rb +41 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4e0e8e77a7f85aa23300c28aaf44fca1d6b0a7ffad9177bc9925cfd7541f4e65
|
4
|
+
data.tar.gz: eb1b9267dbf8264a9c5978dd019dc0c26fcc6613cf0413b767c8fdf4c763cb00
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 26a85edf49b07f5afc0688152bf63bf65966e72f15d58da615b8e4b6575e28a74978113a9dbbed78f0cf076e0d0a5d54d486ef83af6a46a0ce7e1b69547b33c1
|
7
|
+
data.tar.gz: 21bb822480bd6ea79725d27eabb48c3306da71dec81fb817c8d94027b7457e5ae1ed3d78d9d5d870c103f173e2a3bc00e8b45273c66bbd4dfcb259e2ada254bc
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
synvert-core (1.
|
4
|
+
synvert-core (1.7.0)
|
5
5
|
activesupport (< 7.0.0)
|
6
6
|
erubis
|
7
7
|
node_mutation
|
@@ -23,6 +23,7 @@ GEM
|
|
23
23
|
concurrent-ruby (1.1.10)
|
24
24
|
diff-lcs (1.5.0)
|
25
25
|
erubis (2.7.0)
|
26
|
+
fakefs (1.8.0)
|
26
27
|
ffi (1.15.5)
|
27
28
|
formatador (1.1.0)
|
28
29
|
guard (2.18.0)
|
@@ -48,10 +49,10 @@ GEM
|
|
48
49
|
method_source (1.0.0)
|
49
50
|
minitest (5.16.3)
|
50
51
|
nenv (0.3.0)
|
51
|
-
node_mutation (1.
|
52
|
-
activesupport
|
52
|
+
node_mutation (1.3.3)
|
53
|
+
activesupport (< 7.0.0)
|
53
54
|
erubis
|
54
|
-
node_query (1.
|
55
|
+
node_query (1.6.0)
|
55
56
|
activesupport (< 7.0.0)
|
56
57
|
notiffany (0.1.3)
|
57
58
|
nenv (~> 0.1)
|
@@ -90,6 +91,7 @@ PLATFORMS
|
|
90
91
|
ruby
|
91
92
|
|
92
93
|
DEPENDENCIES
|
94
|
+
fakefs
|
93
95
|
guard
|
94
96
|
guard-rspec
|
95
97
|
rake
|
@@ -30,7 +30,7 @@ module Synvert::Core
|
|
30
30
|
|
31
31
|
# Process the instance.
|
32
32
|
# It finds specified files, for each file, it executes the block code, rewrites the original code,
|
33
|
-
# then
|
33
|
+
# then writes the code back to the original file.
|
34
34
|
def process
|
35
35
|
@file_patterns.each do |file_pattern|
|
36
36
|
Dir.glob(File.join(Configuration.path, file_pattern)).each do |file_path|
|
@@ -41,6 +41,21 @@ module Synvert::Core
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
+
# Test the instance.
|
45
|
+
# It finds specified files, for each file, it executes the block code, tests the original code,
|
46
|
+
# then returns the actions.
|
47
|
+
def test
|
48
|
+
paths = @file_patterns.flat_map do |file_pattern|
|
49
|
+
Dir.glob(File.join(Configuration.path, file_pattern))
|
50
|
+
end
|
51
|
+
|
52
|
+
paths.uniq.map do |file_path|
|
53
|
+
next if Configuration.skip_files.include?(file_path)
|
54
|
+
|
55
|
+
test_file(file_path)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
44
59
|
# Gets current node, it allows to get current node in block code.
|
45
60
|
#
|
46
61
|
# @return [Parser::AST::Node]
|
@@ -378,6 +393,37 @@ module Synvert::Core
|
|
378
393
|
end
|
379
394
|
end
|
380
395
|
|
396
|
+
# Test one file.
|
397
|
+
#
|
398
|
+
# @param file_path [String]
|
399
|
+
def test_file(file_path)
|
400
|
+
@current_file = file_path
|
401
|
+
source = read_source(file_path)
|
402
|
+
@current_mutation = NodeMutation.new(source)
|
403
|
+
begin
|
404
|
+
node = parse_code(file_path, source)
|
405
|
+
|
406
|
+
process_with_node(node) do
|
407
|
+
instance_eval(&@block)
|
408
|
+
rescue NoMethodError => e
|
409
|
+
puts [
|
410
|
+
"error: #{e.message}",
|
411
|
+
"file: #{file_path}",
|
412
|
+
"source: #{source}",
|
413
|
+
"line: #{current_node.line}"
|
414
|
+
].join("\n")
|
415
|
+
raise
|
416
|
+
end
|
417
|
+
|
418
|
+
result = @current_mutation.test
|
419
|
+
result.file_path = file_path
|
420
|
+
result
|
421
|
+
rescue Parser::SyntaxError
|
422
|
+
puts "[Warn] file #{file_path} was not parsed correctly."
|
423
|
+
# do nothing, iterate next file
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
381
427
|
# Read file source.
|
382
428
|
# @param file_path [String] file path
|
383
429
|
# @return [String] file source
|
@@ -72,15 +72,16 @@ module Synvert::Core
|
|
72
72
|
#
|
73
73
|
# @param group [String] the rewriter group.
|
74
74
|
# @param name [String] the rewriter name.
|
75
|
-
# @param
|
75
|
+
# @param options [Hash]
|
76
|
+
# @option options [Boolean] :run_instance (true) process the instance.
|
76
77
|
# @return [Synvert::Core::Rewriter] the registered rewriter.
|
77
78
|
# @raise [Synvert::Core::RewriterNotFound] if the registered rewriter is not found.
|
78
|
-
def call(group, name,
|
79
|
+
def call(group, name, options = {})
|
79
80
|
rewriter = fetch(group, name)
|
80
|
-
if
|
81
|
-
rewriter.process_with_sandbox
|
82
|
-
else
|
81
|
+
if options[:run_instance]
|
83
82
|
rewriter.process
|
83
|
+
else
|
84
|
+
rewriter.process_with_sandbox
|
84
85
|
end
|
85
86
|
rewriter
|
86
87
|
end
|
@@ -137,6 +138,8 @@ module Synvert::Core
|
|
137
138
|
@warnings = []
|
138
139
|
@affected_files = Set.new
|
139
140
|
@redo_until_no_change = false
|
141
|
+
@options = { run_instance: true, write_to_file: true }
|
142
|
+
@test_results = []
|
140
143
|
self.class.register(@group, @name, self)
|
141
144
|
end
|
142
145
|
|
@@ -152,14 +155,29 @@ module Synvert::Core
|
|
152
155
|
# Process rewriter with sandbox mode.
|
153
156
|
# It will call the block but doesn't change any file.
|
154
157
|
def process_with_sandbox
|
155
|
-
@
|
158
|
+
@options[:run_instance] = false
|
156
159
|
begin
|
157
160
|
process
|
158
161
|
ensure
|
159
|
-
@
|
162
|
+
@options[:run_instance] = true
|
160
163
|
end
|
161
164
|
end
|
162
165
|
|
166
|
+
def test
|
167
|
+
@options[:write_to_file] = false
|
168
|
+
begin
|
169
|
+
@affected_files = Set.new
|
170
|
+
instance_eval(&@block)
|
171
|
+
|
172
|
+
if !@affected_files.empty? && @redo_until_no_change # redo
|
173
|
+
test
|
174
|
+
end
|
175
|
+
ensure
|
176
|
+
@options[:write_to_file] = true
|
177
|
+
end
|
178
|
+
@test_results
|
179
|
+
end
|
180
|
+
|
163
181
|
# Add a warning.
|
164
182
|
#
|
165
183
|
# @param warning [Synvert::Core::Rewriter::Warning]
|
@@ -225,12 +243,18 @@ module Synvert::Core
|
|
225
243
|
# @param file_patterns [String|Array<String>] string pattern or list of string pattern to find files, e.g. ['spec/**/*_spec.rb']
|
226
244
|
# @param block [Block] the block to rewrite code in the matching files.
|
227
245
|
def within_files(file_patterns, &block)
|
228
|
-
return
|
246
|
+
return unless @options[:run_instance]
|
229
247
|
|
230
248
|
return if @ruby_version && !@ruby_version.match?
|
231
249
|
return if @gem_spec && !@gem_spec.match?
|
232
250
|
|
233
|
-
Rewriter::Instance.new(self, Array(file_patterns), &block)
|
251
|
+
instance = Rewriter::Instance.new(self, Array(file_patterns), &block)
|
252
|
+
if @options[:write_to_file]
|
253
|
+
instance.process
|
254
|
+
else
|
255
|
+
results = instance.test
|
256
|
+
@test_results += results.select { |result| result.affected? }
|
257
|
+
end
|
234
258
|
end
|
235
259
|
|
236
260
|
# Parse +within_file+ dsl, it finds a specifiled file.
|
@@ -248,7 +272,7 @@ module Synvert::Core
|
|
248
272
|
# @param filename [String] file name of newly created file.
|
249
273
|
# @param content [String] file body of newly created file.
|
250
274
|
def add_file(filename, content)
|
251
|
-
return
|
275
|
+
return unless @options[:run_instance]
|
252
276
|
|
253
277
|
filepath = File.join(Configuration.path, filename)
|
254
278
|
if File.exist?(filepath)
|
@@ -267,7 +291,7 @@ module Synvert::Core
|
|
267
291
|
# end
|
268
292
|
# @param filename [String] file name.
|
269
293
|
def remove_file(filename)
|
270
|
-
return
|
294
|
+
return unless @options[:run_instance]
|
271
295
|
|
272
296
|
file_path = File.join(Configuration.path, filename)
|
273
297
|
File.delete(file_path) if File.exist?(file_path)
|
@@ -293,7 +317,7 @@ module Synvert::Core
|
|
293
317
|
# @param group [String] group of another rewriter.
|
294
318
|
# @param name [String] name of another rewriter.
|
295
319
|
def add_snippet(group, name)
|
296
|
-
@sub_snippets << self.class.call(group.to_s, name.to_s, @
|
320
|
+
@sub_snippets << self.class.call(group.to_s, name.to_s, @options)
|
297
321
|
end
|
298
322
|
|
299
323
|
# Parse +helper_method+ dsl, it defines helper method for {Synvert::Core::Rewriter::Instance}.
|
data/lib/synvert/core/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
4
4
|
|
5
5
|
require 'synvert/core'
|
6
|
+
require 'fakefs/spec_helpers'
|
6
7
|
|
7
8
|
Dir[File.join(File.dirname(__FILE__), 'support', '*')].each do |path|
|
8
9
|
require path
|
@@ -10,6 +11,7 @@ end
|
|
10
11
|
|
11
12
|
RSpec.configure do |config|
|
12
13
|
config.include ParserHelper
|
14
|
+
config.include FakeFS::SpecHelpers, fakefs: true
|
13
15
|
|
14
16
|
config.run_all_when_everything_filtered = true
|
15
17
|
config.filter_run :focus
|
@@ -267,6 +267,55 @@ module Synvert::Core
|
|
267
267
|
end
|
268
268
|
end
|
269
269
|
|
270
|
+
describe '#test' do
|
271
|
+
let(:rewriter) { Rewriter.new('foo', 'bar') }
|
272
|
+
|
273
|
+
it 'writes new code to file' do
|
274
|
+
instance =
|
275
|
+
Rewriter::Instance.new rewriter, ['spec/**/*_spec.rb'] do
|
276
|
+
with_node type: 'send', receiver: 'FactoryGirl', message: 'create' do
|
277
|
+
replace_with 'create {{arguments}}'
|
278
|
+
end
|
279
|
+
end
|
280
|
+
input = <<~EOS
|
281
|
+
it 'uses factory_girl' do
|
282
|
+
user = FactoryGirl.create :user
|
283
|
+
post = FactoryGirl.create :post, user: user
|
284
|
+
assert post.valid?
|
285
|
+
end
|
286
|
+
EOS
|
287
|
+
expect(Dir).to receive(:glob).with('./spec/**/*_spec.rb').and_return(['spec/models/post_spec.rb'])
|
288
|
+
expect(File).to receive(:read).with('spec/models/post_spec.rb', encoding: 'UTF-8').and_return(input)
|
289
|
+
results = instance.test
|
290
|
+
expect(results[0].file_path).to eq 'spec/models/post_spec.rb'
|
291
|
+
expect(results[0].actions).to eq [
|
292
|
+
OpenStruct.new(start: 35, end: 59, new_code: 'create :user'),
|
293
|
+
OpenStruct.new(start: 69, end: 105, new_code: 'create :post, user: user')
|
294
|
+
]
|
295
|
+
end
|
296
|
+
|
297
|
+
it 'does not write if file content is not changed' do
|
298
|
+
instance =
|
299
|
+
Rewriter::Instance.new rewriter, ['spec/spec_helper.rb'] do
|
300
|
+
with_node type: 'block', caller: { receiver: 'RSpec', message: 'configure' } do
|
301
|
+
unless_exist_node type: 'send', message: 'include', arguments: ['FactoryGirl::Syntax::Methods'] do
|
302
|
+
insert '{{arguments.first}}.include FactoryGirl::Syntax::Methods'
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
input = <<~EOS
|
307
|
+
RSpec.configure do |config|
|
308
|
+
config.include FactoryGirl::Syntax::Methods
|
309
|
+
end
|
310
|
+
EOS
|
311
|
+
expect(Dir).to receive(:glob).with('./spec/spec_helper.rb').and_return(['spec/spec_helper.rb'])
|
312
|
+
expect(File).to receive(:read).with('spec/spec_helper.rb', encoding: 'UTF-8').and_return(input)
|
313
|
+
result = instance.test
|
314
|
+
expect(result[0].file_path).to eq 'spec/spec_helper.rb'
|
315
|
+
expect(result[0].actions).to eq []
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
270
319
|
describe '#process_with_node' do
|
271
320
|
it 'resets current_node' do
|
272
321
|
node1 = double
|
@@ -37,6 +37,46 @@ module Synvert::Core
|
|
37
37
|
rewriter.process
|
38
38
|
end
|
39
39
|
|
40
|
+
describe '#process' do
|
41
|
+
it 'rewrites the file' do
|
42
|
+
rewriter = Rewriter.new('group', 'name') do
|
43
|
+
within_files '**/*.rb' do
|
44
|
+
with_node node_type: 'class', name: 'Foobar' do
|
45
|
+
replace :name, with: 'Synvert'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
input = "class Foobar\nend"
|
50
|
+
output = "class Synvert\nend"
|
51
|
+
FakeFS do
|
52
|
+
File.write("code.rb", input)
|
53
|
+
rewriter.process
|
54
|
+
expect(File.read("code.rb")).to eq output
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '#test' do
|
60
|
+
it 'gets test results' do
|
61
|
+
rewriter = Rewriter.new('group', 'name') do
|
62
|
+
within_files '**/*.rb' do
|
63
|
+
with_node node_type: 'class', name: 'Foobar' do
|
64
|
+
replace :name, with: 'Synvert'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
input = "class Foobar\nend"
|
69
|
+
FakeFS do
|
70
|
+
File.write("code.rb", input)
|
71
|
+
results = rewriter.test
|
72
|
+
expect(results[0].file_path).to eq '/code.rb'
|
73
|
+
expect(results[0].affected?).to be_truthy
|
74
|
+
expect(results[0].conflicted?).to be_falsey
|
75
|
+
expect(results[0].actions).to eq [OpenStruct.new(start: 6, end: 12, new_code: 'Synvert')]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
40
80
|
describe 'parses within_file' do
|
41
81
|
it 'does nothing if if_ruby does not match' do
|
42
82
|
expect(File).to receive(:exist?).with('./.ruby-version').and_return(true)
|
@@ -245,7 +285,7 @@ module Synvert::Core
|
|
245
285
|
it 'registers and calls rewriter in sandbox mode' do
|
246
286
|
rewriter = Rewriter.new 'group', 'rewriter'
|
247
287
|
expect(rewriter).to receive(:process_with_sandbox)
|
248
|
-
Rewriter.call 'group', 'rewriter',
|
288
|
+
Rewriter.call 'group', 'rewriter', run_instance: false
|
249
289
|
end
|
250
290
|
|
251
291
|
it 'raises RewriterNotFound if rewriter not found' do
|
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.7.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-09-
|
11
|
+
date: 2022-09-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|