synvert-core 1.11.0 → 1.13.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 +11 -0
- data/Gemfile.lock +3 -3
- data/README.md +3 -2
- data/lib/synvert/core/rewriter/condition/if_exist_condition.rb +1 -1
- data/lib/synvert/core/rewriter/condition/if_only_exist_condition.rb +2 -2
- data/lib/synvert/core/rewriter/condition/unless_exist_condition.rb +1 -1
- data/lib/synvert/core/rewriter/condition.rb +4 -4
- data/lib/synvert/core/rewriter/instance.rb +49 -49
- data/lib/synvert/core/rewriter/scope/within_scope.rb +6 -4
- data/lib/synvert/core/rewriter.rb +0 -1
- data/lib/synvert/core/version.rb +1 -1
- data/spec/synvert/core/rewriter/instance_spec.rb +11 -2
- data/spec/synvert/core/rewriter/scope/within_scope_spec.rb +105 -60
- metadata +2 -5
- data/lib/synvert/core/rewriter/scope/query_scope.rb +0 -38
- data/spec/synvert/core/rewriter/scope/query_scope_spec.rb +0 -66
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d3d907ab2e51c1861a28d12934cf453f63df79fc23e072c1005013c5f9b137be
|
|
4
|
+
data.tar.gz: 16e8425a70a74b779b36265eec12aacca4b6073e5911052b0114726a740f6e99
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3a73e71ccb24cbdf40fe515fcb732e242e27e5dbac5b130bc9e88d19b8c3ef315cc7c3e00195d3d4e15f6a24bd4fb89336686ae379451e3fa7433548bd3402c8
|
|
7
|
+
data.tar.gz: c6e026527d96e8766a330626c330d280c6ab650834e71b56c64c4cf81a4dd7d0911d89919c16e0f651208e0d0ce1c9c3b36f6c08f4c9f5f7d04d0af4849a713d
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## 1.13.0 (2022-10-17)
|
|
4
|
+
|
|
5
|
+
* Add `insert_before` dsl
|
|
6
|
+
* Update `insert_after` to reuse `NodeMutation#insert`
|
|
7
|
+
|
|
8
|
+
## 1.12.0 (2022-10-14)
|
|
9
|
+
|
|
10
|
+
* Condition accepts both nql and rules
|
|
11
|
+
* Make `find_node` as an alias to `within_node`
|
|
12
|
+
* Remove skip files only once
|
|
13
|
+
|
|
3
14
|
## 1.11.0 (2022-10-11)
|
|
4
15
|
|
|
5
16
|
* Add `Configuration.number_of_workers`
|
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.13.0)
|
|
5
5
|
activesupport (< 7.0.0)
|
|
6
6
|
erubis
|
|
7
7
|
node_mutation
|
|
@@ -50,10 +50,10 @@ GEM
|
|
|
50
50
|
method_source (1.0.0)
|
|
51
51
|
minitest (5.16.3)
|
|
52
52
|
nenv (0.3.0)
|
|
53
|
-
node_mutation (1.
|
|
53
|
+
node_mutation (1.5.0)
|
|
54
54
|
activesupport (< 7.0.0)
|
|
55
55
|
erubis
|
|
56
|
-
node_query (1.
|
|
56
|
+
node_query (1.8.1)
|
|
57
57
|
activesupport (< 7.0.0)
|
|
58
58
|
notiffany (0.1.3)
|
|
59
59
|
nenv (~> 0.1)
|
data/README.md
CHANGED
|
@@ -73,16 +73,16 @@ DSLs are as follows
|
|
|
73
73
|
|
|
74
74
|
Scopes:
|
|
75
75
|
|
|
76
|
-
* [find_node](./Synvert/Core/Rewriter/Instance.html#find_node-instance_method) - recursively find matching ast nodes by node query language
|
|
77
76
|
* [within_node](./Synvert/Core/Rewriter/Instance.html#within_node-instance_method) - recursively find matching ast nodes
|
|
78
77
|
* [with_node](./Synvert/Core/Rewriter/Instance.html#with_node-instance_method) - alias to within_node
|
|
78
|
+
* [find_node](./Synvert/Core/Rewriter/Instance.html#find_node-instance_method) - alias to within_node
|
|
79
79
|
* [goto_node](./Synvert/Core/Rewriter/Instance.html#goto_node-instance_method) - go to a child node
|
|
80
80
|
|
|
81
81
|
Conditions:
|
|
82
82
|
|
|
83
83
|
* [if_exist_node](./Synvert/Core/Rewriter/Instance.html#if_exist_node-instance_method) - check if matching node exist in the child nodes
|
|
84
84
|
* [unless_exist_node](./Synvert/Core/Rewriter/Instance.html#unless_exist_node-instance_method) - check if matching node doesn't exist in the child nodes
|
|
85
|
-
* [if_only_exist_node](./Synvert/Core/Rewriter/Instance.html#if_only_exist_node-instance_method) - check if current node has only one child node and the child node matches
|
|
85
|
+
* [if_only_exist_node](./Synvert/Core/Rewriter/Instance.html#if_only_exist_node-instance_method) - check if current node has only one child node and the child node matches
|
|
86
86
|
|
|
87
87
|
Actions:
|
|
88
88
|
|
|
@@ -90,6 +90,7 @@ Actions:
|
|
|
90
90
|
* [prepend](./Synvert/Core/Rewriter/Instance.html#prepend-instance_method) - prepend the code to the bottom of current node body
|
|
91
91
|
* [insert](./Synvert/Core/Rewriter/Instance.html#insert-instance_method) - insert code
|
|
92
92
|
* [insert_after](./Synvert/Core/Rewriter/Instance.html#insert_after-instance_method) - insert the code next to the current node
|
|
93
|
+
* [insert_before](./Synvert/Core/Rewriter/Instance.html#insert_before-instance_method) - insert the code previous to the current node
|
|
93
94
|
* [replace](./Synvert/Core/Rewriter/Instance.html#replace-instance_method) - replace the code of specified child nodes
|
|
94
95
|
* [delete](./Synvert/Core/Rewriter/Instance.html#delete-instance_method) - delete the code specified child nodes
|
|
95
96
|
* [wrap](./Synvert/Core/Rewriter/Instance.html#wrap-instance_method) - wrap the current node with code
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Synvert::Core
|
|
4
|
-
# IfOnlyExistCondition checks if node has only one child node and the child node matches
|
|
4
|
+
# IfOnlyExistCondition checks if node has only one child node and the child node matches.
|
|
5
5
|
class Rewriter::IfOnlyExistCondition < Rewriter::Condition
|
|
6
6
|
private
|
|
7
7
|
|
|
8
|
-
# check if only have one child node and the child node matches
|
|
8
|
+
# check if only have one child node and the child node matches.
|
|
9
9
|
#
|
|
10
10
|
# @return [Boolean]
|
|
11
11
|
def match?
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Synvert::Core
|
|
4
|
-
# Condition checks if rules matches.
|
|
4
|
+
# Condition checks if nql or rules matches.
|
|
5
5
|
class Rewriter::Condition
|
|
6
6
|
# Initialize a Condition.
|
|
7
7
|
#
|
|
8
8
|
# @param instance [Synvert::Core::Rewriter::Instance]
|
|
9
|
-
# @param
|
|
9
|
+
# @param nql_or_rules [String|Hash]
|
|
10
10
|
# @yield run when condition matches
|
|
11
|
-
def initialize(instance,
|
|
11
|
+
def initialize(instance, nql_or_rules, &block)
|
|
12
12
|
@instance = instance
|
|
13
|
-
@node_query = NodeQuery.new(
|
|
13
|
+
@node_query = NodeQuery.new(nql_or_rules)
|
|
14
14
|
@block = block
|
|
15
15
|
end
|
|
16
16
|
|
|
@@ -85,38 +85,29 @@ module Synvert::Core
|
|
|
85
85
|
# DSL #
|
|
86
86
|
#######
|
|
87
87
|
|
|
88
|
-
# Parse +find_node+ dsl, it creates {Synvert::Core::Rewriter::QueryScope} to recursively find matching ast nodes,
|
|
89
|
-
# then continue operating on each matching ast node.
|
|
90
|
-
# @example
|
|
91
|
-
# # matches FactoryBot.create(:user)
|
|
92
|
-
# find_node '.send[receiver=FactoryBot][message=create][arguments.size=1]' do
|
|
93
|
-
# end
|
|
94
|
-
# @param nql [String] node query language to find matching ast nodes.
|
|
95
|
-
# @yield run on the matching nodes.
|
|
96
|
-
# @raise [Synvert::Core::NodeQuery::Compiler::ParseError] if query string is invalid.
|
|
97
|
-
def find_node(nql, options = {}, &block)
|
|
98
|
-
Rewriter::QueryScope.new(self, nql, options, &block).process
|
|
99
|
-
rescue NodeQueryLexer::ScanError, Racc::ParseError => e
|
|
100
|
-
raise NodeQuery::Compiler::ParseError, "Invalid query string: #{nql}"
|
|
101
|
-
end
|
|
102
|
-
|
|
103
88
|
# Parse +within_node+ dsl, it creates a {Synvert::Core::Rewriter::WithinScope} to recursively find matching ast nodes,
|
|
104
89
|
# then continue operating on each matching ast node.
|
|
105
90
|
# @example
|
|
106
91
|
# # matches User.find_by_login('test')
|
|
107
92
|
# with_node type: 'send', message: /^find_by_/ do
|
|
108
93
|
# end
|
|
109
|
-
#
|
|
94
|
+
# # matches FactoryBot.create(:user)
|
|
95
|
+
# with_node '.send[receiver=FactoryBot][message=create][arguments.size=1]' do
|
|
96
|
+
# end
|
|
97
|
+
# @param nql_or_rules [String|Hash] nql or rules to find mathing ast nodes.
|
|
110
98
|
# @param options [Hash] optional
|
|
111
99
|
# @option including_self [Boolean] set if query the current node, default is true
|
|
112
100
|
# @option stop_at_first_match [Boolean] set if stop at first match, default is false
|
|
113
101
|
# @option recursive [Boolean] set if recursively query child nodes, default is true
|
|
114
102
|
# @yield run on the matching nodes.
|
|
115
|
-
def within_node(
|
|
116
|
-
Rewriter::WithinScope.new(self,
|
|
103
|
+
def within_node(nql_or_rules, options = {}, &block)
|
|
104
|
+
Rewriter::WithinScope.new(self, nql_or_rules, options, &block).process
|
|
105
|
+
rescue NodeQueryLexer::ScanError, Racc::ParseError => e
|
|
106
|
+
raise NodeQuery::Compiler::ParseError, "Invalid query string: #{nql_or_rules}"
|
|
117
107
|
end
|
|
118
108
|
|
|
119
109
|
alias with_node within_node
|
|
110
|
+
alias find_node within_node
|
|
120
111
|
|
|
121
112
|
# Parse +goto_node+ dsl, it creates a {Synvert::Core::Rewriter::GotoScope} to go to a child node,
|
|
122
113
|
# then continue operating on the child node.
|
|
@@ -140,10 +131,10 @@ module Synvert::Core
|
|
|
140
131
|
# if_exist_node type: 'send', message: 'any_instance' do
|
|
141
132
|
# end
|
|
142
133
|
# end
|
|
143
|
-
# @param
|
|
134
|
+
# @param nql_or_rules [String|Hash] nql or rules to check mathing ast nodes.
|
|
144
135
|
# @param block [Block] block code to continue operating on the matching nodes.
|
|
145
|
-
def if_exist_node(
|
|
146
|
-
Rewriter::IfExistCondition.new(self,
|
|
136
|
+
def if_exist_node(nql_or_rules, &block)
|
|
137
|
+
Rewriter::IfExistCondition.new(self, nql_or_rules, &block).process
|
|
147
138
|
end
|
|
148
139
|
|
|
149
140
|
# Parse +unless_exist_node+ dsl, it creates a {Synvert::Core::Rewriter::UnlessExistCondition} to check
|
|
@@ -154,14 +145,14 @@ module Synvert::Core
|
|
|
154
145
|
# unless_exist_node type: 'send', message: 'any_instance' do
|
|
155
146
|
# end
|
|
156
147
|
# end
|
|
157
|
-
# @param
|
|
148
|
+
# @param nql_or_rules [String|Hash] nql or rules to check mathing ast nodes.
|
|
158
149
|
# @param block [Block] block code to continue operating on the matching nodes.
|
|
159
|
-
def unless_exist_node(
|
|
160
|
-
Rewriter::UnlessExistCondition.new(self,
|
|
150
|
+
def unless_exist_node(nql_or_rules, &block)
|
|
151
|
+
Rewriter::UnlessExistCondition.new(self, nql_or_rules, &block).process
|
|
161
152
|
end
|
|
162
153
|
|
|
163
154
|
# Parse +if_only_exist_node+ dsl, it creates a {Synvert::Core::Rewriter::IfOnlyExistCondition} to check
|
|
164
|
-
# if current node has only one child node and the child node matches
|
|
155
|
+
# if current node has only one child node and the child node matches,
|
|
165
156
|
# if so, then continue operating on each matching ast node.
|
|
166
157
|
# @example
|
|
167
158
|
# # it { should matcher }
|
|
@@ -169,14 +160,13 @@ module Synvert::Core
|
|
|
169
160
|
# if_only_exist_node type: 'send', receiver: nil, message: 'should' do
|
|
170
161
|
# end
|
|
171
162
|
# end
|
|
172
|
-
# @param
|
|
163
|
+
# @param nql_or_rules [String|Hash] nql or rules to check mathing ast nodes.
|
|
173
164
|
# @param block [Block] block code to continue operating on the matching nodes.
|
|
174
|
-
def if_only_exist_node(
|
|
175
|
-
Rewriter::IfOnlyExistCondition.new(self,
|
|
165
|
+
def if_only_exist_node(nql_or_rules, &block)
|
|
166
|
+
Rewriter::IfOnlyExistCondition.new(self, nql_or_rules, &block).process
|
|
176
167
|
end
|
|
177
168
|
|
|
178
|
-
# Parse +append+ dsl, it
|
|
179
|
-
# append the code to the bottom of current node body.
|
|
169
|
+
# Parse +append+ dsl, it appends the code to the bottom of current node body.
|
|
180
170
|
# @example
|
|
181
171
|
# # def teardown
|
|
182
172
|
# # clean_something
|
|
@@ -194,8 +184,7 @@ module Synvert::Core
|
|
|
194
184
|
@current_mutation.append(@current_node, code)
|
|
195
185
|
end
|
|
196
186
|
|
|
197
|
-
# Parse +prepend+ dsl, it
|
|
198
|
-
# prepend the code to the top of current node body.
|
|
187
|
+
# Parse +prepend+ dsl, it prepends the code to the top of current node body.
|
|
199
188
|
# @example
|
|
200
189
|
# # def setup
|
|
201
190
|
# # do_something
|
|
@@ -213,7 +202,7 @@ module Synvert::Core
|
|
|
213
202
|
@current_mutation.prepend(@current_node, code)
|
|
214
203
|
end
|
|
215
204
|
|
|
216
|
-
# Parse +insert+ dsl, it
|
|
205
|
+
# Parse +insert+ dsl, it inserts code.
|
|
217
206
|
# @example
|
|
218
207
|
# # open('http://test.com')
|
|
219
208
|
# # =>
|
|
@@ -228,8 +217,7 @@ module Synvert::Core
|
|
|
228
217
|
@current_mutation.insert(@current_node, code, at: at, to: to)
|
|
229
218
|
end
|
|
230
219
|
|
|
231
|
-
# Parse +insert_after+ dsl, it
|
|
232
|
-
# insert the code next to the current node.
|
|
220
|
+
# Parse +insert_after+ dsl, it inserts the code next to the current node.
|
|
233
221
|
# @example
|
|
234
222
|
# # Synvert::Application.config.secret_token = "0447aa931d42918bfb934750bb78257088fb671186b5d1b6f9fddf126fc8a14d34f1d045cefab3900751c3da121a8dd929aec9bafe975f1cabb48232b4002e4e"
|
|
235
223
|
# # =>
|
|
@@ -240,11 +228,26 @@ module Synvert::Core
|
|
|
240
228
|
# end
|
|
241
229
|
# @param code [String] code need to be inserted.
|
|
242
230
|
def insert_after(code)
|
|
243
|
-
|
|
231
|
+
column = ' ' * NodeMutation.adapter.get_start_loc(@current_node).column
|
|
232
|
+
@current_mutation.insert(@current_node, "\n#{column}#{code}", { at: 'end' })
|
|
244
233
|
end
|
|
245
234
|
|
|
246
|
-
# Parse +
|
|
247
|
-
#
|
|
235
|
+
# Parse +insert_before+ dsl, it inserts the code previous to the current node.
|
|
236
|
+
# @example
|
|
237
|
+
# # Synvert::Application.config.secret_token = "0447aa931d42918bfb934750bb78257088fb671186b5d1b6f9fddf126fc8a14d34f1d045cefab3900751c3da121a8dd929aec9bafe975f1cabb48232b4002e4e"
|
|
238
|
+
# # =>
|
|
239
|
+
# # Synvert::Application.config.secret_key_base = "bf4f3f46924ecd9adcb6515681c78144545bba454420973a274d7021ff946b8ef043a95ca1a15a9d1b75f9fbdf85d1a3afaf22f4e3c2f3f78e24a0a188b581df"
|
|
240
|
+
# # Synvert::Application.config.secret_token = "0447aa931d42918bfb934750bb78257088fb671186b5d1b6f9fddf126fc8a14d34f1d045cefab3900751c3da121a8dd929aec9bafe975f1cabb48232b4002e4e"
|
|
241
|
+
# with_node type: 'send', message: 'secret_token=' do
|
|
242
|
+
# insert_before "{{receiver}}.secret_key_base = \"#{SecureRandom.hex(64)}\""
|
|
243
|
+
# end
|
|
244
|
+
# @param code [String] code need to be inserted.
|
|
245
|
+
def insert_before(code)
|
|
246
|
+
column = ' ' * NodeMutation.adapter.get_start_loc(@current_node).column
|
|
247
|
+
@current_mutation.insert(@current_node, "#{code}\n#{column}", { at: 'beginning' })
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
# Parse +replace_erb_stmt_with_expr+ dsl, it replaces erb stmt code to expr code.
|
|
248
251
|
# @example
|
|
249
252
|
# # <% form_for post do |f| %>
|
|
250
253
|
# # <% end %>
|
|
@@ -258,8 +261,7 @@ module Synvert::Core
|
|
|
258
261
|
@current_mutation.actions << Rewriter::ReplaceErbStmtWithExprAction.new(@current_node).process
|
|
259
262
|
end
|
|
260
263
|
|
|
261
|
-
# Parse +replace_with+ dsl, it
|
|
262
|
-
# replace the whole code of current node.
|
|
264
|
+
# Parse +replace_with+ dsl, it replaces the whole code of current node.
|
|
263
265
|
# @example
|
|
264
266
|
# # obj.stub(:foo => 1, :bar => 2)
|
|
265
267
|
# # =>
|
|
@@ -272,8 +274,7 @@ module Synvert::Core
|
|
|
272
274
|
@current_mutation.replace_with(@current_node, code)
|
|
273
275
|
end
|
|
274
276
|
|
|
275
|
-
# Parse +replace+ dsl, it
|
|
276
|
-
# replace the code of specified child nodes.
|
|
277
|
+
# Parse +replace+ dsl, it replaces the code of specified child nodes.
|
|
277
278
|
# @example
|
|
278
279
|
# # assert(object.empty?)
|
|
279
280
|
# # =>
|
|
@@ -288,7 +289,7 @@ module Synvert::Core
|
|
|
288
289
|
@current_mutation.replace(@current_node, *selectors, with: with)
|
|
289
290
|
end
|
|
290
291
|
|
|
291
|
-
# Parse +remove+ dsl, it
|
|
292
|
+
# Parse +remove+ dsl, it removes current node.
|
|
292
293
|
# @example
|
|
293
294
|
# with_node type: 'send', message: { in: %w[puts p] } do
|
|
294
295
|
# remove
|
|
@@ -299,7 +300,7 @@ module Synvert::Core
|
|
|
299
300
|
@current_mutation.remove(@current_node, **options)
|
|
300
301
|
end
|
|
301
302
|
|
|
302
|
-
# Parse +delete+ dsl, it
|
|
303
|
+
# Parse +delete+ dsl, it deletes child nodes.
|
|
303
304
|
# @example
|
|
304
305
|
# # FactoryBot.create(...)
|
|
305
306
|
# # =>
|
|
@@ -314,8 +315,7 @@ module Synvert::Core
|
|
|
314
315
|
@current_mutation.delete(@current_node, *selectors, **options)
|
|
315
316
|
end
|
|
316
317
|
|
|
317
|
-
# Parse +wrap+ dsl, it
|
|
318
|
-
# wrap current node with code.
|
|
318
|
+
# Parse +wrap+ dsl, it wraps current node with code.
|
|
319
319
|
# @example
|
|
320
320
|
# # class Foobar
|
|
321
321
|
# # end
|
|
@@ -434,16 +434,16 @@ module Synvert::Core
|
|
|
434
434
|
only_paths.flat_map do |only_path|
|
|
435
435
|
@file_patterns.flat_map do |file_pattern|
|
|
436
436
|
pattern = only_path == "." ? file_pattern : File.join(only_path, file_pattern)
|
|
437
|
-
Dir.glob(pattern)
|
|
437
|
+
Dir.glob(pattern)
|
|
438
438
|
end
|
|
439
|
-
end
|
|
439
|
+
end - get_skip_files
|
|
440
440
|
end
|
|
441
441
|
end
|
|
442
442
|
|
|
443
443
|
# Get skip files.
|
|
444
444
|
# @return [Array<String>] skip files
|
|
445
445
|
def get_skip_files
|
|
446
|
-
|
|
446
|
+
Configuration.skip_paths.flat_map do |skip_path|
|
|
447
447
|
if File.directory?(skip_path)
|
|
448
448
|
Dir.glob(File.join(skip_path, "**/*"))
|
|
449
449
|
elsif File.file?(skip_path)
|
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Synvert::Core
|
|
4
|
-
# WithinScope finds out nodes which match rules, then changes its scope to matching node.
|
|
4
|
+
# WithinScope finds out nodes which match nql or rules, then changes its scope to matching node.
|
|
5
5
|
class Rewriter::WithinScope < Rewriter::Scope
|
|
6
6
|
# Initialize a WithinScope.
|
|
7
7
|
#
|
|
8
8
|
# @param instance [Synvert::Core::Rewriter::Instance]
|
|
9
|
-
# @param
|
|
9
|
+
# @param nql_or_rules [String|Hash]
|
|
10
10
|
# @param options [Hash]
|
|
11
11
|
# @yield run on all matching nodes
|
|
12
|
-
|
|
12
|
+
# @raise [Synvert::Core::NodeQuery::Compiler::ParseError] if the query string is invalid.
|
|
13
|
+
def initialize(instance, nql_or_rules, options = {}, &block)
|
|
13
14
|
super(instance, &block)
|
|
14
15
|
|
|
15
16
|
@options = { including_self: true, stop_at_first_match: false, recursive: true }.merge(options)
|
|
16
|
-
@node_query = NodeQuery.new(
|
|
17
|
+
@node_query = NodeQuery.new(nql_or_rules)
|
|
17
18
|
end
|
|
18
19
|
|
|
19
20
|
# Find out the matching nodes.
|
|
21
|
+
#
|
|
20
22
|
# It checks the current node and iterates all child nodes,
|
|
21
23
|
# then run the block code on each matching node.
|
|
22
24
|
def process
|
|
@@ -17,7 +17,6 @@ module Synvert::Core
|
|
|
17
17
|
autoload :Instance, 'synvert/core/rewriter/instance'
|
|
18
18
|
|
|
19
19
|
autoload :Scope, 'synvert/core/rewriter/scope'
|
|
20
|
-
autoload :QueryScope, 'synvert/core/rewriter/scope/query_scope'
|
|
21
20
|
autoload :WithinScope, 'synvert/core/rewriter/scope/within_scope'
|
|
22
21
|
autoload :GotoScope, 'synvert/core/rewriter/scope/goto_scope'
|
|
23
22
|
|
data/lib/synvert/core/version.rb
CHANGED
|
@@ -12,7 +12,7 @@ module Synvert::Core
|
|
|
12
12
|
it 'parses find_node' do
|
|
13
13
|
scope = double
|
|
14
14
|
block = proc {}
|
|
15
|
-
expect(Rewriter::
|
|
15
|
+
expect(Rewriter::WithinScope).to receive(:new).with(instance, '.send[message=create]', {}, &block).and_return(scope)
|
|
16
16
|
expect(scope).to receive(:process)
|
|
17
17
|
instance.find_node('.send[message=create]', &block)
|
|
18
18
|
end
|
|
@@ -127,10 +127,19 @@ module Synvert::Core
|
|
|
127
127
|
it 'parses insert_after' do
|
|
128
128
|
instance.current_mutation = double
|
|
129
129
|
instance.current_node = double
|
|
130
|
-
expect(
|
|
130
|
+
expect(NodeMutation).to receive_message_chain(:adapter, :get_start_loc, :column).and_return(2)
|
|
131
|
+
expect(instance.current_mutation).to receive(:insert).with(instance.current_node, "\n Foobar", at: 'end')
|
|
131
132
|
instance.insert_after 'Foobar'
|
|
132
133
|
end
|
|
133
134
|
|
|
135
|
+
it 'parses insert_before' do
|
|
136
|
+
instance.current_mutation = double
|
|
137
|
+
instance.current_node = double
|
|
138
|
+
expect(NodeMutation).to receive_message_chain(:adapter, :get_start_loc, :column).and_return(2)
|
|
139
|
+
expect(instance.current_mutation).to receive(:insert).with(instance.current_node, "Foobar\n ", at: 'beginning')
|
|
140
|
+
instance.insert_before 'Foobar'
|
|
141
|
+
end
|
|
142
|
+
|
|
134
143
|
it 'parses replace_erb_stmt_with_expr' do
|
|
135
144
|
instance.current_mutation = double
|
|
136
145
|
instance.current_node = double
|
|
@@ -23,72 +23,117 @@ module Synvert::Core
|
|
|
23
23
|
before { instance.current_node = node }
|
|
24
24
|
|
|
25
25
|
describe '#process' do
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
26
|
+
context 'rules' do
|
|
27
|
+
it 'not call block if no matching node' do
|
|
28
|
+
run = false
|
|
29
|
+
scope =
|
|
30
|
+
Rewriter::WithinScope.new instance, type: 'send', message: 'missing' do
|
|
31
|
+
run = true
|
|
32
|
+
end
|
|
33
|
+
scope.process
|
|
34
|
+
expect(run).to be_falsey
|
|
35
|
+
end
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
37
|
+
it 'call block if there is matching node' do
|
|
38
|
+
run = false
|
|
39
|
+
type_in_scope = nil
|
|
40
|
+
scope =
|
|
41
|
+
Rewriter::WithinScope.new instance,
|
|
42
|
+
type: 'send',
|
|
43
|
+
receiver: 'FactoryGirl',
|
|
44
|
+
message: 'create',
|
|
45
|
+
arguments: [':user'] do
|
|
46
|
+
run = true
|
|
47
|
+
type_in_scope = node.type
|
|
48
|
+
end
|
|
49
|
+
scope.process
|
|
50
|
+
expect(run).to be_truthy
|
|
51
|
+
expect(type_in_scope).to eq :send
|
|
52
|
+
expect(instance.current_node.type).to eq :block
|
|
53
|
+
end
|
|
53
54
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
55
|
+
it 'matches multiple block nodes' do
|
|
56
|
+
block_nodes = []
|
|
57
|
+
scope =
|
|
58
|
+
Rewriter::WithinScope.new(instance, { type: 'block' }) do
|
|
59
|
+
block_nodes << node
|
|
60
|
+
end
|
|
61
|
+
scope.process
|
|
62
|
+
expect(block_nodes.size).to eq 3
|
|
63
|
+
end
|
|
63
64
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
65
|
+
it 'matches only 2 block nodes if including_self is false' do
|
|
66
|
+
block_nodes = []
|
|
67
|
+
scope =
|
|
68
|
+
Rewriter::WithinScope.new(instance, { type: 'block' }, { including_self: false }) do
|
|
69
|
+
block_nodes << node
|
|
70
|
+
end
|
|
71
|
+
scope.process
|
|
72
|
+
expect(block_nodes.size).to eq 2
|
|
73
|
+
end
|
|
73
74
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
75
|
+
it 'matches only one block node if recursive is false' do
|
|
76
|
+
block_nodes = []
|
|
77
|
+
scope =
|
|
78
|
+
Rewriter::WithinScope.new(instance, { type: 'block' }, { recursive: false }) do
|
|
79
|
+
block_nodes << node
|
|
80
|
+
end
|
|
81
|
+
scope.process
|
|
82
|
+
expect(block_nodes.size).to eq 1
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it 'matches only one block node if stop_at_first_match is true' do
|
|
86
|
+
block_nodes = []
|
|
87
|
+
scope =
|
|
88
|
+
Rewriter::WithinScope.new(instance, { type: 'block' }, { stop_at_first_match: true }) do
|
|
89
|
+
block_nodes << node
|
|
90
|
+
end
|
|
91
|
+
scope.process
|
|
92
|
+
expect(block_nodes.size).to eq 1
|
|
93
|
+
end
|
|
82
94
|
end
|
|
83
95
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
96
|
+
context 'nql' do
|
|
97
|
+
it 'not call block if no matching node' do
|
|
98
|
+
run = false
|
|
99
|
+
scope =
|
|
100
|
+
described_class.new instance, '.send[message=missing]' do
|
|
101
|
+
run = true
|
|
102
|
+
end
|
|
103
|
+
scope.process
|
|
104
|
+
expect(run).to be_falsey
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
it 'call block if there is matching node' do
|
|
108
|
+
run = false
|
|
109
|
+
type_in_scope = nil
|
|
110
|
+
scope =
|
|
111
|
+
described_class.new instance, '.send[receiver=FactoryGirl][message=create][arguments=(:user)]' do
|
|
112
|
+
run = true
|
|
113
|
+
type_in_scope = node.type
|
|
114
|
+
end
|
|
115
|
+
scope.process
|
|
116
|
+
expect(run).to be_truthy
|
|
117
|
+
expect(type_in_scope).to eq :send
|
|
118
|
+
expect(instance.current_node.type).to eq :block
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it 'matches multiple block nodes' do
|
|
122
|
+
block_nodes = []
|
|
123
|
+
scope =
|
|
124
|
+
described_class.new(instance, '.block') do
|
|
125
|
+
block_nodes << node
|
|
126
|
+
end
|
|
127
|
+
scope.process
|
|
128
|
+
expect(block_nodes.size).to eq 3
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
it 'raises InvalidOperatorError' do
|
|
132
|
+
scope = described_class.new(instance, '.send[receiver IN FactoryGirl]') {}
|
|
133
|
+
expect {
|
|
134
|
+
scope.process
|
|
135
|
+
}.to raise_error(NodeQuery::Compiler::InvalidOperatorError)
|
|
136
|
+
end
|
|
92
137
|
end
|
|
93
138
|
end
|
|
94
139
|
end
|
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.13.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-10-
|
|
11
|
+
date: 2022-10-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -144,7 +144,6 @@ files:
|
|
|
144
144
|
- lib/synvert/core/rewriter/ruby_version.rb
|
|
145
145
|
- lib/synvert/core/rewriter/scope.rb
|
|
146
146
|
- lib/synvert/core/rewriter/scope/goto_scope.rb
|
|
147
|
-
- lib/synvert/core/rewriter/scope/query_scope.rb
|
|
148
147
|
- lib/synvert/core/rewriter/scope/within_scope.rb
|
|
149
148
|
- lib/synvert/core/rewriter/warning.rb
|
|
150
149
|
- lib/synvert/core/utils.rb
|
|
@@ -163,7 +162,6 @@ files:
|
|
|
163
162
|
- spec/synvert/core/rewriter/instance_spec.rb
|
|
164
163
|
- spec/synvert/core/rewriter/ruby_version_spec.rb
|
|
165
164
|
- spec/synvert/core/rewriter/scope/goto_scope_spec.rb
|
|
166
|
-
- spec/synvert/core/rewriter/scope/query_scope_spec.rb
|
|
167
165
|
- spec/synvert/core/rewriter/scope/within_scope_spec.rb
|
|
168
166
|
- spec/synvert/core/rewriter/scope_spec.rb
|
|
169
167
|
- spec/synvert/core/rewriter/warning_spec.rb
|
|
@@ -208,7 +206,6 @@ test_files:
|
|
|
208
206
|
- spec/synvert/core/rewriter/instance_spec.rb
|
|
209
207
|
- spec/synvert/core/rewriter/ruby_version_spec.rb
|
|
210
208
|
- spec/synvert/core/rewriter/scope/goto_scope_spec.rb
|
|
211
|
-
- spec/synvert/core/rewriter/scope/query_scope_spec.rb
|
|
212
209
|
- spec/synvert/core/rewriter/scope/within_scope_spec.rb
|
|
213
210
|
- spec/synvert/core/rewriter/scope_spec.rb
|
|
214
211
|
- spec/synvert/core/rewriter/warning_spec.rb
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Synvert::Core
|
|
4
|
-
# QueryScope finds out nodes by using node query language, then changes its scope to matching node.
|
|
5
|
-
class Rewriter::QueryScope < Rewriter::Scope
|
|
6
|
-
# Initialize a QueryScope.
|
|
7
|
-
#
|
|
8
|
-
# @param instance [Synvert::Core::Rewriter::Instance]
|
|
9
|
-
# @param nql [String]
|
|
10
|
-
# @param options [Hash]
|
|
11
|
-
# @yield run on all matching nodes
|
|
12
|
-
def initialize(instance, nql, options = {}, &block)
|
|
13
|
-
super(instance, &block)
|
|
14
|
-
|
|
15
|
-
@options = { including_self: true, stop_at_first_match: false, recursive: true }.merge(options)
|
|
16
|
-
@node_query = NodeQuery.new(nql)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
# Find out the matching nodes.
|
|
20
|
-
#
|
|
21
|
-
# It checks the current node and iterates all child nodes,
|
|
22
|
-
# then run the block code on each matching node.
|
|
23
|
-
# @raise [Synvert::Core::NodeQuery::Compiler::ParseError] if the query string is invalid.
|
|
24
|
-
def process
|
|
25
|
-
current_node = @instance.current_node
|
|
26
|
-
return unless current_node
|
|
27
|
-
|
|
28
|
-
matching_nodes = @node_query.query_nodes(current_node, @options)
|
|
29
|
-
@instance.process_with_node(current_node) do
|
|
30
|
-
matching_nodes.each do |node|
|
|
31
|
-
@instance.process_with_node(node) do
|
|
32
|
-
@instance.instance_eval(&@block)
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
end
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'spec_helper'
|
|
4
|
-
|
|
5
|
-
module Synvert::Core
|
|
6
|
-
describe Rewriter::QueryScope do
|
|
7
|
-
let(:instance) {
|
|
8
|
-
rewriter = Rewriter.new('foo', 'bar')
|
|
9
|
-
Rewriter::Instance.new(rewriter, 'file pattern')
|
|
10
|
-
}
|
|
11
|
-
let(:source) { <<~EOS }
|
|
12
|
-
describe Post do
|
|
13
|
-
it 'gets post' do
|
|
14
|
-
FactoryGirl.create :post
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
EOS
|
|
18
|
-
|
|
19
|
-
let(:node) { Parser::CurrentRuby.parse(source) }
|
|
20
|
-
|
|
21
|
-
before { instance.current_node = node }
|
|
22
|
-
|
|
23
|
-
describe '#process' do
|
|
24
|
-
it 'not call block if no matching node' do
|
|
25
|
-
run = false
|
|
26
|
-
scope =
|
|
27
|
-
described_class.new instance, '.send[message=missing]' do
|
|
28
|
-
run = true
|
|
29
|
-
end
|
|
30
|
-
scope.process
|
|
31
|
-
expect(run).to be_falsey
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
it 'call block if there is matching node' do
|
|
35
|
-
run = false
|
|
36
|
-
type_in_scope = nil
|
|
37
|
-
scope =
|
|
38
|
-
described_class.new instance, '.send[receiver=FactoryGirl][message=create][arguments=(:post)]' do
|
|
39
|
-
run = true
|
|
40
|
-
type_in_scope = node.type
|
|
41
|
-
end
|
|
42
|
-
scope.process
|
|
43
|
-
expect(run).to be_truthy
|
|
44
|
-
expect(type_in_scope).to eq :send
|
|
45
|
-
expect(instance.current_node.type).to eq :block
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
it 'matches multiple block nodes' do
|
|
49
|
-
block_nodes = []
|
|
50
|
-
scope =
|
|
51
|
-
described_class.new(instance, '.block') do
|
|
52
|
-
block_nodes << node
|
|
53
|
-
end
|
|
54
|
-
scope.process
|
|
55
|
-
expect(block_nodes.size).to eq 2
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
it 'raises InvalidOperatorError' do
|
|
59
|
-
scope = described_class.new(instance, '.send[receiver IN FactoryGirl]') {}
|
|
60
|
-
expect {
|
|
61
|
-
scope.process
|
|
62
|
-
}.to raise_error(NodeQuery::Compiler::InvalidOperatorError)
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
end
|