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