synvert-core 1.1.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 tCOMMA
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 tOPEN_ARRAY tCLOSE_ARRAY tOPEN_SELECTOR tCLOSE_SELECTOR
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
- : selector tCHILD expression { Compiler::Expression.new(selector: val[0], rest: val[2], relationship: :child) }
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 tCOMMA array_value { Compiler::Array.new(value: val[0], rest: val[2]) }
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: +[receiver = nil]+, +[message = create]+
9
- # * attribute regex: <code>[key=~/\A:([^'"]+)\z/]</code>, <code>[key!~/\A:([^'"]+)\z/]</code>
10
- # * attribute conditions: +[message != nil]+, +[value > 1]+, +[value >= 1]+, +[value < 1]+, +[value <= 1]+
11
- # * nested attribute: +[caller.message = map]+, +[arguments.size = 2]+
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, b)]+
25
- # * IN operator: +.send[message IN (try, try!)]+
26
- # * NOT IN operator: +.send[message NOT IN (create, build)]+
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
  #
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Synvert
4
4
  module Core
5
- VERSION = '1.1.0'
5
+ VERSION = '1.2.1'
6
6
  end
7
7
  end
@@ -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 + bar
1036
+ { foo => bar }
1037
1037
  end
1038
1038
  end
1039
1039
  EOS
1040
- expect(node.to_hash).to eq({
1041
- type: :class,
1042
- parent_class: nil,
1043
- name: {
1044
- type: :const,
1045
- parent_const: nil,
1046
- name: :Synvert
1047
- },
1048
- body: [{
1049
- type: :def,
1050
- name: :foobar,
1051
- arguments: [
1052
- { type: :arg, name: :foo},
1053
- { type: :arg, name: :bar}
1054
- ],
1055
- body: [{
1056
- type: :send,
1057
- receiver: { name: :foo, type: :lvar },
1058
- message: :+,
1059
- arguments: [{ name: :bar, type: :lvar }]
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, build)]'
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, build)]'
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, bar)]'
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, bar)]'
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, bar)]')
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, bar)]')
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, b)]')
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, a)]')
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, b)]')
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, a)]')
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.children.last, node.body.second.children.last]
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.children.last, node.body.second.children.last]
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.children.last, node.body.second.children.last]
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 [node.body.first.children.last, node.body.second.children.last]
251
- expression = parser.parse('.send[arguments.size>2]')
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 [node.body.first.children.last, node.body.second.children.last]
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=[size=2][first=.sym][last=.hash]]')
259
- expect(expression.query_nodes(node)).to eq [node.body.first.children.last, node.body.second.children.last]
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 identifier' do
275
- expression = parser.parse('.send[receiver=foo][message=merge]')
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.0
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-04-26 00:00:00.000000000 Z
11
+ date: 2022-05-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport