synvert-core 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 71ae91a324677995dbfd9b1251ebf2a0a01e7c25289dcebcf86abb07599b1db8
4
- data.tar.gz: 4370235d14aee70f57b6b02313637e9d24b13ca2aee61b71e4fa4022f78bc3f8
3
+ metadata.gz: 5d838da042cfdbc68e4a235117a465ca340fa732203f7470684a9279e6797fff
4
+ data.tar.gz: ad784c3e09faa73a55e0bf0ad51a982230d9a1b2a328c43414e4aa297e38a00e
5
5
  SHA512:
6
- metadata.gz: 8bcd68a69575a6cd5c5c0bc7a91f82d09d2f438ab06988c01ad14c7d97c863bc2556f5c3ad7d054e35cfcb830cb778ec10a9797952a56a9391062b4bf3ce2a3f
7
- data.tar.gz: be7b4c9fda8428c0d2a8c29350f6d2c60c40577c0f990ed5d8f4d2742fc2545fc8ddbd139298aaf39a9e69e9e9bf83fe29385745ac7ef10459da836572df9327
6
+ metadata.gz: 4b31e94f8071af04f1ae7b1292bb5af91e52ba047949535667cb6765a5ef32c9bbcf855dd92a212aa640b0185f42fbd1bbcf4614f424c596f9c52f62a313a643
7
+ data.tar.gz: 197318ccffd17c9eb60251731bf49f45198e2b5fb5812c22d4fe6d0d07bac94bff638bc5a125d05be2ccec930b16300ccdb83ffdd53bf8cf0c4cd8ad22a34c94
@@ -15,7 +15,6 @@ on:
15
15
 
16
16
  jobs:
17
17
  test:
18
-
19
18
  runs-on: ubuntu-latest
20
19
  strategy:
21
20
  matrix:
data/.gitignore CHANGED
@@ -3,7 +3,6 @@
3
3
  .bundle
4
4
  .config
5
5
  .yardoc
6
- Gemfile.lock
7
6
  InstalledFiles
8
7
  _yardoc
9
8
  coverage
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 1.6.0 (2022-09-15)
4
+
5
+ * Make use of `NodeQuery` to query nodes
6
+ * Remove `Node#to_hash`
7
+ * Downgrade `activesupport` to < 7.0.0
8
+
3
9
  ## 1.5.0 (2022-07-02)
4
10
 
5
11
  * Abstract `node_query`
data/Gemfile.lock ADDED
@@ -0,0 +1,101 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ synvert-core (1.6.0)
5
+ activesupport (< 7.0.0)
6
+ erubis
7
+ node_mutation
8
+ node_query
9
+ parser
10
+ parser_node_ext
11
+
12
+ GEM
13
+ remote: https://rubygems.org/
14
+ specs:
15
+ activesupport (6.1.7)
16
+ concurrent-ruby (~> 1.0, >= 1.0.2)
17
+ i18n (>= 1.6, < 2)
18
+ minitest (>= 5.1)
19
+ tzinfo (~> 2.0)
20
+ zeitwerk (~> 2.3)
21
+ ast (2.4.2)
22
+ coderay (1.1.3)
23
+ concurrent-ruby (1.1.10)
24
+ diff-lcs (1.5.0)
25
+ erubis (2.7.0)
26
+ ffi (1.15.5)
27
+ formatador (1.1.0)
28
+ guard (2.18.0)
29
+ formatador (>= 0.2.4)
30
+ listen (>= 2.7, < 4.0)
31
+ lumberjack (>= 1.0.12, < 2.0)
32
+ nenv (~> 0.1)
33
+ notiffany (~> 0.0)
34
+ pry (>= 0.13.0)
35
+ shellany (~> 0.0)
36
+ thor (>= 0.18.1)
37
+ guard-compat (1.2.1)
38
+ guard-rspec (4.7.3)
39
+ guard (~> 2.1)
40
+ guard-compat (~> 1.1)
41
+ rspec (>= 2.99.0, < 4.0)
42
+ i18n (1.12.0)
43
+ concurrent-ruby (~> 1.0)
44
+ listen (3.7.1)
45
+ rb-fsevent (~> 0.10, >= 0.10.3)
46
+ rb-inotify (~> 0.9, >= 0.9.10)
47
+ lumberjack (1.2.8)
48
+ method_source (1.0.0)
49
+ minitest (5.16.3)
50
+ nenv (0.3.0)
51
+ node_mutation (1.2.1)
52
+ activesupport
53
+ erubis
54
+ node_query (1.5.0)
55
+ activesupport (< 7.0.0)
56
+ notiffany (0.1.3)
57
+ nenv (~> 0.1)
58
+ shellany (~> 0.0)
59
+ parser (3.1.2.1)
60
+ ast (~> 2.4.1)
61
+ parser_node_ext (0.4.0)
62
+ parser
63
+ pry (0.14.1)
64
+ coderay (~> 1.1)
65
+ method_source (~> 1.0)
66
+ rake (13.0.6)
67
+ rb-fsevent (0.11.1)
68
+ rb-inotify (0.10.1)
69
+ ffi (~> 1.0)
70
+ rspec (3.10.0)
71
+ rspec-core (~> 3.10.0)
72
+ rspec-expectations (~> 3.10.0)
73
+ rspec-mocks (~> 3.10.0)
74
+ rspec-core (3.10.2)
75
+ rspec-support (~> 3.10.0)
76
+ rspec-expectations (3.10.2)
77
+ diff-lcs (>= 1.2.0, < 2.0)
78
+ rspec-support (~> 3.10.0)
79
+ rspec-mocks (3.10.2)
80
+ diff-lcs (>= 1.2.0, < 2.0)
81
+ rspec-support (~> 3.10.0)
82
+ rspec-support (3.10.3)
83
+ shellany (0.0.1)
84
+ thor (1.2.1)
85
+ tzinfo (2.0.5)
86
+ concurrent-ruby (~> 1.0)
87
+ zeitwerk (2.6.0)
88
+
89
+ PLATFORMS
90
+ ruby
91
+
92
+ DEPENDENCIES
93
+ guard
94
+ guard-rspec
95
+ rake
96
+ rspec
97
+ rspec-mocks
98
+ synvert-core!
99
+
100
+ BUNDLED WITH
101
+ 2.3.7
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # synvert-core-ruby
2
2
 
3
- <img src="https://synvert.xinminlabs.com/img/logo_96.png" alt="logo" width="32" height="32" />
3
+ <img src="https://synvert.net/img/logo_96.png" alt="logo" width="32" height="32" />
4
4
 
5
5
  [![AwesomeCode Status for xinminlabs/synvert-core-ruby](https://awesomecode.io/projects/033f7f02-7b22-41c3-a902-fca37f1ec72a/status)](https://awesomecode.io/repos/xinminlabs/synvert-core-ruby)
6
6
  ![Main workflow](https://github.com/xinminlabs/synvert-core-ruby/actions/workflows/main.yml/badge.svg)
@@ -50,43 +50,6 @@ module Parser::AST
50
50
  loc.expression.line
51
51
  end
52
52
 
53
- # Match node with rules.
54
- # It provides some additional keywords to match rules, +any+, +contain+, +not+, +in+, +not_in+, +gt+, +gte+, +lt+, +lte+.
55
- # @example
56
- # type: 'send', arguments: { any: 'Lifo::ShowExceptions' }
57
- # type: { in: ['send', 'csend'] }
58
- # type: :send, arguments: { length: { gt: 2 } }
59
- # @param rules [Hash] rules to match.
60
- # @return true if matches.
61
- def match?(rules)
62
- keywords = %i[any contain not in not_in gt gte lt lte]
63
- flat_hash(rules).keys.all? do |multi_keys|
64
- last_key = multi_keys.last
65
- actual = keywords.include?(last_key) ? actual_value(multi_keys[0...-1]) : actual_value(multi_keys)
66
- expected = expected_value(rules, multi_keys)
67
- case last_key
68
- when :any, :contain
69
- actual.any? { |actual_value| match_value?(actual_value, expected) }
70
- when :not
71
- !match_value?(actual, expected)
72
- when :in
73
- expected.any? { |expected_value| match_value?(actual, expected_value) }
74
- when :not_in
75
- expected.all? { |expected_value| !match_value?(actual, expected_value) }
76
- when :gt
77
- actual > expected
78
- when :gte
79
- actual >= expected
80
- when :lt
81
- actual < expected
82
- when :lte
83
- actual <= expected
84
- else
85
- match_value?(actual, expected)
86
- end
87
- end
88
- end
89
-
90
53
  # Strip curly braces for hash.
91
54
  # @example
92
55
  # node # s(:hash, s(:pair, s(:sym, :foo), s(:str, "bar")))
@@ -161,141 +124,5 @@ module Parser::AST
161
124
  to_source
162
125
  end
163
126
  end
164
-
165
- # Convert node to a hash, so that it can be converted to a json.
166
- def to_hash
167
- result = { type: type }
168
- if TYPE_CHILDREN[type]
169
- TYPE_CHILDREN[type].each do |key|
170
- value = send(key)
171
- result[key] =
172
- case value
173
- when Array
174
- value.map { |v| v.respond_to?(:to_hash) ? v.to_hash : v }
175
- when Parser::AST::Node
176
- value.to_hash
177
- else
178
- value
179
- end
180
- end
181
- else
182
- result[:children] = children.map { |c| c.respond_to?(:to_hash) ? c.to_hash : c }
183
- end
184
- result
185
- end
186
-
187
- private
188
-
189
- # Compare actual value with expected value.
190
- #
191
- # @param actual [Object] actual value.
192
- # @param expected [Object] expected value.
193
- # @return [Boolean]
194
- # @raise [Synvert::Core::MethodNotSupported] if expected class is not supported.
195
- def match_value?(actual, expected)
196
- return true if actual == expected
197
-
198
- case expected
199
- when Symbol
200
- if actual.is_a?(Parser::AST::Node)
201
- actual.to_source == ":#{expected}" || actual.to_source == expected.to_s
202
- else
203
- actual.to_sym == expected
204
- end
205
- when String
206
- if actual.is_a?(Parser::AST::Node)
207
- actual.to_source == expected || actual.to_source == unwrap_quote(expected) ||
208
- unwrap_quote(actual.to_source) == expected || unwrap_quote(actual.to_source) == unwrap_quote(expected)
209
- else
210
- actual.to_s == expected || wrap_quote(actual.to_s) == expected
211
- end
212
- when Regexp
213
- if actual.is_a?(Parser::AST::Node)
214
- actual.to_source =~ Regexp.new(expected.to_s, Regexp::MULTILINE)
215
- else
216
- actual.to_s =~ Regexp.new(expected.to_s, Regexp::MULTILINE)
217
- end
218
- when Array
219
- return false unless expected.length == actual.length
220
-
221
- actual.zip(expected).all? { |a, e| match_value?(a, e) }
222
- when NilClass
223
- if actual.is_a?(Parser::AST::Node)
224
- :nil == actual.type
225
- else
226
- actual.nil?
227
- end
228
- when Numeric
229
- if actual.is_a?(Parser::AST::Node)
230
- actual.children[0] == expected
231
- else
232
- actual == expected
233
- end
234
- when TrueClass
235
- :true == actual.type
236
- when FalseClass
237
- :false == actual.type
238
- when Parser::AST::Node
239
- actual == expected
240
- when Synvert::Core::Rewriter::AnyValue
241
- !actual.nil?
242
- else
243
- raise Synvert::Core::MethodNotSupported, "#{expected.class} is not handled for match_value?"
244
- end
245
- end
246
-
247
- # Convert a hash to flat one.
248
- #
249
- # @example
250
- # flat_hash(type: 'block', caller: {type: 'send', receiver: 'RSpec'})
251
- # # {[:type] => 'block', [:caller, :type] => 'send', [:caller, :receiver] => 'RSpec'}
252
- # @param h [Hash] original hash.
253
- # @return flatten hash.
254
- def flat_hash(h, k = [])
255
- new_hash = {}
256
- h.each_pair do |key, val|
257
- if val.is_a?(Hash)
258
- new_hash.merge!(flat_hash(val, k + [key]))
259
- else
260
- new_hash[k + [key]] = val
261
- end
262
- end
263
- new_hash
264
- end
265
-
266
- # Get actual value from the node.
267
- #
268
- # @param multi_keys [Array<Symbol, String>]
269
- # @return [Object] actual value.
270
- def actual_value(multi_keys)
271
- multi_keys.inject(self) { |n, key| n.send(key) if n }
272
- end
273
-
274
- # Get expected value from rules.
275
- #
276
- # @param rules [Hash]
277
- # @param multi_keys [Array<Symbol>]
278
- # @return [Object] expected value.
279
- def expected_value(rules, multi_keys)
280
- multi_keys.inject(rules) { |o, key| o[key] }
281
- end
282
-
283
- # Wrap the string with single or double quote.
284
- def wrap_quote(string)
285
- if string.include?("'")
286
- "\"#{string}\""
287
- else
288
- "'#{string}'"
289
- end
290
- end
291
-
292
- # Unwrap the quote from the string.
293
- def unwrap_quote(string)
294
- if (string[0] == '"' && string[-1] == '"') || (string[0] == "'" && string[-1] == "'")
295
- string[1...-1]
296
- else
297
- string
298
- end
299
- end
300
127
  end
301
128
  end
@@ -9,11 +9,7 @@ module Synvert::Core
9
9
  #
10
10
  # @return [Boolean]
11
11
  def match?
12
- match = false
13
- NodeQuery::Helper.handle_recursive_child(@instance.current_node) do |child_node|
14
- match ||= child_node&.match?(@rules)
15
- end
16
- match
12
+ @node_query.query_nodes(target_node, including_self: false, stop_at_first_match: true).size > 0
17
13
  end
18
14
  end
19
15
  end
@@ -9,7 +9,7 @@ module Synvert::Core
9
9
  #
10
10
  # @return [Boolean]
11
11
  def match?
12
- @instance.current_node.body.size == 1 && @instance.current_node.body.first.match?(@rules)
12
+ target_node.body.size == 1 && @node_query.match_node?(target_node.body.first)
13
13
  end
14
14
  end
15
15
  end
@@ -9,11 +9,7 @@ module Synvert::Core
9
9
  #
10
10
  # return [Boolean]
11
11
  def match?
12
- match = false
13
- NodeQuery::Helper.handle_recursive_child(@instance.current_node) do |child_node|
14
- match ||= child_node&.match?(@rules)
15
- end
16
- !match
12
+ @node_query.query_nodes(target_node, including_self: false, stop_at_first_match: true).size == 0
17
13
  end
18
14
  end
19
15
  end
@@ -10,7 +10,7 @@ module Synvert::Core
10
10
  # @yield run when condition matches
11
11
  def initialize(instance, rules, &block)
12
12
  @instance = instance
13
- @rules = rules
13
+ @node_query = NodeQuery.new(rules)
14
14
  @block = block
15
15
  end
16
16
 
@@ -27,5 +27,9 @@ module Synvert::Core
27
27
  def match?
28
28
  raise NotImplementedError, 'must be implemented by subclasses'
29
29
  end
30
+
31
+ def target_node
32
+ @instance.current_node
33
+ end
30
34
  end
31
35
  end
@@ -79,11 +79,13 @@ module Synvert::Core
79
79
  # # matches FactoryBot.create(:user)
80
80
  # find_node '.send[receiver=FactoryBot][message=create][arguments.size=1]' do
81
81
  # end
82
- # @param query_string [String] query string to find matching ast nodes.
82
+ # @param nql [String] node query language to find matching ast nodes.
83
83
  # @yield run on the matching nodes.
84
84
  # @raise [Synvert::Core::NodeQuery::Compiler::ParseError] if query string is invalid.
85
- def find_node(query_string, &block)
86
- Rewriter::QueryScope.new(self, query_string, &block).process
85
+ def find_node(nql, options = {}, &block)
86
+ Rewriter::QueryScope.new(self, nql, options, &block).process
87
+ rescue NodeQueryLexer::ScanError, Racc::ParseError => e
88
+ raise NodeQuery::Compiler::ParseError, "Invalid query string: #{nql}"
87
89
  end
88
90
 
89
91
  # Parse +within_node+ dsl, it creates a {Synvert::Core::Rewriter::WithinScope} to recursively find matching ast nodes,
@@ -94,12 +96,11 @@ module Synvert::Core
94
96
  # end
95
97
  # @param rules [Hash] rules to find mathing ast nodes.
96
98
  # @param options [Hash] optional
97
- # @option stop_when_match [Boolean] set if stop when match, default is false
98
- # @option direct [Boolean] set if find direct matching ast nodes, default is false
99
+ # @option including_self [Boolean] set if query the current node, default is true
100
+ # @option stop_at_first_match [Boolean] set if stop at first match, default is false
101
+ # @option recursive [Boolean] set if recursively query child nodes, default is true
99
102
  # @yield run on the matching nodes.
100
103
  def within_node(rules, options = {}, &block)
101
- options[:stop_when_match] ||= false
102
- options[:direct] ||= false
103
104
  Rewriter::WithinScope.new(self, rules, options, &block).process
104
105
  end
105
106
 
@@ -6,11 +6,14 @@ module Synvert::Core
6
6
  # Initialize a QueryScope.
7
7
  #
8
8
  # @param instance [Synvert::Core::Rewriter::Instance]
9
- # @param query_string [String]
9
+ # @param nql [String]
10
+ # @param options [Hash]
10
11
  # @yield run on all matching nodes
11
- def initialize(instance, query_string, &block)
12
+ def initialize(instance, nql, options = {}, &block)
12
13
  super(instance, &block)
13
- @query_string = query_string
14
+
15
+ @options = { including_self: true, stop_at_first_match: false, recursive: true }.merge(options)
16
+ @node_query = NodeQuery.new(nql)
14
17
  end
15
18
 
16
19
  # Find out the matching nodes.
@@ -22,15 +25,14 @@ module Synvert::Core
22
25
  current_node = @instance.current_node
23
26
  return unless current_node
24
27
 
28
+ matching_nodes = @node_query.query_nodes(current_node, @options)
25
29
  @instance.process_with_node(current_node) do
26
- NodeQuery.new(@query_string).parse(current_node).each do |node|
30
+ matching_nodes.each do |node|
27
31
  @instance.process_with_node(node) do
28
32
  @instance.instance_eval(&@block)
29
33
  end
30
34
  end
31
35
  end
32
- rescue NodeQueryLexer::ScanError, Racc::ParseError => e
33
- raise NodeQuery::Compiler::ParseError, "Invalid query string: #{@query_string}"
34
36
  end
35
37
  end
36
38
  end
@@ -11,8 +11,9 @@ module Synvert::Core
11
11
  # @yield run on all matching nodes
12
12
  def initialize(instance, rules, options = {}, &block)
13
13
  super(instance, &block)
14
- @rules = rules
15
- @options = options
14
+
15
+ @options = { including_self: true, stop_at_first_match: false, recursive: true }.merge(options)
16
+ @node_query = NodeQuery.new(rules)
16
17
  end
17
18
 
18
19
  # Find out the matching nodes.
@@ -22,14 +23,7 @@ module Synvert::Core
22
23
  current_node = @instance.current_node
23
24
  return unless current_node
24
25
 
25
- matching_nodes =
26
- if @options[:direct]
27
- find_direct_matching_nodes(current_node)
28
- elsif @options[:stop_when_match]
29
- find_matching_nodes(current_node)
30
- else
31
- find_recursive_matching_nodes(current_node)
32
- end
26
+ matching_nodes = @node_query.query_nodes(current_node, @options)
33
27
  @instance.process_with_node current_node do
34
28
  matching_nodes.each do |matching_node|
35
29
  @instance.process_with_node matching_node do
@@ -38,82 +32,5 @@ module Synvert::Core
38
32
  end
39
33
  end
40
34
  end
41
-
42
- private
43
-
44
- # Find the matching nodes only in current or direct children.
45
- #
46
- # @param current_node [Parser::AST::Node]
47
- def find_direct_matching_nodes(current_node)
48
- matching_nodes = []
49
- if current_node.is_a?(Parser::AST::Node)
50
- if current_node.type == :begin
51
- current_node.children.each do |child_node|
52
- matching_nodes << child_node if child_node.match?(@rules)
53
- end
54
- elsif current_node.match?(@rules)
55
- matching_nodes << current_node
56
- end
57
- else
58
- current_node.each do |child_node|
59
- matching_nodes << child_node if child_node.match?(@rules)
60
- end
61
- end
62
- matching_nodes
63
- end
64
-
65
- # Find matching nodes in all recursive children.
66
- #
67
- # @param current_node [Parser::AST::Node]
68
- def find_recursive_matching_nodes(current_node)
69
- matching_nodes = []
70
- if current_node.is_a?(Parser::AST::Node)
71
- matching_nodes << current_node if current_node.match?(@rules)
72
- NodeQuery::Helper.handle_recursive_child(current_node) do |child_node|
73
- matching_nodes << child_node if child_node.match?(@rules)
74
- end
75
- else
76
- current_node.each do |node|
77
- matching_nodes << node if node.match?(@rules)
78
- NodeQuery::Helper.handle_recursive_child(node) do |child_node|
79
- matching_nodes << child_node if child_node.match?(@rules)
80
- end
81
- end
82
- end
83
- matching_nodes
84
- end
85
-
86
- # Find matching nodes in recursive children but do not continue on matching nodes.
87
- #
88
- # @param current_node [Parser::AST::Node]
89
- def find_matching_nodes(current_node)
90
- matching_nodes = []
91
- if current_node.is_a?(Parser::AST::Node)
92
- if current_node.match?(@rules)
93
- matching_nodes << current_node
94
- return matching_nodes
95
- end
96
- NodeQuery::Helper.handle_recursive_child(current_node) do |child_node|
97
- if child_node.match?(@rules)
98
- matching_nodes << child_node
99
- next :stop
100
- end
101
- end
102
- else
103
- current_node.each do |node|
104
- if node.match?(@rules)
105
- matching_nodes << node
106
- next
107
- end
108
- NodeQuery::Helper.handle_recursive_child(node) do |child_node|
109
- if child_node.match?(@rules)
110
- matching_nodes << child_node
111
- next :stop
112
- end
113
- end
114
- end
115
- end
116
- matching_nodes
117
- end
118
35
  end
119
36
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Synvert
4
4
  module Core
5
- VERSION = '1.5.0'
5
+ VERSION = '1.6.0'
6
6
  end
7
7
  end
@@ -3,133 +3,6 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Parser::AST::Node do
6
- describe '#match?' do
7
- it 'matches class name' do
8
- source = 'class Synvert; end'
9
- node = parse(source)
10
- expect(node).to be_match(type: 'class', name: 'Synvert')
11
- end
12
-
13
- it 'matches message with regexp' do
14
- source = 'User.find_by_login(login)'
15
- node = parse(source)
16
- expect(node).to be_match(type: 'send', message: /^find_by_/)
17
- end
18
-
19
- it 'matches arguments with symbol' do
20
- source = 'params[:user]'
21
- node = parse(source)
22
- expect(node).to be_match(type: 'send', receiver: 'params', message: '[]', arguments: [:user])
23
- end
24
-
25
- it 'matches pair key with symbol' do
26
- source = '{ type: :model }'
27
- node = parse(source).children[0]
28
- expect(node).to be_match(type: 'pair', key: :type)
29
- end
30
-
31
- it 'matches assign number' do
32
- source = 'at_least(0)'
33
- node = parse(source)
34
- expect(node).to be_match(type: 'send', arguments: [0])
35
- end
36
-
37
- it 'matches assign float' do
38
- source = 'at_least(1.5)'
39
- node = parse(source)
40
- expect(node).to be_match(type: 'send', arguments: [1.5])
41
- end
42
-
43
- it 'matches arguments with string' do
44
- source = 'params["user"]'
45
- node = parse(source)
46
- expect(node).to be_match(type: 'send', receiver: 'params', message: '[]', arguments: ['user'])
47
- end
48
-
49
- it 'matches arguments with string 2' do
50
- source = 'params["user"]'
51
- node = parse(source)
52
- expect(node).to be_match(type: 'send', receiver: 'params', message: '[]', arguments: ["'user'"])
53
- end
54
-
55
- it 'matches arguments with string 3' do
56
- source = "{ notice: 'Welcome' }"
57
- node = parse(source)
58
- expect(node).to be_match(type: 'hash', notice_value: "'Welcome'")
59
- end
60
-
61
- it 'matches arguments any' do
62
- source = 'config.middleware.insert_after ActiveRecord::QueryCache, Lifo::Cache, page_cache: false'
63
- node = parse(source)
64
- expect(node).to be_match(type: 'send', arguments: { any: 'Lifo::Cache' })
65
- end
66
-
67
- it 'matches arguments with nested hash' do
68
- source = '{ user_id: user.id }'
69
- node = parse(source)
70
- expect(node).to be_match(
71
- type: 'hash',
72
- user_id_value: {
73
- type: 'send',
74
- receiver: { type: 'send', message: 'user' },
75
- message: 'id'
76
- }
77
- )
78
- end
79
-
80
- it 'matches arguments contain' do
81
- source = 'def slow(foo, bar, &block); end'
82
- node = parse(source)
83
- expect(node).to be_match(type: 'def', arguments: { contain: '&block' })
84
- end
85
-
86
- it 'matches not' do
87
- source = 'class Synvert; end'
88
- node = parse(source)
89
- expect(node).not_to be_match(type: 'class', name: { not: 'Synvert' })
90
- end
91
-
92
- it 'matches in' do
93
- source = 'FactoryBot.create(:user)'
94
- node = parse(source)
95
- expect(node).to be_match(type: 'send', message: { in: %i[create build] })
96
- end
97
-
98
- it 'matches not_in' do
99
- source = 'FactoryBot.create(:user)'
100
- node = parse(source)
101
- expect(node).not_to be_match(type: 'send', message: { not_in: %i[create build] })
102
- end
103
-
104
- it 'matches gt' do
105
- source = 'foobar(foo, bar)'
106
- node = parse(source)
107
- expect(node).to be_match(type: 'send', arguments: { size: { gt: 1 } })
108
- expect(node).not_to be_match(type: 'send', arguments: { size: { gt: 2 } })
109
- end
110
-
111
- it 'matches gte' do
112
- source = 'foobar(foo, bar)'
113
- node = parse(source)
114
- expect(node).to be_match(type: 'send', arguments: { size: { gte: 2 } })
115
- expect(node).not_to be_match(type: 'send', arguments: { size: { gte: 3 } })
116
- end
117
-
118
- it 'matches lt' do
119
- source = 'foobar(foo, bar)'
120
- node = parse(source)
121
- expect(node).to be_match(type: 'send', arguments: { size: { lt: 3 } })
122
- expect(node).not_to be_match(type: 'send', arguments: { size: { lt: 2 } })
123
- end
124
-
125
- it 'matches lte' do
126
- source = 'foobar(foo, bar)'
127
- node = parse(source)
128
- expect(node).to be_match(type: 'send', arguments: { size: { lte: 2 } })
129
- expect(node).not_to be_match(type: 'send', arguments: { size: { lte: 1 } })
130
- end
131
- end
132
-
133
6
  describe '#strip_curly_braces' do
134
7
  context 'hash node' do
135
8
  it 'removes curly braces' do
@@ -232,47 +105,4 @@ describe Parser::AST::Node do
232
105
  end
233
106
  end
234
107
  end
235
-
236
- describe '#to_hash' do
237
- it 'gets hash' do
238
- node = parse(<<~EOS)
239
- class Synvert
240
- def foobar(foo, bar)
241
- { foo => bar }
242
- end
243
- end
244
- EOS
245
- expect(node.to_hash).to eq(
246
- {
247
- type: :class,
248
- parent_class: nil,
249
- name: {
250
- type: :const,
251
- parent_const: nil,
252
- name: :Synvert
253
- },
254
- body: [
255
- {
256
- type: :def,
257
- name: :foobar,
258
- arguments: [
259
- { type: :arg, name: :foo },
260
- { type: :arg, name: :bar }
261
- ],
262
- body: [
263
- {
264
- type: :hash,
265
- pairs: {
266
- type: :pair,
267
- key: { type: :lvar, name: :foo },
268
- value: { type: :lvar, name: :bar }
269
- }
270
- }
271
- ]
272
- }
273
- ]
274
- }
275
- )
276
- end
277
- end
278
108
  end
@@ -12,16 +12,27 @@ module Synvert::Core
12
12
  it 'parses find_node' do
13
13
  scope = double
14
14
  block = proc {}
15
- expect(Rewriter::QueryScope).to receive(:new).with(instance, '.send[message=create]', &block).and_return(scope)
15
+ expect(Rewriter::QueryScope).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
19
19
 
20
+ it 'raises ParseError when parsing invalid nql' do
21
+ block = proc {}
22
+ expect {
23
+ instance.find_node('synvert', &block)
24
+ }.to raise_error(NodeQuery::Compiler::ParseError)
25
+
26
+ expect {
27
+ instance.find_node('.block <caller.arguments> .hash', &block)
28
+ }.to raise_error(NodeQuery::Compiler::ParseError)
29
+ end
30
+
20
31
  it 'parses within_node' do
21
32
  scope = double
22
33
  block = proc {}
23
34
  expect(Rewriter::WithinScope).to receive(:new)
24
- .with(instance, { type: 'send', message: 'create' }, { stop_when_match: false, direct: false }, &block)
35
+ .with(instance, { type: 'send', message: 'create' }, {}, &block)
25
36
  .and_return(scope)
26
37
  expect(scope).to receive(:process)
27
38
  instance.within_node(type: 'send', message: 'create', &block)
@@ -31,30 +42,20 @@ module Synvert::Core
31
42
  scope = double
32
43
  block = proc {}
33
44
  expect(Rewriter::WithinScope).to receive(:new)
34
- .with(instance, { type: 'send', message: 'create' }, { stop_when_match: false, direct: false }, &block)
45
+ .with(instance, { type: 'send', message: 'create' }, {}, &block)
35
46
  .and_return(scope)
36
47
  expect(scope).to receive(:process)
37
48
  instance.with_node(type: 'send', message: 'create', &block)
38
49
  end
39
50
 
40
- it 'parses within_node with stop_when_match true' do
41
- scope = double
42
- block = proc {}
43
- expect(Rewriter::WithinScope).to receive(:new)
44
- .with(instance, { type: 'send', message: 'create' }, { stop_when_match: true, direct: false }, &block)
45
- .and_return(scope)
46
- expect(scope).to receive(:process)
47
- instance.within_node({ type: 'send', message: 'create' }, { stop_when_match: true }, &block)
48
- end
49
-
50
- it 'parses within_node with direct true' do
51
+ it 'parses within_node with stop_at_first_match true' do
51
52
  scope = double
52
53
  block = proc {}
53
54
  expect(Rewriter::WithinScope).to receive(:new)
54
- .with(instance, { type: 'send', message: 'create' }, { stop_when_match: false, direct: true }, &block)
55
+ .with(instance, { type: 'send', message: 'create' }, { stop_at_first_match: true }, &block)
55
56
  .and_return(scope)
56
57
  expect(scope).to receive(:process)
57
- instance.within_node({ type: 'send', message: 'create' }, { direct: true }, &block)
58
+ instance.within_node({ type: 'send', message: 'create' }, { stop_at_first_match: true }, &block)
58
59
  end
59
60
 
60
61
  it 'parses goto_node' do
@@ -55,18 +55,6 @@ module Synvert::Core
55
55
  expect(block_nodes.size).to eq 2
56
56
  end
57
57
 
58
- it 'raises ParseError' do
59
- scope = described_class.new(instance, 'synvert') {}
60
- expect {
61
- scope.process
62
- }.to raise_error(NodeQuery::Compiler::ParseError)
63
-
64
- scope = described_class.new(instance, '.block <caller.arguments> .hash') {}
65
- expect {
66
- scope.process
67
- }.to raise_error(NodeQuery::Compiler::ParseError)
68
- end
69
-
70
58
  it 'raises InvalidOperatorError' do
71
59
  scope = described_class.new(instance, '.send[receiver IN FactoryGirl]') {}
72
60
  expect {
@@ -9,9 +9,11 @@ module Synvert::Core
9
9
  Rewriter::Instance.new(rewriter, 'file pattern')
10
10
  }
11
11
  let(:source) { <<~EOS }
12
- describe Post do
13
- it 'gets post' do
14
- FactoryGirl.create :post
12
+ describe User do
13
+ describe 'create' do
14
+ it 'creates user' do
15
+ FactoryGirl.create :user
16
+ end
15
17
  end
16
18
  end
17
19
  EOS
@@ -39,7 +41,7 @@ module Synvert::Core
39
41
  type: 'send',
40
42
  receiver: 'FactoryGirl',
41
43
  message: 'create',
42
- arguments: [':post'] do
44
+ arguments: [':user'] do
43
45
  run = true
44
46
  type_in_scope = node.type
45
47
  end
@@ -52,27 +54,37 @@ module Synvert::Core
52
54
  it 'matches multiple block nodes' do
53
55
  block_nodes = []
54
56
  scope =
55
- Rewriter::WithinScope.new(instance, { type: 'block' }, { stop_when_match: false }) do
57
+ Rewriter::WithinScope.new(instance, { type: 'block' }) do
58
+ block_nodes << node
59
+ end
60
+ scope.process
61
+ expect(block_nodes.size).to eq 3
62
+ end
63
+
64
+ it 'matches only 2 block nodes if including_self is false' do
65
+ block_nodes = []
66
+ scope =
67
+ Rewriter::WithinScope.new(instance, { type: 'block' }, { including_self: false }) do
56
68
  block_nodes << node
57
69
  end
58
70
  scope.process
59
71
  expect(block_nodes.size).to eq 2
60
72
  end
61
73
 
62
- it 'matches only one block node if no recursive' do
74
+ it 'matches only one block node if recursive is false' do
63
75
  block_nodes = []
64
76
  scope =
65
- Rewriter::WithinScope.new(instance, { type: 'block' }, { stop_when_match: true }) do
77
+ Rewriter::WithinScope.new(instance, { type: 'block' }, { recursive: false }) do
66
78
  block_nodes << node
67
79
  end
68
80
  scope.process
69
81
  expect(block_nodes.size).to eq 1
70
82
  end
71
83
 
72
- it 'matches only one direct node' do
84
+ it 'matches only one block node if stop_at_first_match is true' do
73
85
  block_nodes = []
74
86
  scope =
75
- Rewriter::WithinScope.new(instance, { type: 'block' }, { direct: true }) do
87
+ Rewriter::WithinScope.new(instance, { type: 'block' }, { stop_at_first_match: true }) do
76
88
  block_nodes << node
77
89
  end
78
90
  scope.process
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
20
  spec.require_paths = ["lib"]
21
21
 
22
- spec.add_runtime_dependency "activesupport"
22
+ spec.add_runtime_dependency "activesupport", "< 7.0.0"
23
23
  spec.add_runtime_dependency "erubis"
24
24
  spec.add_runtime_dependency "node_query"
25
25
  spec.add_runtime_dependency "node_mutation"
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: synvert-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 1.6.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-07-02 00:00:00.000000000 Z
11
+ date: 2022-09-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "<"
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: 7.0.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "<"
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: 7.0.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: erubis
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -106,6 +106,7 @@ files:
106
106
  - ".rspec"
107
107
  - CHANGELOG.md
108
108
  - Gemfile
109
+ - Gemfile.lock
109
110
  - Guardfile
110
111
  - LICENSE.txt
111
112
  - README.md