synvert-core 1.1.0 → 1.2.1
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 +17 -0
- data/lib/synvert/core/array_ext.rb +9 -2
- data/lib/synvert/core/node_ext.rb +14 -2
- data/lib/synvert/core/node_query/compiler/array.rb +1 -1
- data/lib/synvert/core/node_query/compiler/expression.rb +69 -31
- data/lib/synvert/core/node_query/compiler/selector.rb +17 -14
- data/lib/synvert/core/node_query/compiler/string.rb +0 -11
- data/lib/synvert/core/node_query/lexer.rex +12 -1
- data/lib/synvert/core/node_query/lexer.rex.rb +28 -2
- data/lib/synvert/core/node_query/parser.racc.rb +219 -253
- data/lib/synvert/core/node_query/parser.y +9 -14
- data/lib/synvert/core/node_query.rb +7 -7
- data/lib/synvert/core/version.rb +1 -1
- data/spec/synvert/core/node_ext_spec.rb +32 -24
- data/spec/synvert/core/node_query/lexer_spec.rb +56 -4
- data/spec/synvert/core/node_query/parser_spec.rb +90 -25
- metadata +2 -2
@@ -1,31 +1,26 @@
|
|
1
1
|
class Synvert::Core::NodeQuery::Parser
|
2
2
|
options no_result_var
|
3
|
-
token tNODE_TYPE tATTRIBUTE tKEY tIDENTIFIER tIDENTIFIER_VALUE tINDEX tPSEUDO_CLASS
|
3
|
+
token tNODE_TYPE tATTRIBUTE tKEY tIDENTIFIER tIDENTIFIER_VALUE tINDEX tPSEUDO_CLASS
|
4
4
|
tCHILD tSUBSEQUENT_SIBLING tNEXT_SIBLING
|
5
|
-
tOPEN_ATTRIBUTE tCLOSE_ATTRIBUTE tOPEN_DYNAMIC_ATTRIBUTE tCLOSE_DYNAMIC_ATTRIBUTE
|
5
|
+
tOPEN_ATTRIBUTE tCLOSE_ATTRIBUTE tOPEN_DYNAMIC_ATTRIBUTE tCLOSE_DYNAMIC_ATTRIBUTE
|
6
|
+
tOPEN_ARRAY tCLOSE_ARRAY tOPEN_SELECTOR tCLOSE_SELECTOR tOPEN_GOTO_SCOPE tCLOSE_GOTO_SCOPE
|
6
7
|
tEQUAL tNOT_EQUAL tMATCH tNOT_MATCH tGREATER_THAN tGREATER_THAN_OR_EQUAL tLESS_THAN tLESS_THAN_OR_EQUAL tIN tNOT_IN tINCLUDES
|
7
8
|
tARRAY_VALUE tDYNAMIC_ATTRIBUTE tBOOLEAN tFLOAT tINTEGER tNIL tREGEXP tSTRING tSYMBOL
|
8
9
|
rule
|
9
10
|
expression
|
10
|
-
:
|
11
|
-
| selector tSUBSEQUENT_SIBLING expression { Compiler::Expression.new(selector: val[0], rest: val[2], relationship: :subsequent_sibling) }
|
12
|
-
| selector tNEXT_SIBLING expression { Compiler::Expression.new(selector: val[0], rest: val[2], relationship: :next_sibling) }
|
13
|
-
| selector expression { Compiler::Expression.new(selector: val[0], rest: val[1], relationship: :descendant) }
|
14
|
-
| selector { Compiler::Expression.new(selector: val[0]) }
|
15
|
-
| tCHILD expression { Compiler::Expression.new(rest: val[1], relationship: :child) }
|
11
|
+
: tCHILD expression { Compiler::Expression.new(rest: val[1], relationship: :child) }
|
16
12
|
| tSUBSEQUENT_SIBLING expression { Compiler::Expression.new(rest: val[1], relationship: :subsequent_sibling) }
|
17
13
|
| tNEXT_SIBLING expression { Compiler::Expression.new(rest: val[1], relationship: :next_sibling) }
|
14
|
+
| tOPEN_GOTO_SCOPE tIDENTIFIER tCLOSE_GOTO_SCOPE expression { Compiler::Expression.new(goto_scope: val[1], rest: val[3]) }
|
15
|
+
| tPSEUDO_CLASS tOPEN_SELECTOR expression tCLOSE_SELECTOR { Compiler::Expression.new(relationship: val[0].to_sym, rest: val[2]) }
|
16
|
+
| selector expression { Compiler::Expression.new(selector: val[0], rest: val[1]) }
|
17
|
+
| selector { Compiler::Expression.new(selector: val[0]) }
|
18
18
|
|
19
19
|
selector
|
20
20
|
: tNODE_TYPE attribute_list tINDEX { Compiler::Selector.new(node_type: val[0], attribute_list: val[1], index: val[2]) }
|
21
21
|
| tNODE_TYPE tINDEX { Compiler::Selector.new(node_type: val[0], index: val[1]) }
|
22
|
-
| attribute_list tINDEX { Compiler::Selector.new(attribute_list: val[0], index: val[1]) }
|
23
|
-
| tNODE_TYPE attribute_list tPSEUDO_CLASS tOPEN_SELECTOR expression tCLOSE_SELECTOR { Compiler::Selector.new(node_type: val[0], attribute_list: val[1], pseudo_class: val[2], pseudo_expression: val[4]) }
|
24
|
-
| tNODE_TYPE tPSEUDO_CLASS tOPEN_SELECTOR expression tCLOSE_SELECTOR { Compiler::Selector.new(node_type: val[0], pseudo_class: val[1], pseudo_expression: val[3]) }
|
25
|
-
| attribute_list tPSEUDO_CLASS tOPEN_SELECTOR expression tCLOSE_SELECTOR { Compiler::Selector.new(attribute_list: val[0], pseudo_class: val[1], pseudo_expression: val[3]) }
|
26
22
|
| tNODE_TYPE attribute_list { Compiler::Selector.new(node_type: val[0], attribute_list: val[1]) }
|
27
23
|
| tNODE_TYPE { Compiler::Selector.new(node_type: val[0]) }
|
28
|
-
| attribute_list { Compiler::Selector.new(attribute_list: val[0]) }
|
29
24
|
;
|
30
25
|
|
31
26
|
attribute_list
|
@@ -53,7 +48,7 @@ rule
|
|
53
48
|
| tKEY tIN tOPEN_ARRAY array_value tCLOSE_ARRAY { Compiler::Attribute.new(key: val[0], value: val[3], operator: :in) }
|
54
49
|
|
55
50
|
array_value
|
56
|
-
: value
|
51
|
+
: value array_value { Compiler::Array.new(value: val[0], rest: val[1]) }
|
57
52
|
| value { Compiler::Array.new(value: val[0]) }
|
58
53
|
|
59
54
|
value
|
@@ -5,10 +5,10 @@
|
|
5
5
|
# It supports the following selectors:
|
6
6
|
#
|
7
7
|
# * AST node type: +.class+, +.send+
|
8
|
-
# * attribute value:
|
9
|
-
# * attribute regex: <code
|
10
|
-
# * attribute conditions:
|
11
|
-
# * nested attribute:
|
8
|
+
# * attribute value: +.send[receiver = nil]+, +.send[message = create]+
|
9
|
+
# * attribute regex: <code>.send[key=~/\A:([^'"]+)\z/]</code>, <code>.send[key!~/\A:([^'"]+)\z/]</code>
|
10
|
+
# * attribute conditions: +.send[message != nil]+, +.send[value > 1]+, +.send[value >= 1]+, +.send[value < 1]+, +.send[value <= 1]+
|
11
|
+
# * nested attribute: +.send[caller.message = map]+, +.send[arguments.size = 2]+
|
12
12
|
# * first or last child: +.def:first-child+, +.send:last-child+
|
13
13
|
# * nth-child or nth-last-child: +.def:nth-child(2)+, +.send:nth-last-child(2)+
|
14
14
|
# * descendant: +.class .send+
|
@@ -21,9 +21,9 @@
|
|
21
21
|
#
|
22
22
|
# * not_has: +.class:not_has(.def)+, it's same as +:not(:has())+ in css, just to make implementation easy.
|
23
23
|
# * nested selector: +.send[arguments = [size = 2][first = .sym][last = .hash]]+
|
24
|
-
# * array value: +.send[arguments = (a
|
25
|
-
# * IN operator: +.send[message IN (try
|
26
|
-
# * NOT IN operator: +.send[message NOT IN (create
|
24
|
+
# * array value: +.send[arguments = (a b)]+
|
25
|
+
# * IN operator: +.send[message IN (try try!)]+
|
26
|
+
# * NOT IN operator: +.send[message NOT IN (create build)]+
|
27
27
|
# * INCLUDES operator: +.send[arguments INCLUDES &block]+
|
28
28
|
# * dynamic attribute value: +.hash > .pair[key={{value}}]+
|
29
29
|
#
|
data/lib/synvert/core/version.rb
CHANGED
@@ -1033,33 +1033,41 @@ describe Parser::AST::Node do
|
|
1033
1033
|
node = parse(<<~EOS)
|
1034
1034
|
class Synvert
|
1035
1035
|
def foobar(foo, bar)
|
1036
|
-
foo
|
1036
|
+
{ foo => bar }
|
1037
1037
|
end
|
1038
1038
|
end
|
1039
1039
|
EOS
|
1040
|
-
expect(node.to_hash).to eq(
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
1059
|
-
|
1060
|
-
|
1061
|
-
|
1062
|
-
|
1040
|
+
expect(node.to_hash).to eq(
|
1041
|
+
{
|
1042
|
+
type: :class,
|
1043
|
+
parent_class: nil,
|
1044
|
+
name: {
|
1045
|
+
type: :const,
|
1046
|
+
parent_const: nil,
|
1047
|
+
name: :Synvert
|
1048
|
+
},
|
1049
|
+
body: [
|
1050
|
+
{
|
1051
|
+
type: :def,
|
1052
|
+
name: :foobar,
|
1053
|
+
arguments: [
|
1054
|
+
{ type: :arg, name: :foo },
|
1055
|
+
{ type: :arg, name: :bar }
|
1056
|
+
],
|
1057
|
+
body: [
|
1058
|
+
{
|
1059
|
+
type: :hash,
|
1060
|
+
pairs: {
|
1061
|
+
type: :pair,
|
1062
|
+
key: { type: :lvar, name: :foo },
|
1063
|
+
value: { type: :lvar, name: :bar }
|
1064
|
+
}
|
1065
|
+
}
|
1066
|
+
]
|
1067
|
+
}
|
1068
|
+
]
|
1069
|
+
}
|
1070
|
+
)
|
1063
1071
|
end
|
1064
1072
|
end
|
1065
1073
|
end
|
@@ -200,6 +200,45 @@ module Synvert::Core::NodeQuery
|
|
200
200
|
assert_tokens source, expected_tokens
|
201
201
|
end
|
202
202
|
|
203
|
+
it 'matches :[] message' do
|
204
|
+
source = ".send[message=[]]"
|
205
|
+
expected_tokens = [
|
206
|
+
[:tNODE_TYPE, "send"],
|
207
|
+
[:tOPEN_ATTRIBUTE, "["],
|
208
|
+
[:tKEY, "message"],
|
209
|
+
[:tEQUAL, "="],
|
210
|
+
[:tIDENTIFIER_VALUE, "[]"],
|
211
|
+
[:tCLOSE_ATTRIBUTE, "]"]
|
212
|
+
]
|
213
|
+
assert_tokens source, expected_tokens
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'matches :[] message' do
|
217
|
+
source = ".send[message=:[]=]"
|
218
|
+
expected_tokens = [
|
219
|
+
[:tNODE_TYPE, "send"],
|
220
|
+
[:tOPEN_ATTRIBUTE, "["],
|
221
|
+
[:tKEY, "message"],
|
222
|
+
[:tEQUAL, "="],
|
223
|
+
[:tSYMBOL, :[]=],
|
224
|
+
[:tCLOSE_ATTRIBUTE, "]"]
|
225
|
+
]
|
226
|
+
assert_tokens source, expected_tokens
|
227
|
+
end
|
228
|
+
|
229
|
+
it 'matches nil?' do
|
230
|
+
source = ".send[message=nil?]"
|
231
|
+
expected_tokens = [
|
232
|
+
[:tNODE_TYPE, "send"],
|
233
|
+
[:tOPEN_ATTRIBUTE, "["],
|
234
|
+
[:tKEY, "message"],
|
235
|
+
[:tEQUAL, "="],
|
236
|
+
[:tIDENTIFIER_VALUE, "nil?"],
|
237
|
+
[:tCLOSE_ATTRIBUTE, "]"]
|
238
|
+
]
|
239
|
+
assert_tokens source, expected_tokens
|
240
|
+
end
|
241
|
+
|
203
242
|
it 'matches attribute value' do
|
204
243
|
source = '.pair[key={{value}}]'
|
205
244
|
expected_tokens = [
|
@@ -403,7 +442,7 @@ module Synvert::Core::NodeQuery
|
|
403
442
|
end
|
404
443
|
|
405
444
|
it 'matches IN' do
|
406
|
-
source = '.send[message IN (create
|
445
|
+
source = '.send[message IN (create build)]'
|
407
446
|
expected_tokens = [
|
408
447
|
[:tNODE_TYPE, "send"],
|
409
448
|
[:tOPEN_ATTRIBUTE, "["],
|
@@ -411,7 +450,6 @@ module Synvert::Core::NodeQuery
|
|
411
450
|
[:tIN, "IN"],
|
412
451
|
[:tOPEN_ARRAY, "("],
|
413
452
|
[:tIDENTIFIER_VALUE, "create"],
|
414
|
-
[:tCOMMA, ","],
|
415
453
|
[:tIDENTIFIER_VALUE, "build"],
|
416
454
|
[:tCLOSE_ARRAY, ")"],
|
417
455
|
[:tCLOSE_ATTRIBUTE, "]"]
|
@@ -420,7 +458,7 @@ module Synvert::Core::NodeQuery
|
|
420
458
|
end
|
421
459
|
|
422
460
|
it 'matches NOT IN' do
|
423
|
-
source = '.send[message NOT IN (create
|
461
|
+
source = '.send[message NOT IN (create build)]'
|
424
462
|
expected_tokens = [
|
425
463
|
[:tNODE_TYPE, "send"],
|
426
464
|
[:tOPEN_ATTRIBUTE, "["],
|
@@ -428,7 +466,6 @@ module Synvert::Core::NodeQuery
|
|
428
466
|
[:tNOT_IN, "NOT IN"],
|
429
467
|
[:tOPEN_ARRAY, "("],
|
430
468
|
[:tIDENTIFIER_VALUE, "create"],
|
431
|
-
[:tCOMMA, ","],
|
432
469
|
[:tIDENTIFIER_VALUE, "build"],
|
433
470
|
[:tCLOSE_ARRAY, ")"],
|
434
471
|
[:tCLOSE_ATTRIBUTE, "]"]
|
@@ -584,5 +621,20 @@ module Synvert::Core::NodeQuery
|
|
584
621
|
assert_tokens source, expected_tokens
|
585
622
|
end
|
586
623
|
end
|
624
|
+
|
625
|
+
context 'goto_scope' do
|
626
|
+
it 'matches' do
|
627
|
+
source = '.block <body> > .def'
|
628
|
+
expected_tokens = [
|
629
|
+
[:tNODE_TYPE, "block"],
|
630
|
+
[:tOPEN_GOTO_SCOPE, "<"],
|
631
|
+
[:tIDENTIFIER, "body"],
|
632
|
+
[:tCLOSE_GOTO_SCOPE, ">"],
|
633
|
+
[:tCHILD, ">"],
|
634
|
+
[:tNODE_TYPE, "def"]
|
635
|
+
]
|
636
|
+
assert_tokens source, expected_tokens
|
637
|
+
end
|
638
|
+
end
|
587
639
|
end
|
588
640
|
end
|
@@ -28,6 +28,11 @@ module Synvert::Core::NodeQuery
|
|
28
28
|
assert_parser(source)
|
29
29
|
end
|
30
30
|
|
31
|
+
it 'parses scope' do
|
32
|
+
source = '.block <body> > .send'
|
33
|
+
assert_parser(source)
|
34
|
+
end
|
35
|
+
|
31
36
|
it 'parses :first-child' do
|
32
37
|
source = '.class .def:first-child'
|
33
38
|
assert_parser(source)
|
@@ -49,12 +54,17 @@ module Synvert::Core::NodeQuery
|
|
49
54
|
end
|
50
55
|
|
51
56
|
it 'parses :has selector' do
|
52
|
-
source = '.class:has(> .def)'
|
57
|
+
source = '.class :has(> .def)'
|
53
58
|
assert_parser(source)
|
54
59
|
end
|
55
60
|
|
56
61
|
it 'parses :not_has selector' do
|
57
|
-
source = '.class:not_has(> .def)'
|
62
|
+
source = '.class :not_has(> .def)'
|
63
|
+
assert_parser(source)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'parses root :has selector' do
|
67
|
+
source = ':has(.def)'
|
58
68
|
assert_parser(source)
|
59
69
|
end
|
60
70
|
|
@@ -99,12 +109,12 @@ module Synvert::Core::NodeQuery
|
|
99
109
|
end
|
100
110
|
|
101
111
|
it 'parses in operator' do
|
102
|
-
source = '.def[name in (foo
|
112
|
+
source = '.def[name in (foo bar)]'
|
103
113
|
assert_parser(source)
|
104
114
|
end
|
105
115
|
|
106
116
|
it 'parses not_in operator' do
|
107
|
-
source = '.def[name not in (foo
|
117
|
+
source = '.def[name not in (foo bar)]'
|
108
118
|
assert_parser(source)
|
109
119
|
end
|
110
120
|
|
@@ -118,6 +128,16 @@ module Synvert::Core::NodeQuery
|
|
118
128
|
assert_parser(source)
|
119
129
|
end
|
120
130
|
|
131
|
+
it 'parses []=' do
|
132
|
+
source = '.send[message=[]=]'
|
133
|
+
assert_parser(source)
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'parses :[]' do
|
137
|
+
source = '.send[message=:[]]'
|
138
|
+
assert_parser(source)
|
139
|
+
end
|
140
|
+
|
121
141
|
describe '#query_nodes' do
|
122
142
|
let(:node) {
|
123
143
|
parse(<<~EOS)
|
@@ -132,13 +152,22 @@ module Synvert::Core::NodeQuery
|
|
132
152
|
|
133
153
|
def foobar(a, b)
|
134
154
|
{ a: a, b: b }
|
135
|
-
foo.merge(bar)
|
136
155
|
arr[index]
|
156
|
+
arr[index] = value
|
157
|
+
nil?
|
158
|
+
call('')
|
137
159
|
end
|
138
160
|
end
|
139
161
|
EOS
|
140
162
|
}
|
141
163
|
|
164
|
+
let(:test_node) {
|
165
|
+
parse(<<~EOS)
|
166
|
+
RSpec.describe Synvert do
|
167
|
+
end
|
168
|
+
EOS
|
169
|
+
}
|
170
|
+
|
142
171
|
it 'matches class node' do
|
143
172
|
expression = parser.parse('.class[name=Synvert]')
|
144
173
|
expect(expression.query_nodes(node)).to eq [node]
|
@@ -180,12 +209,12 @@ module Synvert::Core::NodeQuery
|
|
180
209
|
end
|
181
210
|
|
182
211
|
it 'matches in' do
|
183
|
-
expression = parser.parse('.def[name IN (foo
|
212
|
+
expression = parser.parse('.def[name IN (foo bar)]')
|
184
213
|
expect(expression.query_nodes(node)).to eq [node.body.first, node.body.second]
|
185
214
|
end
|
186
215
|
|
187
216
|
it 'matches not in' do
|
188
|
-
expression = parser.parse('.def[name NOT IN (foo
|
217
|
+
expression = parser.parse('.def[name NOT IN (foo bar)]')
|
189
218
|
expect(expression.query_nodes(node)).to eq [node.body.last]
|
190
219
|
end
|
191
220
|
|
@@ -195,34 +224,34 @@ module Synvert::Core::NodeQuery
|
|
195
224
|
end
|
196
225
|
|
197
226
|
it 'matches equal array' do
|
198
|
-
expression = parser.parse('.def[arguments=(a
|
227
|
+
expression = parser.parse('.def[arguments=(a b)]')
|
199
228
|
expect(expression.query_nodes(node)).to eq [node.body.last]
|
200
229
|
|
201
|
-
expression = parser.parse('.def[arguments=(b
|
230
|
+
expression = parser.parse('.def[arguments=(b a)]')
|
202
231
|
expect(expression.query_nodes(node)).to eq []
|
203
232
|
end
|
204
233
|
|
205
234
|
it 'matches not equal array' do
|
206
|
-
expression = parser.parse('.def[arguments!=(a
|
235
|
+
expression = parser.parse('.def[arguments!=(a b)]')
|
207
236
|
expect(expression.query_nodes(node)).to eq [node.body.first, node.body.second]
|
208
237
|
|
209
|
-
expression = parser.parse('.def[arguments!=(b
|
238
|
+
expression = parser.parse('.def[arguments!=(b a)]')
|
210
239
|
expect(expression.query_nodes(node)).to eq [node.body.first, node.body.second, node.body.last]
|
211
240
|
end
|
212
241
|
|
213
242
|
it 'matches descendant node' do
|
214
243
|
expression = parser.parse('.class .send[message=:create]')
|
215
|
-
expect(expression.query_nodes(node)).to eq [node.body.first.
|
244
|
+
expect(expression.query_nodes(node)).to eq [node.body.first.body.last, node.body.second.body.last]
|
216
245
|
end
|
217
246
|
|
218
247
|
it 'matches three level descendant node' do
|
219
248
|
expression = parser.parse('.class .def .send[message=:create]')
|
220
|
-
expect(expression.query_nodes(node)).to eq [node.body.first.
|
249
|
+
expect(expression.query_nodes(node)).to eq [node.body.first.body.last, node.body.second.body.last]
|
221
250
|
end
|
222
251
|
|
223
252
|
it 'matches child node' do
|
224
253
|
expression = parser.parse('.def > .send[message=:create]')
|
225
|
-
expect(expression.query_nodes(node)).to eq [node.body.first.
|
254
|
+
expect(expression.query_nodes(node)).to eq [node.body.first.body.last, node.body.second.body.last]
|
226
255
|
end
|
227
256
|
|
228
257
|
it 'matches next sibling node' do
|
@@ -235,6 +264,19 @@ module Synvert::Core::NodeQuery
|
|
235
264
|
expect(expression.query_nodes(node)).to eq [node.body.last]
|
236
265
|
end
|
237
266
|
|
267
|
+
it 'matches goto scope' do
|
268
|
+
expression = parser.parse('.def <body> > .send[message=:create]')
|
269
|
+
expect(expression.query_nodes(node)).to eq [node.body.first.body.last, node.body.second.body.last]
|
270
|
+
|
271
|
+
expression = parser.parse('.def <body> .send[message=:create]')
|
272
|
+
expect(expression.query_nodes(node)).to eq [node.body.first.body.last, node.body.second.body.last]
|
273
|
+
end
|
274
|
+
|
275
|
+
it 'matches multiple goto scope' do
|
276
|
+
expression = parser.parse('.block <caller.arguments> .const[name=Synvert]')
|
277
|
+
expect(expression.query_nodes(test_node)).to eq [test_node.caller.arguments.first]
|
278
|
+
end
|
279
|
+
|
238
280
|
it 'matches has selector' do
|
239
281
|
expression = parser.parse('.def:has(> .send[receiver=FactoryBot])')
|
240
282
|
expect(expression.query_nodes(node)).to eq [node.body.first, node.body.second]
|
@@ -245,18 +287,31 @@ module Synvert::Core::NodeQuery
|
|
245
287
|
expect(expression.query_nodes(node)).to eq [node.body.last]
|
246
288
|
end
|
247
289
|
|
290
|
+
it 'matches root has selector' do
|
291
|
+
expression = parser.parse(':has(.def[name=foobar])')
|
292
|
+
expect(expression.query_nodes(node)).to eq [node]
|
293
|
+
end
|
294
|
+
|
248
295
|
it 'matches arguments.size' do
|
249
|
-
expression = parser.parse('.send[arguments.size=2]')
|
250
|
-
expect(expression.query_nodes(node)).to eq [
|
251
|
-
|
296
|
+
expression = parser.parse('.def .send[arguments.size=2]')
|
297
|
+
expect(expression.query_nodes(node)).to eq [
|
298
|
+
node.body.first.body.last,
|
299
|
+
node.body.second.body.last,
|
300
|
+
node.body.third.body.third
|
301
|
+
]
|
302
|
+
expression = parser.parse('.def .send[arguments.size>2]')
|
252
303
|
expect(expression.query_nodes(node)).to eq []
|
253
|
-
expression = parser.parse('.send[arguments.size>=2]')
|
254
|
-
expect(expression.query_nodes(node)).to eq [
|
304
|
+
expression = parser.parse('.def .send[arguments.size>=2]')
|
305
|
+
expect(expression.query_nodes(node)).to eq [
|
306
|
+
node.body.first.body.last,
|
307
|
+
node.body.second.body.last,
|
308
|
+
node.body.third.body.third
|
309
|
+
]
|
255
310
|
end
|
256
311
|
|
257
312
|
it 'matches arguments' do
|
258
|
-
expression = parser.parse('.send[arguments
|
259
|
-
expect(expression.query_nodes(node)).to eq [node.body.first.
|
313
|
+
expression = parser.parse('.send[arguments.size=2][arguments.first=.sym][arguments.last=.hash]')
|
314
|
+
expect(expression.query_nodes(node)).to eq [node.body.first.body.last, node.body.second.body.last]
|
260
315
|
end
|
261
316
|
|
262
317
|
it 'matches regexp value' do
|
@@ -271,15 +326,25 @@ module Synvert::Core::NodeQuery
|
|
271
326
|
expect(expression.query_nodes(node)).to eq node.body.last.body.first.children
|
272
327
|
end
|
273
328
|
|
274
|
-
it 'matches
|
275
|
-
expression = parser.parse('.send[
|
329
|
+
it 'matches []' do
|
330
|
+
expression = parser.parse('.send[message=[]]')
|
276
331
|
expect(expression.query_nodes(node)).to eq [node.body.last.body.second]
|
277
332
|
end
|
278
333
|
|
279
|
-
it 'matches []' do
|
280
|
-
expression = parser.parse('.send[message
|
334
|
+
it 'matches []=' do
|
335
|
+
expression = parser.parse('.send[message=:[]=]')
|
281
336
|
expect(expression.query_nodes(node)).to eq [node.body.last.body.third]
|
282
337
|
end
|
338
|
+
|
339
|
+
it 'matches nil and nil?' do
|
340
|
+
expression = parser.parse('.send[receiver=nil][message=nil?]')
|
341
|
+
expect(expression.query_nodes(node)).to eq [node.body.last.body.fourth]
|
342
|
+
end
|
343
|
+
|
344
|
+
it 'matches empty string' do
|
345
|
+
expression = parser.parse('.send[message=call][arguments.first=""]')
|
346
|
+
expect(expression.query_nodes(node)).to eq [node.body.last.body.last]
|
347
|
+
end
|
283
348
|
end
|
284
349
|
end
|
285
350
|
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.1
|
4
|
+
version: 1.2.1
|
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
|
+
date: 2022-05-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|