sportdb-parser 0.7.0 → 0.7.2
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 +1 -1
- data/Manifest.txt +18 -4
- data/Rakefile +0 -1
- data/lib/sportdb/parser/lexer-on_goal.rb +172 -0
- data/lib/sportdb/parser/lexer-on_group_def.rb +31 -0
- data/lib/sportdb/parser/lexer-on_prop_lineup.rb +79 -0
- data/lib/sportdb/parser/lexer-on_prop_misc.rb +110 -0
- data/lib/sportdb/parser/lexer-on_prop_penalties.rb +40 -0
- data/lib/sportdb/parser/lexer-on_round_def.rb +37 -0
- data/lib/sportdb/parser/lexer-on_top.rb +125 -0
- data/lib/sportdb/parser/lexer-prep_doc.rb +131 -0
- data/lib/sportdb/parser/lexer-prep_line.rb +63 -0
- data/lib/sportdb/parser/lexer-tokenize.rb +449 -0
- data/lib/sportdb/parser/lexer.rb +133 -1363
- data/lib/sportdb/parser/lexer_buffer.rb +8 -37
- data/lib/sportdb/parser/lexer_token.rb +126 -0
- data/lib/sportdb/parser/parser.rb +1104 -1401
- data/lib/sportdb/parser/parser_runtime.rb +379 -0
- data/lib/sportdb/parser/racc_parser.rb +36 -32
- data/lib/sportdb/parser/racc_tree.rb +65 -98
- data/lib/sportdb/parser/token-date--helpers.rb +130 -0
- data/lib/sportdb/parser/token-date--names.rb +108 -0
- data/lib/sportdb/parser/token-date.rb +20 -192
- data/lib/sportdb/parser/token-date_duration.rb +8 -27
- data/lib/sportdb/parser/token-geo.rb +16 -16
- data/lib/sportdb/parser/token-goals--helpers.rb +114 -0
- data/lib/sportdb/parser/token-goals.rb +103 -249
- data/lib/sportdb/parser/token-group.rb +8 -22
- data/lib/sportdb/parser/token-prop.rb +138 -124
- data/lib/sportdb/parser/token-prop_name.rb +48 -39
- data/lib/sportdb/parser/token-round.rb +21 -35
- data/lib/sportdb/parser/token-score--helpers.rb +189 -0
- data/lib/sportdb/parser/token-score.rb +9 -393
- data/lib/sportdb/parser/token-score_full.rb +331 -0
- data/lib/sportdb/parser/token-status.rb +44 -46
- data/lib/sportdb/parser/token-status_inline.rb +112 -0
- data/lib/sportdb/parser/token-text.rb +41 -31
- data/lib/sportdb/parser/token-time.rb +29 -26
- data/lib/sportdb/parser/token.rb +58 -159
- data/lib/sportdb/parser/version.rb +1 -1
- data/lib/sportdb/parser.rb +50 -19
- metadata +20 -20
- data/lib/sportdb/parser/blocktxt.rb +0 -99
- data/lib/sportdb/parser/lexer_tty.rb +0 -111
- data/lib/sportdb/parser/token-table.rb +0 -149
- data/lib/sportdb/parser/token_helpers.rb +0 -92
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
class RaccMatchParser
|
|
6
6
|
|
|
7
7
|
=begin
|
|
8
|
-
RefereeLine = Struct.new( :name, :country ) do
|
|
8
|
+
RefereeLine = Struct.new( :name, :country ) do
|
|
9
9
|
def pretty_print( printer )
|
|
10
10
|
printer.text( "<RefereeLine " )
|
|
11
11
|
printer.text( self.name )
|
|
@@ -16,7 +16,7 @@ end
|
|
|
16
16
|
=end
|
|
17
17
|
|
|
18
18
|
## support multiple referees (incl. assistant refs etc.)
|
|
19
|
-
RefereeLine = Struct.new( :referees ) do
|
|
19
|
+
RefereeLine = Struct.new( :referees ) do
|
|
20
20
|
def pretty_print( printer )
|
|
21
21
|
printer.text( "<RefereeLine " )
|
|
22
22
|
printer.text( self.referees.pretty_inspect )
|
|
@@ -28,16 +28,16 @@ Referee = Struct.new( :name, :country ) do
|
|
|
28
28
|
def to_s
|
|
29
29
|
buf = String.new
|
|
30
30
|
buf << self.name
|
|
31
|
-
buf << " (#{self.country})" if self.country
|
|
31
|
+
buf << " (#{self.country})" if self.country
|
|
32
32
|
buf
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def pretty_print( printer )
|
|
36
36
|
printer.text( to_s )
|
|
37
|
-
end
|
|
37
|
+
end
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
-
AttendanceLine = Struct.new( :att ) do
|
|
40
|
+
AttendanceLine = Struct.new( :att ) do
|
|
41
41
|
def pretty_print( printer )
|
|
42
42
|
printer.text( "<AttendanceLine #{self.att}>" )
|
|
43
43
|
end
|
|
@@ -45,7 +45,7 @@ end
|
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
|
|
48
|
-
PenaltiesLine = Struct.new( :penalties ) do
|
|
48
|
+
PenaltiesLine = Struct.new( :penalties ) do
|
|
49
49
|
def pretty_print( printer )
|
|
50
50
|
printer.text( "<PenaltiesLine " )
|
|
51
51
|
printer.text( self.penalties.pretty_inspect )
|
|
@@ -59,21 +59,21 @@ Penalty = Struct.new( :name, :score, :note ) do
|
|
|
59
59
|
buf = String.new
|
|
60
60
|
buf << "#{self.score[0]}-#{self.score[1]} " if self.score
|
|
61
61
|
buf << self.name
|
|
62
|
-
buf << " (#{self.note})" if self.note
|
|
62
|
+
buf << " (#{self.note})" if self.note
|
|
63
63
|
buf
|
|
64
64
|
end
|
|
65
65
|
|
|
66
66
|
|
|
67
67
|
def pretty_print( printer )
|
|
68
68
|
printer.text( to_s )
|
|
69
|
-
end
|
|
69
|
+
end
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
|
|
73
73
|
|
|
74
74
|
|
|
75
75
|
## find a better name for player (use bookings?) - note - red/yellow card for trainer possible
|
|
76
|
-
CardsLine = Struct.new( :type, :bookings ) do
|
|
76
|
+
CardsLine = Struct.new( :type, :bookings ) do
|
|
77
77
|
def pretty_print( printer )
|
|
78
78
|
printer.text( "<CardsLine " )
|
|
79
79
|
printer.text( self.type )
|
|
@@ -92,7 +92,7 @@ Booking = Struct.new( :name, :minute ) do
|
|
|
92
92
|
|
|
93
93
|
def pretty_print( printer )
|
|
94
94
|
printer.text( to_s )
|
|
95
|
-
end
|
|
95
|
+
end
|
|
96
96
|
end
|
|
97
97
|
|
|
98
98
|
|
|
@@ -111,11 +111,11 @@ end
|
|
|
111
111
|
Lineup = Struct.new( :name, :captain, :cards, :sub ) do
|
|
112
112
|
def pretty_print( printer )
|
|
113
113
|
buf = String.new
|
|
114
|
-
buf << self.name
|
|
114
|
+
buf << self.name
|
|
115
115
|
buf << " [c]" if captain
|
|
116
116
|
buf << " cards=" + self.cards.pretty_inspect if cards
|
|
117
117
|
buf << " sub=" + self.sub.pretty_inspect if sub
|
|
118
|
-
printer.text( buf )
|
|
118
|
+
printer.text( buf )
|
|
119
119
|
end
|
|
120
120
|
end
|
|
121
121
|
|
|
@@ -130,18 +130,18 @@ Card = Struct.new( :name, :minute ) do
|
|
|
130
130
|
|
|
131
131
|
def pretty_print( printer )
|
|
132
132
|
printer.text( to_s )
|
|
133
|
-
end
|
|
133
|
+
end
|
|
134
134
|
end
|
|
135
135
|
|
|
136
136
|
|
|
137
137
|
Sub = Struct.new( :minute, :sub ) do
|
|
138
138
|
def pretty_print( printer )
|
|
139
|
-
buf = String.new
|
|
139
|
+
buf = String.new
|
|
140
140
|
buf << "(" ## note - possibly recursive (thus, let minute go first/print first/upfront)
|
|
141
|
-
buf << "#{self.minute.to_s} " if self.minute
|
|
142
|
-
buf << "#{self.sub.pretty_inspect}"
|
|
141
|
+
buf << "#{self.minute.to_s} " if self.minute
|
|
142
|
+
buf << "#{self.sub.pretty_inspect}"
|
|
143
143
|
buf << ")"
|
|
144
|
-
printer.text( buf )
|
|
144
|
+
printer.text( buf )
|
|
145
145
|
end
|
|
146
146
|
end
|
|
147
147
|
|
|
@@ -201,13 +201,6 @@ class BlankLine
|
|
|
201
201
|
end
|
|
202
202
|
end
|
|
203
203
|
|
|
204
|
-
## todo/check - find a better name for hruler - divider? or ??? - why? why not?
|
|
205
|
-
class HRuler ## h(orizontal) ruler (for breaks; new scopes)
|
|
206
|
-
def pretty_print( printer )
|
|
207
|
-
printer.text( "<HRuler>" )
|
|
208
|
-
end
|
|
209
|
-
end
|
|
210
|
-
|
|
211
204
|
|
|
212
205
|
|
|
213
206
|
NoteLine = Struct.new( :text ) do
|
|
@@ -223,32 +216,6 @@ NotaBene = Struct.new( :text ) do
|
|
|
223
216
|
end
|
|
224
217
|
|
|
225
218
|
|
|
226
|
-
## todo/check - rename TableHeading to TableHeader - why? why not?
|
|
227
|
-
TableHeading = Struct.new( :text ) do
|
|
228
|
-
def pretty_print( printer )
|
|
229
|
-
printer.text( "<TableHeading #{self.text}>" )
|
|
230
|
-
end
|
|
231
|
-
end
|
|
232
|
-
|
|
233
|
-
## todo/check - rename TableDivider to TableRule/TableRuler/TableLine - why? why not?
|
|
234
|
-
TableDivider = Struct.new( :text ) do
|
|
235
|
-
def pretty_print( printer )
|
|
236
|
-
printer.text( "<TableDivider #{self.text}>" )
|
|
237
|
-
end
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
TableLine = Struct.new( :text ) do
|
|
241
|
-
def pretty_print( printer )
|
|
242
|
-
printer.text( "<TableLine #{self.text}>" )
|
|
243
|
-
end
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
TableNote = Struct.new( :text ) do
|
|
247
|
-
def pretty_print( printer )
|
|
248
|
-
printer.text( "<TableNote #{self.text}>" )
|
|
249
|
-
end
|
|
250
|
-
end
|
|
251
|
-
|
|
252
219
|
|
|
253
220
|
|
|
254
221
|
## todo/check - use a generic Heading instead of Heading1/2/3 - why? why not?
|
|
@@ -278,7 +245,7 @@ MatchLineBye = Struct.new( :team, :note ) do
|
|
|
278
245
|
printer.text( "#{self.team} bye")
|
|
279
246
|
printer.text( " note=#{self.note.pretty_inspect}" ) if self.note
|
|
280
247
|
printer.text( ">" )
|
|
281
|
-
end
|
|
248
|
+
end
|
|
282
249
|
end
|
|
283
250
|
|
|
284
251
|
MatchLineWalkover = Struct.new( :team1, :team2, :note ) do
|
|
@@ -287,10 +254,10 @@ MatchLineWalkover = Struct.new( :team1, :team2, :note ) do
|
|
|
287
254
|
printer.text( "#{self.team1} w/o #{self.team2}")
|
|
288
255
|
printer.text( " note=#{self.note.pretty_inspect}" ) if self.note
|
|
289
256
|
printer.text( ">" )
|
|
290
|
-
end
|
|
257
|
+
end
|
|
291
258
|
end
|
|
292
259
|
|
|
293
|
-
MatchLineLegs = Struct.new( :team1, :team2,
|
|
260
|
+
MatchLineLegs = Struct.new( :team1, :team2,
|
|
294
261
|
:score ) do ## change to geos - why? why not?
|
|
295
262
|
def pretty_print( printer )
|
|
296
263
|
printer.text( "<MatchLineLegs " )
|
|
@@ -300,26 +267,26 @@ MatchLineLegs = Struct.new( :team1, :team2,
|
|
|
300
267
|
members.zip(values) do |name, value|
|
|
301
268
|
next if [:team1, :team2].include?( name )
|
|
302
269
|
next if value.nil?
|
|
303
|
-
|
|
270
|
+
|
|
304
271
|
printer.text( "#{name}=#{value.pretty_inspect}" )
|
|
305
|
-
end
|
|
272
|
+
end
|
|
306
273
|
|
|
307
274
|
printer.text( ">" )
|
|
308
|
-
end
|
|
275
|
+
end
|
|
309
276
|
end
|
|
310
277
|
|
|
311
278
|
|
|
312
279
|
#
|
|
313
280
|
# note: use two status attributes for now
|
|
314
281
|
# 1) inline_status and 2) (note_)status
|
|
315
|
-
# for now e.g. A abd. B vs A v B [abadoned]
|
|
282
|
+
# for now e.g. A abd. B vs A v B [abadoned]
|
|
316
283
|
# A 3-0 awd B vs A 3-0 B [awarded]
|
|
317
284
|
# note - BOTH might be present at the same time
|
|
318
285
|
|
|
319
286
|
|
|
320
287
|
MatchLine = Struct.new( :header, :tty, ## tty = TELETYPE MODE for teams and score!!
|
|
321
288
|
:num, :date, :time, :time_local, :year,
|
|
322
|
-
:team1, :team2,
|
|
289
|
+
:team1, :team2,
|
|
323
290
|
:score,
|
|
324
291
|
:status, :status_inline, :status_note,
|
|
325
292
|
:geo,
|
|
@@ -335,12 +302,12 @@ MatchLine = Struct.new( :header, :tty, ## tty = TELETYPE MODE for teams and
|
|
|
335
302
|
members.zip(values) do |name, value|
|
|
336
303
|
next if [:team1, :team2].include?( name )
|
|
337
304
|
next if value.nil?
|
|
338
|
-
|
|
305
|
+
|
|
339
306
|
printer.text( "#{name}=#{value.pretty_inspect}" )
|
|
340
|
-
end
|
|
307
|
+
end
|
|
341
308
|
|
|
342
309
|
printer.text( ">" )
|
|
343
|
-
end
|
|
310
|
+
end
|
|
344
311
|
|
|
345
312
|
end
|
|
346
313
|
|
|
@@ -351,12 +318,12 @@ GoalLine = Struct.new( :goals1, :goals2 ) do
|
|
|
351
318
|
printer.text( "goals1=" + self.goals1.pretty_inspect + "," )
|
|
352
319
|
printer.breakable
|
|
353
320
|
printer.text( "goals2=" + self.goals2.pretty_inspect + ">" )
|
|
354
|
-
end
|
|
321
|
+
end
|
|
355
322
|
|
|
356
323
|
## def clone
|
|
357
|
-
## _clone = GoalLine.new( goals1: goals1.clone,
|
|
324
|
+
## _clone = GoalLine.new( goals1: goals1.clone,
|
|
358
325
|
## goals2: goals2.clone )
|
|
359
|
-
##
|
|
326
|
+
##
|
|
360
327
|
## puts "[debug] clone #{self.pretty_inspect} => #{_clone.pretty_inspect}"
|
|
361
328
|
##
|
|
362
329
|
## _clone
|
|
@@ -386,7 +353,7 @@ Goal = Struct.new( :player, :minutes, :count ) do
|
|
|
386
353
|
|
|
387
354
|
def pretty_print( printer )
|
|
388
355
|
printer.text( to_s )
|
|
389
|
-
end
|
|
356
|
+
end
|
|
390
357
|
|
|
391
358
|
## def clone
|
|
392
359
|
## puts "[debug] clone #{self.pretty_inspect}"
|
|
@@ -402,7 +369,7 @@ GoalLineAlt = Struct.new( :goals ) do
|
|
|
402
369
|
def pretty_print( printer )
|
|
403
370
|
printer.text( "<GoalLineAlt " )
|
|
404
371
|
printer.text( "goals=" + self.goals.pretty_inspect + ">" )
|
|
405
|
-
end
|
|
372
|
+
end
|
|
406
373
|
end
|
|
407
374
|
|
|
408
375
|
|
|
@@ -423,7 +390,7 @@ GoalAlt = Struct.new( :score, :player, :minute, :goal_type ) do
|
|
|
423
390
|
|
|
424
391
|
def pretty_print( printer )
|
|
425
392
|
printer.text( to_s )
|
|
426
|
-
end
|
|
393
|
+
end
|
|
427
394
|
end
|
|
428
395
|
|
|
429
396
|
|
|
@@ -432,7 +399,7 @@ GoalLineCompat = Struct.new( :goals ) do
|
|
|
432
399
|
def pretty_print( printer )
|
|
433
400
|
printer.text( "<GoalLineCompat " )
|
|
434
401
|
printer.text( "goals=" + self.goals.pretty_inspect + ">" )
|
|
435
|
-
end
|
|
402
|
+
end
|
|
436
403
|
end
|
|
437
404
|
|
|
438
405
|
##
|
|
@@ -443,7 +410,7 @@ end
|
|
|
443
410
|
GoalCompat = Struct.new( :score, :player, :minute, :goal_type ) do
|
|
444
411
|
def to_s
|
|
445
412
|
buf = String.new
|
|
446
|
-
buf << "#{self.minute}"
|
|
413
|
+
buf << "#{self.minute}"
|
|
447
414
|
buf << " #{self.player}"
|
|
448
415
|
buf << " #{self.goal_type}" if self.goal_type
|
|
449
416
|
buf << " #{self.score[0]}-#{self.score[1]}" if self.score
|
|
@@ -452,7 +419,7 @@ GoalCompat = Struct.new( :score, :player, :minute, :goal_type ) do
|
|
|
452
419
|
|
|
453
420
|
def pretty_print( printer )
|
|
454
421
|
printer.text( to_s )
|
|
455
|
-
end
|
|
422
|
+
end
|
|
456
423
|
end
|
|
457
424
|
|
|
458
425
|
|
|
@@ -477,31 +444,31 @@ GoalMinute = Struct.new( :m, :offset, :secs,
|
|
|
477
444
|
buf = String.new
|
|
478
445
|
buf << "#{self.m}"
|
|
479
446
|
buf << "'"
|
|
480
|
-
buf << "+#{self.offset}" if self.offset
|
|
481
|
-
buf << "
|
|
482
|
-
buf << "
|
|
483
|
-
buf << "
|
|
484
|
-
buf << "
|
|
447
|
+
buf << "+#{self.offset}" if self.offset
|
|
448
|
+
buf << "(og)" if self.og
|
|
449
|
+
buf << "(p)" if self.pen
|
|
450
|
+
buf << "(f)" if self.freekick
|
|
451
|
+
buf << "(h)" if self.header
|
|
485
452
|
buf << " (#{self.secs} secs)" if self.secs
|
|
486
453
|
buf
|
|
487
454
|
end
|
|
488
|
-
|
|
489
|
-
def pretty_print( printer )
|
|
490
|
-
printer.text( to_s )
|
|
491
|
-
end
|
|
455
|
+
|
|
456
|
+
def pretty_print( printer )
|
|
457
|
+
printer.text( to_s )
|
|
458
|
+
end
|
|
492
459
|
|
|
493
460
|
### quick hack:
|
|
494
461
|
### split struct into Minute+GoalType structs
|
|
495
462
|
def to_minute
|
|
496
|
-
Minute.new( m: self.m,
|
|
463
|
+
Minute.new( m: self.m,
|
|
497
464
|
offset: self.offset,
|
|
498
465
|
secs: self.secs )
|
|
499
466
|
end
|
|
500
467
|
|
|
501
468
|
def to_goal_type
|
|
502
|
-
if self.og || self.pen || self.header || self.freekick
|
|
503
|
-
GoalType.new( og: self.og,
|
|
504
|
-
pen: self.pen,
|
|
469
|
+
if self.og || self.pen || self.header || self.freekick
|
|
470
|
+
GoalType.new( og: self.og,
|
|
471
|
+
pen: self.pen,
|
|
505
472
|
header: self.header,
|
|
506
473
|
freekick: self.freekick )
|
|
507
474
|
else
|
|
@@ -511,14 +478,14 @@ GoalMinute = Struct.new( :m, :offset, :secs,
|
|
|
511
478
|
|
|
512
479
|
## def clone
|
|
513
480
|
## puts "[debug] clone #{self.pretty_inspect}"
|
|
514
|
-
## GoalMinute.new( m: m.clone,
|
|
515
|
-
## offset: offset.clone,
|
|
481
|
+
## GoalMinute.new( m: m.clone,
|
|
482
|
+
## offset: offset.clone,
|
|
516
483
|
## secs: secs.clone,
|
|
517
|
-
## og: og.clone,
|
|
518
|
-
## pen: pen.clone,
|
|
519
|
-
## header: header.clone,
|
|
484
|
+
## og: og.clone,
|
|
485
|
+
## pen: pen.clone,
|
|
486
|
+
## header: header.clone,
|
|
520
487
|
## freekick: freekick.clone )
|
|
521
|
-
##
|
|
488
|
+
##
|
|
522
489
|
## end
|
|
523
490
|
end
|
|
524
491
|
|
|
@@ -532,10 +499,10 @@ GoalType = Struct.new( :og, :pen, :header, :freekick ) do
|
|
|
532
499
|
buf << "(h)" if self.header
|
|
533
500
|
buf
|
|
534
501
|
end
|
|
535
|
-
|
|
536
|
-
def pretty_print( printer )
|
|
537
|
-
printer.text( to_s )
|
|
538
|
-
end
|
|
502
|
+
|
|
503
|
+
def pretty_print( printer )
|
|
504
|
+
printer.text( to_s )
|
|
505
|
+
end
|
|
539
506
|
end
|
|
540
507
|
|
|
541
508
|
|
|
@@ -544,14 +511,14 @@ Minute = Struct.new( :m, :offset, :secs ) do
|
|
|
544
511
|
buf = String.new
|
|
545
512
|
buf << "#{self.m}"
|
|
546
513
|
buf << "'"
|
|
547
|
-
buf << "+#{self.offset}" if self.offset
|
|
514
|
+
buf << "+#{self.offset}" if self.offset
|
|
548
515
|
buf << "/#{self.secs} secs" if self.secs
|
|
549
516
|
buf
|
|
550
517
|
end
|
|
551
|
-
|
|
552
|
-
def pretty_print( printer )
|
|
553
|
-
printer.text( to_s )
|
|
554
|
-
end
|
|
518
|
+
|
|
519
|
+
def pretty_print( printer )
|
|
520
|
+
printer.text( to_s )
|
|
521
|
+
end
|
|
555
522
|
end
|
|
556
523
|
|
|
557
524
|
end # class RaccMatchParser
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
module SportDb
|
|
2
|
+
class Lexer
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
## "internal" date helpers
|
|
6
|
+
def self._build_date( m )
|
|
7
|
+
date = {}
|
|
8
|
+
## map month names
|
|
9
|
+
## note - allow any/upcase JULY/JUL etc. thus ALWAYS downcase for lookup
|
|
10
|
+
date[:y] = m[:year].to_i(10) if m[:year]
|
|
11
|
+
## check - use y too for two-digit year or keep separate - why? why not?
|
|
12
|
+
date[:yy] = m[:yy].to_i(10) if m[:yy] ## two digit year (e.g. 25 or 78 etc.)
|
|
13
|
+
date[:m] = m[:month].to_i(10) if m[:month]
|
|
14
|
+
date[:m] = MONTH_MAP[ m[:month_name].downcase ] if m[:month_name]
|
|
15
|
+
date[:d] = m[:day].to_i(10) if m[:day]
|
|
16
|
+
date[:wday] = DAY_MAP[ m[:day_name].downcase ] if m[:day_name]
|
|
17
|
+
|
|
18
|
+
date
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self._build_date_legs( m )
|
|
22
|
+
legs = {}
|
|
23
|
+
## map month names
|
|
24
|
+
## note - allow any/upcase JULY/JUL etc. thus ALWAYS downcase for lookup
|
|
25
|
+
date = {}
|
|
26
|
+
date[:m] = MONTH_MAP[ m[:month_name1].downcase ]
|
|
27
|
+
date[:d] = m[:day1].to_i(10)
|
|
28
|
+
legs[:date1] = date
|
|
29
|
+
|
|
30
|
+
date = {}
|
|
31
|
+
date[:m] = MONTH_MAP[ m[:month_name2].downcase ] if m[:month_name2]
|
|
32
|
+
date[:d] = m[:day2].to_i(10)
|
|
33
|
+
legs[:date2] = date
|
|
34
|
+
|
|
35
|
+
legs
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def self._build_duration( m )
|
|
40
|
+
## todo/check/fix - if end: works for kwargs!!!!!
|
|
41
|
+
duration = { start: {}, end: {}}
|
|
42
|
+
|
|
43
|
+
duration[:start][:y] = m[:year1].to_i(10) if m[:year1]
|
|
44
|
+
duration[:start][:m] = MONTH_MAP[ m[:month_name1].downcase ] if m[:month_name1]
|
|
45
|
+
duration[:start][:d] = m[:day1].to_i(10) if m[:day1]
|
|
46
|
+
duration[:start][:wday] = DAY_MAP[ m[:day_name1].downcase ] if m[:day_name1]
|
|
47
|
+
|
|
48
|
+
duration[:end][:y] = m[:year2].to_i(10) if m[:year2]
|
|
49
|
+
duration[:end][:m] = MONTH_MAP[ m[:month_name2].downcase ] if m[:month_name2]
|
|
50
|
+
duration[:end][:d] = m[:day2].to_i(10) if m[:day2]
|
|
51
|
+
duration[:end][:wday] = DAY_MAP[ m[:day_name2].downcase ] if m[:day_name2]
|
|
52
|
+
|
|
53
|
+
duration
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _build_date( m ) self.class._build_date( m ); end
|
|
60
|
+
def _build_date_legs( m ) self.class._build_date_legs( m ); end
|
|
61
|
+
def _build_duration( m ) self.class._build_duration( m ); end
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
#############
|
|
67
|
+
## "top-level" add a date parser helper
|
|
68
|
+
|
|
69
|
+
## note: parse_date - returns Date object
|
|
70
|
+
## _parse_date (with underscore) - return hash of "parsed" regex match data!!
|
|
71
|
+
|
|
72
|
+
def self.parse_date( str, start: nil )
|
|
73
|
+
if m = _parse_date( str )
|
|
74
|
+
year = m[:y]
|
|
75
|
+
yy = m[:yy]
|
|
76
|
+
|
|
77
|
+
####
|
|
78
|
+
## support two digit shortcut for year
|
|
79
|
+
if yy && year.nil?
|
|
80
|
+
###
|
|
81
|
+
## for now assume 00,01 to 30 is 2000,2001 to 2030
|
|
82
|
+
## and 31 to 99 is 1931 to 1999
|
|
83
|
+
year = yy <= 30 ? 2000+yy : 1900+yy
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
month = m[:m]
|
|
87
|
+
day = m[:d]
|
|
88
|
+
wday = m[:wday]
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
if year.nil? ## try to calculate year
|
|
92
|
+
raise ArgumentError, "year required in date >#{str}< or pass along start date" if start.nil?
|
|
93
|
+
|
|
94
|
+
year = if month > start.month ||
|
|
95
|
+
(month == start.month && day >= start.day)
|
|
96
|
+
# assume same year as start_at event (e.g. 2013 for 2013/14 season)
|
|
97
|
+
start.year
|
|
98
|
+
else
|
|
99
|
+
# assume year+1 as start_at event (e.g. 2014 for 2013/14 season)
|
|
100
|
+
start.year+1
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
Date.new( year,month,day )
|
|
104
|
+
else
|
|
105
|
+
raise ArgumentError, "unexpected date format; cannot parse >#{str}<"
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def self._parse_date( str )
|
|
112
|
+
## note - strip - leading/trailing spaces automatic - why? why not?
|
|
113
|
+
m = DATE_RE.match( str.strip )
|
|
114
|
+
|
|
115
|
+
if m && m.pre_match == '' && m.post_match == ''
|
|
116
|
+
## return hash table with captured components
|
|
117
|
+
date = _build_date( m )
|
|
118
|
+
date
|
|
119
|
+
elsif m
|
|
120
|
+
## note - match BUT not anchored to start and end-of-string!!!
|
|
121
|
+
## report, error somehow??
|
|
122
|
+
nil
|
|
123
|
+
else
|
|
124
|
+
nil ## no match - return nil
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
end # class Lexer
|
|
130
|
+
end # module SportDb
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
module SportDb
|
|
2
|
+
class Lexer
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def self.parse_names( txt )
|
|
6
|
+
lines = [] # array of lines (with words)
|
|
7
|
+
|
|
8
|
+
txt.each_line do |line|
|
|
9
|
+
line = line.strip
|
|
10
|
+
|
|
11
|
+
next if line.empty?
|
|
12
|
+
next if line.start_with?( '#' ) ## skip comments too
|
|
13
|
+
|
|
14
|
+
## strip inline (until end-of-line) comments too
|
|
15
|
+
## e.g. Janvier Janv Jan ## check janv in use??
|
|
16
|
+
## => Janvier Janv Jan
|
|
17
|
+
|
|
18
|
+
line = line.sub( /#.*/, '' ).strip
|
|
19
|
+
## pp line
|
|
20
|
+
|
|
21
|
+
values = line.split( /[ \t]+/ )
|
|
22
|
+
## pp values
|
|
23
|
+
|
|
24
|
+
## todo/fix -- add check for duplicates
|
|
25
|
+
lines << values
|
|
26
|
+
end
|
|
27
|
+
lines
|
|
28
|
+
|
|
29
|
+
end # method parse
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def self.build_names( lines )
|
|
33
|
+
## join all words together into a single string e.g.
|
|
34
|
+
## January|Jan|February|Feb|March|Mar|April|Apr|May|June|Jun|...
|
|
35
|
+
lines.map { |line| line.join('|') }.join('|')
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def self.build_map( lines, downcase: false )
|
|
40
|
+
## note: downcase name!!!
|
|
41
|
+
## build a lookup map that maps the word to the index (line no) plus 1 e.g.
|
|
42
|
+
## {"january" => 1, "jan" => 1,
|
|
43
|
+
## "february" => 2, "feb" => 2,
|
|
44
|
+
## "march" => 3, "mar" => 3,
|
|
45
|
+
## "april" => 4, "apr" => 4,
|
|
46
|
+
## "may" => 5,
|
|
47
|
+
## "june" => 6, "jun" => 6, ...
|
|
48
|
+
lines.each_with_index.reduce( {} ) do |h,(line,i)|
|
|
49
|
+
line.each do |name|
|
|
50
|
+
h[ downcase ? name.downcase : name ] = i+1
|
|
51
|
+
end ## note: start mapping with 1 (and NOT zero-based, that is, 0)
|
|
52
|
+
h
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
MONTH_LINES = parse_names( <<TXT )
|
|
60
|
+
January Jan
|
|
61
|
+
February Feb
|
|
62
|
+
March Mar
|
|
63
|
+
April Apr
|
|
64
|
+
May
|
|
65
|
+
June Jun
|
|
66
|
+
July Jul
|
|
67
|
+
August Aug
|
|
68
|
+
September Sept Sep
|
|
69
|
+
October Oct
|
|
70
|
+
November Nov
|
|
71
|
+
December Dec
|
|
72
|
+
TXT
|
|
73
|
+
|
|
74
|
+
MONTH_NAMES = build_names( MONTH_LINES )
|
|
75
|
+
# pp MONTH_NAMES
|
|
76
|
+
MONTH_MAP = build_map( MONTH_LINES, downcase: true )
|
|
77
|
+
# pp MONTH_MAP
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
DAY_LINES = parse_names( <<TXT )
|
|
82
|
+
Monday Mon Mo
|
|
83
|
+
Tuesday Tues Tue Tu
|
|
84
|
+
Wednesday Wed We
|
|
85
|
+
Thursday Thurs Thur Thu Th
|
|
86
|
+
Friday Fri Fr
|
|
87
|
+
Saturday Sat Sa
|
|
88
|
+
Sunday Sun Su
|
|
89
|
+
TXT
|
|
90
|
+
|
|
91
|
+
DAY_NAMES = build_names( DAY_LINES )
|
|
92
|
+
# pp DAY_NAMES
|
|
93
|
+
DAY_MAP = build_map( DAY_LINES, downcase: true )
|
|
94
|
+
# pp DAY_MAP
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
#=>
|
|
98
|
+
# "January|Jan|February|Feb|March|Mar|April|Apr|May|June|Jun|
|
|
99
|
+
# July|Jul|August|Aug|September|Sept|Sep|October|Oct|
|
|
100
|
+
# November|Nov|December|Dec"
|
|
101
|
+
#
|
|
102
|
+
# "Monday|Mon|Mo|Tuesday|Tues|Tue|Tu|Wednesday|Wed|We|
|
|
103
|
+
# Thursday|Thurs|Thur|Thu|Th|Friday|Fri|Fr|
|
|
104
|
+
# Saturday|Sat|Sa|Sunday|Sun|Su"
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
end # class Lexer
|
|
108
|
+
end # module SportDb
|