sportdb-parser 0.7.1 → 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 +17 -4
- 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 -1403
- 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 +45 -17
- metadata +19 -6
- 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,61 +5,70 @@
|
|
|
5
5
|
class RaccMatchParser
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
@tree = []
|
|
8
|
+
|
|
9
|
+
def initialize( txt, debug: false )
|
|
10
|
+
@tree = []
|
|
13
11
|
@errors = []
|
|
14
12
|
|
|
15
|
-
### todo:
|
|
16
|
-
## - pass along debug flag
|
|
17
13
|
lexer = SportDb::Lexer.new( txt, debug: debug )
|
|
18
14
|
## note - use tokenize_with_errors and add/collect tokenize errors
|
|
19
15
|
@tokens, @errors = lexer.tokenize_with_errors
|
|
20
16
|
## pp @tokens
|
|
21
|
-
|
|
22
|
-
## quick hack - convert to racc format single char literal tokens e.g. '@' etc.
|
|
23
|
-
@tokens = @tokens.map do |tok|
|
|
24
|
-
if tok.size == 1
|
|
25
|
-
[tok[0].to_s, tok[0].to_s]
|
|
26
|
-
else
|
|
27
|
-
tok
|
|
28
|
-
end
|
|
29
|
-
end
|
|
17
|
+
|
|
30
18
|
end
|
|
31
19
|
|
|
32
20
|
|
|
33
21
|
def debug( value ) @debug = value; end ### fix: use setter-style e.g. debug=(value) !!!
|
|
34
22
|
def debug?() @debug == true; end
|
|
35
23
|
|
|
24
|
+
###
|
|
25
|
+
### fix-fix-fix rename to _trace
|
|
26
|
+
## check lexer - add [debug] Parser - or such!!!
|
|
27
|
+
##
|
|
36
28
|
## debug - trace / print message
|
|
37
29
|
def trace( msg )
|
|
38
|
-
|
|
30
|
+
puts " fix-fix-fix use _trace() in parser!!"
|
|
31
|
+
puts " [parse] " + msg
|
|
39
32
|
end
|
|
40
33
|
|
|
41
|
-
|
|
34
|
+
def _trace( *args )
|
|
35
|
+
## if debug?
|
|
36
|
+
print "[DEBUG] Parser -- "
|
|
37
|
+
args.each { |arg| puts args }
|
|
38
|
+
## end
|
|
39
|
+
end
|
|
42
40
|
|
|
43
41
|
|
|
44
42
|
def next_token
|
|
45
43
|
tok = @tokens.shift
|
|
46
|
-
|
|
44
|
+
_trace( "next_token => #{tok.pretty_inspect}" )
|
|
45
|
+
|
|
46
|
+
## convert to racc format single char literal tokens e.g. '@' etc.
|
|
47
|
+
## note - literal token MUST be string (NOT symbol)
|
|
48
|
+
## note - racc expects array with to items
|
|
49
|
+
## - item[0] is the token id
|
|
50
|
+
## - item[1] is the token value
|
|
51
|
+
|
|
52
|
+
## note - returns nil for end-of-file !!!
|
|
53
|
+
tok = [tok.type, tok] if tok
|
|
54
|
+
|
|
47
55
|
tok
|
|
48
56
|
end
|
|
49
|
-
|
|
57
|
+
|
|
58
|
+
|
|
50
59
|
# on_error do |error_token_id, error_value, value_stack|
|
|
51
60
|
# puts "Parse error on token: #{error_token_id}, value: #{error_value}"
|
|
52
|
-
# end
|
|
61
|
+
# end
|
|
53
62
|
|
|
54
|
-
def parse_with_errors
|
|
55
|
-
|
|
63
|
+
def parse_with_errors
|
|
64
|
+
_trace( "start parse:" )
|
|
56
65
|
do_parse
|
|
57
66
|
[@tree, @errors]
|
|
58
67
|
end
|
|
59
68
|
|
|
60
69
|
def parse ## convenience shortcut (ignores errors)
|
|
61
70
|
tree, _ = parse_with_errors
|
|
62
|
-
tree
|
|
71
|
+
tree
|
|
63
72
|
end
|
|
64
73
|
|
|
65
74
|
|
|
@@ -69,20 +78,15 @@ def initialize( txt, debug: false )
|
|
|
69
78
|
|
|
70
79
|
def on_error(error_token_id, error_value, value_stack)
|
|
71
80
|
## auto-add error_token (as string)
|
|
72
|
-
error_token = Racc_token_to_s_table[error_token_id]
|
|
81
|
+
error_token = Racc_token_to_s_table[error_token_id]
|
|
73
82
|
args = [error_token, error_token_id, error_value, value_stack]
|
|
83
|
+
|
|
74
84
|
puts
|
|
75
85
|
puts "!! on parse error:"
|
|
76
86
|
puts "args=#{args.pretty_inspect}"
|
|
77
87
|
|
|
78
|
-
@errors << "parse error on token: #{error_token}
|
|
79
|
-
## exit 1 ## exit for now - get and print more info about context etc.!!
|
|
88
|
+
@errors << "parse error on token: #{error_token} >#{error_value.pretty_inspect}<, stack: #{value_stack.pretty_inspect}"
|
|
80
89
|
end
|
|
81
90
|
|
|
82
91
|
|
|
83
|
-
=begin
|
|
84
|
-
on_error do |error_token_id, error_value, value_stack|
|
|
85
|
-
puts "Parse error on token: #{error_token_id}, value: #{error_value}"
|
|
86
|
-
end
|
|
87
|
-
=end
|
|
88
92
|
end # class RaccMatchParser
|
|
@@ -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
|