sportdb-quick 0.3.1 → 0.5.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: d24c209b9b7c40d0f042062a41edf15ebc99a9d6536b06456eb09b365ddc3d11
4
- data.tar.gz: d6d4c961906539774027860d4c29a306186f5fba96b049a3a7b9720a9c87498d
3
+ metadata.gz: d352420645cf51612b5f1c1185f955ac0766d6bb26d84cae1a9e2adc16b2bd1e
4
+ data.tar.gz: fa83e99ca9c5b86ad8f9a101513d537e52338d03e181809579ef06ad03788cff
5
5
  SHA512:
6
- metadata.gz: bde8f1b34c6be7c3c68b5c051dcb21c257d721719ea1e1c648b911c504535832c885395492427ca985de7b2b35e2c2b92590cd5e41b5f5f6c7344dcee8e3904a
7
- data.tar.gz: a46daab3b1d77e498badaca558c237ad43e81c129641efa88450eabaa05d4b71499b6f2d7af0101a46b976e1ab6b0a152a9b3a6c3d0183faae53b56648814e51
6
+ metadata.gz: 3f962bf9735b43bf53aa733c7543679f00daa08582862b4c4624fdc96556d148a2bcb2ea7a16f7a9637bae908cd71591bbc6f0b2fd7b7a0124d3106712a9094b
7
+ data.tar.gz: 818778f17464a71e2e8f7997661a00d4fd0844a5ebffdb22eb7800590f55bf7a7ccbd49aefe7fdd2d325eef84cb4669cdfb1287b5f819d5e5d6aae438c7ae759
data/CHANGELOG.md CHANGED
@@ -1,4 +1,4 @@
1
- ### 0.3.1
1
+ ### 0.5.0
2
2
  ### 0.0.1 / 2024-08-27
3
3
 
4
4
  * Everything is new. First release.
data/Rakefile CHANGED
@@ -21,7 +21,7 @@ Hoe.spec 'sportdb-quick' do
21
21
  self.licenses = ['Public Domain']
22
22
 
23
23
  self.extra_deps = [
24
- ['sportdb-parser', '>= 0.4.0'],
24
+ ['sportdb-parser', '>= 0.5.0'],
25
25
  ['sportdb-structs', '>= 0.5.0'],
26
26
  ['logutils', '>= 0.6.1'],
27
27
  ]
@@ -88,8 +88,6 @@ class MatchParser ## simple match parser for team match schedules
88
88
  @last_round = nil
89
89
  @last_group = nil
90
90
 
91
- ## last_goals - rename to (longer) @last_team_goals or such - why? why not?
92
- @last_goals = 1 ## toggle between 1|2 - hacky (quick & dirty) support for multi-line goals, fix soon!
93
91
 
94
92
  @teams = Hash.new(0) ## track counts (only) for now for (interal) team stats - why? why not?
95
93
  @rounds = {}
@@ -99,12 +97,12 @@ class MatchParser ## simple match parser for team match schedules
99
97
  @warns = [] ## track list of warnings (unmatched lines) too - why? why not?
100
98
 
101
99
 
102
-
103
- @parser = Parser.new
104
100
  @tree = []
105
101
 
106
102
  attrib_found = false
107
103
 
104
+
105
+ lines = []
108
106
  @lines.each_with_index do |line,i|
109
107
 
110
108
  if debug?
@@ -134,6 +132,9 @@ class MatchParser ## simple match parser for team match schedules
134
132
  next
135
133
  end
136
134
 
135
+ lines << line
136
+
137
+ =begin
137
138
  t, error_messages = @parser.parse_with_errors( line )
138
139
 
139
140
 
@@ -151,71 +152,47 @@ class MatchParser ## simple match parser for team match schedules
151
152
  pp t if debug?
152
153
 
153
154
  @tree << t
155
+ =end
154
156
  end # each lines
155
157
 
158
+ txt = lines.join( "\n") + "\n"
159
+ parser = RaccMatchParser.new( txt ) ## use own parser instance (not shared) - why? why not?
160
+ @tree = parser.parse
161
+ ## pp @tree
162
+
156
163
  ## pp @tree
157
164
 
158
165
  ## report parse errors here - why? why not?
159
166
 
160
167
 
161
168
 
162
- @tree.each do |nodes|
169
+ @tree.each do |node|
163
170
 
164
- node_type = nodes[0][0] ## get node type of first/head node
165
-
166
- if node_type == :round_def
171
+ if node.is_a? RaccMatchParser::RoundDef
167
172
  ## todo/fix: add round definition (w begin n end date)
168
173
  ## todo: do not patch rounds with definition (already assume begin/end date is good)
169
174
  ## -- how to deal with matches that get rescheduled/postponed?
170
- parse_round_def( nodes )
171
- elsif node_type == :group_def ## NB: group goes after round (round may contain group marker too)
175
+ on_round_def( node )
176
+ elsif node.is_a? RaccMatchParser::GroupDef ## NB: group goes after round (round may contain group marker too)
172
177
  ### todo: add pipe (|) marker (required)
173
- parse_group_def( nodes )
174
-
175
- elsif node_type == :player ||
176
- node_type == :none # e.g [[:none], [:";"], [:player, "Xhaka"],...]
177
- ## note - for now goals line MUST start with player!!
178
- parse_goals( nodes )
179
- else
180
- ## try to be liberal/flexible
181
- ## eat-up nodes as we go
182
- ## assume match with group / round header
183
- ## etc. on its own line or not
184
-
185
- ## preprocess possible before match nodes
186
-
187
- while !nodes.empty? do
188
- node_type = nodes[0][0] ## get node type of first/head node
189
- if node_type == :round
190
- node = nodes.shift ## eat-up
191
- parse_round_header( node )
192
- elsif node_type == :leg
193
- node = nodes.shift ## eat-up
194
- ## ignore (round) leg for now - add later leg - 1|2|3 etc!!!
195
- ## needs to get added to db/schema too!!!!
196
- ## add @last_leg = nil or 1|2|3 etc.
197
- elsif node_type == :group
198
- ## -- lets you set group e.g. Group A etc.
199
- node = nodes.shift ## eat-up
200
- parse_group_header( node )
201
- elsif node_type == :date
202
- node = nodes.shift ## eat-up
203
- parse_date_header( node )
204
- ## add time here too - why? why not?
205
- ## add skip comma separator here too - why? why not?
206
- ## "slurp-up" in upstream parser?
207
- ## e.g. round, group or group, round ?
208
- else
209
- break
210
- end
211
- end
212
- next if nodes.empty?
213
-
214
- ## rename to try_parse_match - why? why not?
215
- parse_match( nodes )
178
+ on_group_def( node )
179
+ elsif node.is_a? RaccMatchParser::GroupHeader
180
+ on_group_header( node )
181
+ elsif node.is_a? RaccMatchParser::RoundHeader
182
+ on_round_header( node )
183
+ elsif node.is_a? RaccMatchParser::DateHeader
184
+ on_date_header( node )
185
+ elsif node.is_a? RaccMatchParser::MatchLine
186
+ on_match_line( node )
187
+ elsif node.is_a? RaccMatchParser::GoalLine
188
+ on_goal_line( node )
189
+ else
190
+ ## report error
191
+ puts "!! ERROR - unknown node (parse tree type)"
192
+ pp node
193
+ exit 1
216
194
  end
217
-
218
- end # tree.each
195
+ end # tree.each
219
196
 
220
197
  ## note - team keys are names and values are "internal" stats!!
221
198
  ## and NOT team/club/nat_team structs!!
@@ -224,8 +201,8 @@ class MatchParser ## simple match parser for team match schedules
224
201
 
225
202
 
226
203
 
227
- def parse_group_header( node )
228
- logger.debug "parsing group header: >#{node}<"
204
+ def on_group_header( node )
205
+ logger.debug "on group header: >#{node}<"
229
206
 
230
207
  # note: group header resets (last) round (allows, for example):
231
208
  # e.g.
@@ -235,7 +212,7 @@ class MatchParser ## simple match parser for team match schedules
235
212
  # team1 team2 - match (will get new auto-matchday! not last round)
236
213
  @last_round = nil
237
214
 
238
- name = node[1]
215
+ name = node.name
239
216
 
240
217
  group = @groups[ name ]
241
218
  if group.nil?
@@ -248,8 +225,8 @@ class MatchParser ## simple match parser for team match schedules
248
225
  end
249
226
 
250
227
 
251
- def parse_group_def( nodes )
252
- logger.debug "parsing group def: >#{nodes}<"
228
+ def on_group_def( node )
229
+ logger.debug "on group def: >#{node}<"
253
230
 
254
231
  ## e.g
255
232
  ## [:group_def, "Group A"],
@@ -258,26 +235,15 @@ class MatchParser ## simple match parser for team match schedules
258
235
  ## [:team, "Hungary"],
259
236
  ## [:team, "Switzerland"]
260
237
 
261
- node = nodes[0]
262
- name = node[1] ## group name
263
-
264
- teams = nodes[1..-1].map do |node|
265
- if node[0] == :team
266
- team = node[1]
267
- @teams[ team ] += 1
268
- team
269
- else
270
- puts "!! PARSE ERROR - only teams expected in group def; got:"
271
- pp nodes
272
- exit 1
273
- end
274
- end
275
-
238
+ node.teams.each do |team|
239
+ @teams[ team ] += 1
240
+ end
241
+
276
242
  ## todo/check/fix: add back group key - why? why not?
277
- group = Import::Group.new( name: name,
278
- teams: teams )
243
+ group = Import::Group.new( name: node.name,
244
+ teams: node.teams )
279
245
 
280
- @groups[ name ] = group
246
+ @groups[ node.name ] = group
281
247
  end
282
248
 
283
249
 
@@ -307,37 +273,35 @@ class MatchParser ## simple match parser for team match schedules
307
273
  Date.new( y,m,d ) ## y,m,d
308
274
  end
309
275
 
310
- def parse_round_def( nodes )
311
- logger.debug "parsing round def: >#{nodes}<"
276
+
277
+ def on_round_def( node )
278
+ logger.debug "on round def: >#{node}<"
312
279
 
313
280
  ## e.g. [[:round_def, "Matchday 1"], [:duration, "Fri Jun/14 - Tue Jun/18"]]
314
281
  ## [[:round_def, "Matchday 2"], [:duration, "Wed Jun/19 - Sat Jun/22"]]
315
282
  ## [[:round_def, "Matchday 3"], [:duration, "Sun Jun/23 - Wed Jun/26"]]
316
283
 
317
- node = nodes[0]
318
- name = node[1]
284
+ name = node.name
319
285
  # NB: use extracted round name for knockout check
320
286
  # knockout_flag = is_knockout_round?( name )
321
287
 
322
- node = nodes[1]
323
- node_type = node[0]
324
- if node_type == :date
325
- start_date = end_date = _build_date( m: node[2][:m],
326
- d: node[2][:d],
327
- y: node[2][:y],
288
+ if node.date
289
+ start_date = end_date = _build_date( m: node.date[:m],
290
+ d: node.date[:d],
291
+ y: node.date[:y],
328
292
  start: @start)
329
- elsif node_type == :duration
330
- start_date = _build_date( m: node[2][:start][:m],
331
- d: node[2][:start][:d],
332
- y: node[2][:start][:y],
293
+ elsif node.duration
294
+ start_date = _build_date( m: node.duration[:start][:m],
295
+ d: node.duration[:start][:d],
296
+ y: node.duration[:start][:y],
333
297
  start: @start)
334
- end_date = _build_date( m: node[2][:end][:m],
335
- d: node[2][:end][:d],
336
- y: node[2][:end][:y],
298
+ end_date = _build_date( m: node.duration[:end][:m],
299
+ d: node.duration[:end][:d],
300
+ y: node.duration[:end][:y],
337
301
  start: @start)
338
302
  else
339
303
  puts "!! PARSE ERROR - expected date or duration for round def; got:"
340
- pp nodes
304
+ pp node
341
305
  exit 1
342
306
  end
343
307
 
@@ -375,10 +339,11 @@ class MatchParser ## simple match parser for team match schedules
375
339
  end
376
340
 
377
341
 
378
- def parse_round_header( node )
379
- logger.debug "parsing round header: >#{node}<"
342
+ def on_round_header( node )
343
+ logger.debug "on round header: >#{node}<"
380
344
 
381
- name = node[1]
345
+ name = node.names[0] ## ignore more names for now
346
+ ## fix later - fix more names!!!
382
347
 
383
348
  # name = name.sub( ROUND_EXTRA_WORDS_RE, '' )
384
349
  # name = name.strip
@@ -399,12 +364,12 @@ class MatchParser ## simple match parser for team match schedules
399
364
  ## reset date/time e.g. @last_date = nil !!!!
400
365
  end
401
366
 
402
- def parse_date_header( node )
367
+ def on_date_header( node )
403
368
  logger.debug( "date header: >#{node}<")
404
369
 
405
- date = _build_date( m: node[2][:m],
406
- d: node[2][:d],
407
- y: node[2][:y],
370
+ date = _build_date( m: node.date[:m],
371
+ d: node.date[:d],
372
+ y: node.date[:y],
408
373
  start: @start )
409
374
 
410
375
  logger.debug( " date: #{date} with start: #{@start}")
@@ -431,93 +396,17 @@ class MatchParser ## simple match parser for team match schedules
431
396
  =end
432
397
  end
433
398
 
434
- def parse_minutes( nodes )
435
- ## parse goals by player
436
- ## may have multiple minutes!!
437
- goals = []
438
-
439
- node = nodes.shift ## get player
440
- name = node[1]
441
-
442
- loop do
443
- goal = {}
444
- goal[:name] = name
445
-
446
- node_type = nodes[0][0]
447
- if node_type != :minute
448
- puts "!! PARSE ERROR - minute expected to follow player (in goal); got #{node_type}:"
449
- pp nodes
450
- exit 1
451
- end
452
-
453
- node = nodes.shift
454
- goal[:minute] = node[2][:m]
455
- goal[:offset] = node[2][:offset] if node[2][:offset]
456
-
457
- ## check for own goal or penalty or such
458
- if !nodes.empty?
459
- node_type = nodes[0][0]
460
- if node_type == :og
461
- nodes.shift
462
- goal[:og] = true
463
- elsif node_type == :pen
464
- nodes.shift
465
- goal[:pen] = true
466
- else
467
- # do nothing
468
- end
469
- end
470
-
471
- goals << goal
472
-
473
- ## check if another minute ahead; otherwise break
474
- break if nodes.empty?
475
-
476
- node_type = nodes[0][0]
477
399
 
478
- ## Kane 39', 62', 67'
479
- ## consume/eat-up (optional?) commas
480
- if node_type == :','
481
- nodes.shift
482
- node_type = nodes[0][0]
483
- end
400
+ def on_goal_line( node )
401
+ logger.debug "on goal line: >#{node}<"
484
402
 
485
- break if node_type != :minute
486
- end
487
-
488
-
489
- goals
490
- end
491
-
492
-
493
- def parse_goals( nodes )
494
- logger.debug "parse goals: >#{nodes}<"
495
-
496
- goals1 = []
497
- goals2 = []
498
-
499
- while !nodes.empty?
500
- node_type = nodes[0][0]
501
- if node_type == :player
502
- more_goals = parse_minutes( nodes )
503
- ## hacky multi-line support for goals
504
- ## using last_goal (1|2)
505
- @last_goals == 2 ? goals2 += more_goals :
506
- goals1 += more_goals
507
- elsif node_type == :';' ## team separator
508
- nodes.shift # eat-up
509
- @last_goals = 2
510
- elsif node_type == :none
511
- nodes.shift # eat-up
512
- else
513
- puts "!! PARSE ERROR - unexpected node type in goals;; got #{node_type}:"
514
- pp nodes
515
- exit 1
516
- end
517
- end
403
+ goals1 = node.goals1
404
+ goals2 = node.goals2
518
405
 
406
+
519
407
  pp [goals1,goals2] if debug?
520
408
 
409
+
521
410
  ## wrap in struct andd add/append to match
522
411
  =begin
523
412
  class GoalStruct
@@ -532,26 +421,30 @@ class GoalStruct
532
421
 
533
422
  goals = []
534
423
  goals1.each do |rec|
535
- goal = Import::Goal.new(
536
- player: rec[:name],
424
+ rec.minutes.each do |minute|
425
+ goal = Import::Goal.new(
426
+ player: rec.player,
537
427
  team: 1,
538
- minute: rec[:minute],
539
- offset: rec[:offset],
540
- penalty: rec[:pen] || false, # note: pass along/use false NOT nil
541
- owngoal: rec[:og] || false
428
+ minute: minute.m,
429
+ offset: minute.offset,
430
+ penalty: minute.pen || false, # note: pass along/use false NOT nil
431
+ owngoal: minute.og || false
542
432
  )
543
- goals << goal
433
+ goals << goal
434
+ end
544
435
  end
545
436
  goals2.each do |rec|
546
- goal = Import::Goal.new(
547
- player: rec[:name],
437
+ rec.minutes.each do |minute|
438
+ goal = Import::Goal.new(
439
+ player: rec.player,
548
440
  team: 2,
549
- minute: rec[:minute],
550
- offset: rec[:offset],
551
- penalty: rec[:pen] || false, # note: pass along/use false NOT nil
552
- owngoal: rec[:og] || false
441
+ minute: minute.m,
442
+ offset: minute.offset,
443
+ penalty: minute.pen || false, # note: pass along/use false NOT nil
444
+ owngoal: minute.og || false
553
445
  )
554
446
  goals << goal
447
+ end
555
448
  end
556
449
 
557
450
  pp goals if debug?
@@ -569,90 +462,65 @@ class GoalStruct
569
462
  end
570
463
 
571
464
 
572
- def parse_match( nodes )
573
- logger.debug( "parse match: >#{nodes}<" )
465
+ def on_match_line( node )
466
+ logger.debug( "on match: >#{node}<" )
574
467
 
575
468
  ## collect (possible) nodes by type
576
469
  num = nil
470
+ num = node.ord if node.ord
471
+
577
472
  date = nil
578
- time = nil
579
- teams = []
473
+ date = _build_date( m: node.date[:m],
474
+ d: node.date[:d],
475
+ y: node.date[:y],
476
+ start: @start ) if node.date
477
+
478
+ ## note - there's no time (-only) type in ruby
479
+ ## use string (e.g. '14:56', '1:44')
480
+ ## use 01:44 or 1:44 ?
481
+ ## check for 0:00 or 24:00 possible?
482
+ time = ('%d:%02d' % [node.time[:h], node.time[:m]]) if node.time
483
+
484
+
485
+ ### todo/fix
486
+ ## add keywords (e.g. ht, ft or such) to Score.new - why? why not?
487
+ ## or use new Score.build( ht:, ft:, ) or such - why? why not?
488
+ ## pp score
580
489
  score = nil
490
+ if node.score
491
+ ht = node.score[:ht] || [nil,nil]
492
+ ft = node.score[:ft] || [nil,nil]
493
+ et = node.score[:et] || [nil,nil]
494
+ p = node.score[:p] || [nil,nil]
495
+ values = [*ht, *ft, *et, *p]
496
+ ## pp values
497
+ score = Score.new( *values )
498
+ end
499
+
581
500
  more = []
501
+
582
502
  status = nil
503
+ ## if node_type == :status # e.g. awarded, canceled, postponed, etc.
504
+ ## status = node[1]
505
+
583
506
 
584
- while !nodes.empty?
585
- node = nodes.shift
586
- node_type = node[0]
587
-
588
- if node_type == :num
589
- num = node[1]
590
- elsif node_type == :date
591
- ## note: date wipes out/clear time
592
- ## time MUST always come after date
593
- time = nil
594
- date = _build_date( m: node[2][:m],
595
- d: node[2][:d],
596
- y: node[2][:y],
597
- start: @start )
598
- elsif node_type == :time
599
- ## note - there's no time (-only) type in ruby
600
- ## use string (e.g. '14:56', '1:44')
601
- ## use 01:44 or 1:44 ?
602
- ## check for 0:00 or 24:00 possible?
603
- time = '%d:%02d' % [node[2][:h], node[2][:m]]
604
- elsif node_type == :team
605
- teams << node[1]
606
- elsif node_type == :score
607
- ### todo/fix
608
- ## add keywords (e.g. ht, ft or such) to Score.new - why? why not?
609
- ## or use new Score.build( ht:, ft:, ) or such - why? why not?
610
- ht = node[2][:ht] || [nil,nil]
611
- ft = node[2][:ft] || [nil,nil]
612
- et = node[2][:et] || [nil,nil]
613
- p = node[2][:p] || [nil,nil]
614
- values = [*ht, *ft, *et, *p]
615
- ## pp values
616
-
617
- score = Score.new( *values )
618
- ## pp score
619
- elsif node_type == :status # e.g. awarded, canceled, postponed, etc.
620
- status = node[1]
621
- elsif node_type == :vs
622
- ## skip; do nothing
623
- ##
507
+ #
624
508
  ## todo - add ## find (optional) match status e.g. [abandoned] or [replay] or [awarded]
625
509
  ## or [cancelled] or [postponed] etc.
626
510
  ## status = find_status!( line ) ## todo/check: allow match status also in geo part (e.g. after @) - why? why not?
627
-
628
- elsif node_type == :'@' ||
629
- node_type == :',' ||
630
- node_type == :geo ||
631
- node_type == :timezone
511
+ #
512
+ # elsif node_type == :'@' ||
513
+ # node_type == :',' ||
514
+ # node_type == :geo ||
515
+ # node_type == :timezone
632
516
  ## e.g.
633
517
  ## [:"@"], [:geo, "Stade de France"], [:","], [:geo, "Saint-Denis"]]
634
518
  ## [:"@"], [:geo, "Arena de São Paulo"], [:","], [:geo, "São Paulo"], [:timezone, "(UTC-3)"]
635
- more << node[1] if node_type == :geo
636
- else
637
- puts "!! PARSE ERROR - unexpected node type #{node_type} in match line; got:"
638
- pp node
639
- ## exit 1
640
- @errors << ["PARSE ERROR - unexpected node type #{node_type} in match line; got: #{node.inspect}"]
641
- return
642
- end
643
- end
644
-
519
+ # more << node[1] if node_type == :geo
520
+
645
521
 
646
- if teams.size != 2
647
- puts "!! PARSE ERROR - expected two teams; got #{teams.size}:"
648
- pp teams
649
- ## exit 1
650
- @errors << ["PARSE ERROR - expected two teams; got #{teams.size}: #{teams.inspect}"]
651
- return
652
- end
653
-
654
- team1 = teams[0]
655
- team2 = teams[1]
522
+ team1 = node.team1
523
+ team2 = node.team2
656
524
 
657
525
  @teams[ team1 ] += 1
658
526
  @teams[ team2 ] += 1
@@ -738,10 +606,6 @@ class GoalStruct
738
606
  status: status,
739
607
  ground: ground )
740
608
  ### todo: cache team lookups in hash?
741
-
742
- ## hacky goals support
743
- ### reset/toggle 1/2
744
- @last_goals = 1
745
609
  end
746
610
  end # class MatchParser
747
611
  end # module SportDb
@@ -3,8 +3,8 @@ module SportDb
3
3
  module Module
4
4
  module Quick
5
5
  MAJOR = 0 ## todo: namespace inside version or something - why? why not??
6
- MINOR = 3
7
- PATCH = 1
6
+ MINOR = 5
7
+ PATCH = 0
8
8
  VERSION = [MAJOR,MINOR,PATCH].join('.')
9
9
 
10
10
  def self.version
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sportdb-quick
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerald Bauer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-01-02 00:00:00.000000000 Z
11
+ date: 2025-01-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sportdb-parser
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.4.0
19
+ version: 0.5.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.4.0
26
+ version: 0.5.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: sportdb-structs
29
29
  requirement: !ruby/object:Gem::Requirement