fbtxt-parser 0.9.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.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +4 -0
  3. data/Manifest.txt +50 -0
  4. data/README.md +22 -0
  5. data/Rakefile +53 -0
  6. data/lib/fbtxt/parser/debuggable.rb +53 -0
  7. data/lib/fbtxt/parser/lexer-logger.rb +20 -0
  8. data/lib/fbtxt/parser/lexer-on_goal.rb +167 -0
  9. data/lib/fbtxt/parser/lexer-on_group_def.rb +31 -0
  10. data/lib/fbtxt/parser/lexer-on_prop_lineup.rb +79 -0
  11. data/lib/fbtxt/parser/lexer-on_prop_misc.rb +123 -0
  12. data/lib/fbtxt/parser/lexer-on_prop_penalties.rb +40 -0
  13. data/lib/fbtxt/parser/lexer-on_round_def.rb +37 -0
  14. data/lib/fbtxt/parser/lexer-on_top.rb +133 -0
  15. data/lib/fbtxt/parser/lexer-prep_doc.rb +131 -0
  16. data/lib/fbtxt/parser/lexer-prep_line.rb +63 -0
  17. data/lib/fbtxt/parser/lexer-tokenize.rb +468 -0
  18. data/lib/fbtxt/parser/lexer.rb +231 -0
  19. data/lib/fbtxt/parser/lexer_buffer.rb +68 -0
  20. data/lib/fbtxt/parser/lexer_token.rb +126 -0
  21. data/lib/fbtxt/parser/parse_tree--core.rb +29 -0
  22. data/lib/fbtxt/parser/parse_tree-match.rb +309 -0
  23. data/lib/fbtxt/parser/parse_tree-props.rb +233 -0
  24. data/lib/fbtxt/parser/parse_tree.rb +202 -0
  25. data/lib/fbtxt/parser/parser-runtime.rb +379 -0
  26. data/lib/fbtxt/parser/parser-top.rb +102 -0
  27. data/lib/fbtxt/parser/parser.rb +2343 -0
  28. data/lib/fbtxt/parser/token-date--helpers.rb +130 -0
  29. data/lib/fbtxt/parser/token-date--names.rb +108 -0
  30. data/lib/fbtxt/parser/token-date.rb +200 -0
  31. data/lib/fbtxt/parser/token-date_duration.rb +171 -0
  32. data/lib/fbtxt/parser/token-geo.rb +134 -0
  33. data/lib/fbtxt/parser/token-goals--helpers.rb +114 -0
  34. data/lib/fbtxt/parser/token-goals.rb +306 -0
  35. data/lib/fbtxt/parser/token-group.rb +29 -0
  36. data/lib/fbtxt/parser/token-note.rb +40 -0
  37. data/lib/fbtxt/parser/token-prop.rb +309 -0
  38. data/lib/fbtxt/parser/token-prop_name.rb +83 -0
  39. data/lib/fbtxt/parser/token-round.rb +88 -0
  40. data/lib/fbtxt/parser/token-score--helpers.rb +189 -0
  41. data/lib/fbtxt/parser/token-score.rb +60 -0
  42. data/lib/fbtxt/parser/token-score_full.rb +331 -0
  43. data/lib/fbtxt/parser/token-score_fuller.rb +434 -0
  44. data/lib/fbtxt/parser/token-score_legs.rb +59 -0
  45. data/lib/fbtxt/parser/token-status.rb +192 -0
  46. data/lib/fbtxt/parser/token-status_inline.rb +112 -0
  47. data/lib/fbtxt/parser/token-text.rb +221 -0
  48. data/lib/fbtxt/parser/token-time.rb +144 -0
  49. data/lib/fbtxt/parser/token.rb +224 -0
  50. data/lib/fbtxt/parser/version.rb +24 -0
  51. data/lib/fbtxt/parser.rb +140 -0
  52. metadata +145 -0
@@ -0,0 +1,309 @@
1
+ ###
2
+ ## team prop mode e.g.
3
+ ##
4
+ ##
5
+ ## Fri Jun 14 21:00 @ München Fußball Arena, München
6
+ ## Germany v Scotland 5-1 (3-0)
7
+ ## (Wirtz 10' Musiala 19' Havertz 45+1' (pen.) Füllkrug 68' Can 90+3'; Rüdiger 87' (o.g.))
8
+ ##
9
+ ## Germany: Neuer - Kimmich, Rüdiger, Tah [Y], Mittelstädt - Andrich [Y] (Groß 46'),
10
+ ## Kroos (Can 80') - Musiala (Müller 74'), Gündogan, Wirtz (Sane 63') -
11
+ ## Havertz (Füllkrug 63')
12
+ ## Scotland: Gunn - Porteous [R 44'], Hendry, Tierney (McKenna 78') - Ralston [Y],
13
+ ## McTominay, McGregor (Gilmour 67'), Robertson - Christie (Shankland 82'),
14
+ ## Adams (Hanley 46'), McGinn (McLean 67')
15
+
16
+
17
+ module Fbtxt
18
+ class Lexer
19
+
20
+
21
+ ##############
22
+ # add support for props/ attributes e.g.
23
+ #
24
+ # Germany: Neuer - Kimmich, Rüdiger, Tah [Y], Mittelstädt - Andrich [Y] (46' Groß),
25
+ # Kroos (80' Can) - Musiala (74' Müller), Gündogan,
26
+ # Wirtz (63' Sane) - Havertz (63' Füllkrug)
27
+ # Scotland: Gunn - Porteous [R 44'], Hendry, Tierney (78' McKenna) - Ralston [Y],
28
+ # McTominay, McGregor (67' Gilmour), Robertson - Christie (82' Shankland),
29
+ # Adams (46' Hanley), McGinn (67' McLean)
30
+ #
31
+ ## note: colon (:) MUST be followed by one (or more) spaces
32
+ ## make sure mon feb 12 18:10 will not match
33
+ ## allow 1. FC Köln etc.
34
+ ## Mainz 05:
35
+ ## limit to 30 chars max
36
+ ## only allow chars incl. intl but (NOT ()[]/;)
37
+ ##
38
+ ##
39
+ ## note - use special \G - Matches first matching position !!!!
40
+ ## check for \G like backreference of regex tokens/parts if possible/available in ruby?
41
+
42
+
43
+
44
+ ## (i) starting w/ letters
45
+ ## note - incl./allows digits (0-9)
46
+ ## e.g. a1, a2000, etc.
47
+ ##
48
+ ## note - added back optional trailing dot (.) for abbrev. word !!!
49
+ PROP_KEY_WORD_ = %r{
50
+ \p{L}
51
+ [\p{L}\d]*
52
+ \.?
53
+ }ix
54
+
55
+ ## note - incl. optional dot or numsign e.g. 1. or 1°
56
+ PROP_KEY_NUM_ = %r{
57
+ \d+
58
+ [.°]?
59
+ }ix
60
+
61
+ ## e.g. 1A, 1FC etc.
62
+ ## note - no trailing dot (.) for now - check if any cases exist in real world
63
+ PROP_KEY_NUMALPHA_ = %r{
64
+ \d+
65
+ \p{L}
66
+ [\p{L}\d]*
67
+ }ix
68
+
69
+
70
+
71
+
72
+
73
+ START_WITH_PROP_KEY_RE = %r{
74
+ \A ## note - MUST start line; leading spaces optional (eat-up)
75
+ (?<prop_key>
76
+ [ ]* ## optional leading spaces
77
+ (?<key>
78
+ (?:
79
+ ## (i) starting w/ letters
80
+ #{PROP_KEY_WORD_}
81
+
82
+ ## (ii) starting w/ number
83
+ ## e.g. 1fc, 1a,
84
+ | #{PROP_KEY_NUMALPHA_}
85
+ ## followed by optional dot) and
86
+ ## optional space
87
+ ## MUST be follow by letter (a to z)!!!!
88
+ ## eg. 1[ fc], 1.[ fc], 1.[fc], etc.
89
+ | #{PROP_KEY_NUM_} (?= [ ]? \p{L})
90
+ )
91
+ (?:
92
+ ## connectors - note - no dot (.), must match with abbrev word or num!!
93
+ (?: ## (i) single space or WITHOUT surrounding spaces!! - slash (/), dash (-)
94
+ ## e.g. do NOT match one - two or one / two
95
+ ## only one-two or one/two
96
+
97
+ [ /-]
98
+
99
+ ## (ii) surrounded by leading or trailing optional space
100
+ ## c & a, etc.
101
+ ## d'ivoire, d' ivoire
102
+ ## borusia 'gladbach etc.
103
+ ## exclude space ' space - why? why not? (or ignore for now)
104
+ ##
105
+ ## check for quotes ('') - not realy supported here
106
+ ## e.g. leading or trailing ' will NOT match
107
+
108
+ | [ ]? & [ ]?
109
+ | [ ]? '
110
+ | ' [ ]?
111
+
112
+ #### (iii)
113
+ ## note - special "hack" to connect WITHOUT space
114
+ ## for Union 1.FC and SKN St.Pölten or St.Pölten
115
+ ## connects 1.FC => NUM+WORD
116
+ ## 1°Mayo => NUM+WORD
117
+ ## St.Pölten => ABBREV+WORD
118
+ ##
119
+ ## note - match WITHOUT (space) connector
120
+ ## 1.FC (Union 1.FC Stein)
121
+ ## [WORD: "Union"], [NUM: "1."], [WORD: "FC"]
122
+ ## St.Pölten (SKN St.Pölten)
123
+ ## [WORD: "SKN"], [ABBREV: "St."], [WORD: "Pölten"]
124
+ | (?<= [.°] )
125
+ (?= \p{L})
126
+ )
127
+ (?:
128
+ #{PROP_KEY_NUMALPHA_}
129
+ | #{PROP_KEY_NUM_}
130
+ | #{PROP_KEY_WORD_}
131
+ )
132
+ )*
133
+ ) ## close <key> capture
134
+ [ ]*? ## slurp trailing spaces
135
+ :
136
+
137
+ ## positive lookahead (must be followed by space!!)
138
+ ## or allow end-of-line too
139
+ (?= [ ]+|$)
140
+ ) ## close <prop_key> capture
141
+ }ix
142
+
143
+
144
+
145
+
146
+
147
+ ################
148
+ ## todo/check - use token for card short cuts?
149
+ ## if m[:name] == 'Y'
150
+ ## [:YELLOW_CARD, m[:name]]
151
+ ## elsif m[:name] == 'R'
152
+ ## [:RED_CARD, m[:name]]
153
+ ## - [Y], [R], [Y/R] Yellow-Red Card
154
+ ## check if minutes possible inside [Y 46']
155
+ ## add [c] for captain too
156
+
157
+
158
+ ## [c] or [C] for marking player as captain
159
+ ## support [y ] too - or require Y - why? why not?
160
+ INLINE_CAPTAIN = %r{ (?<inline_captain>
161
+ \[ [cC] \]
162
+ )}x
163
+
164
+ INLINE_YELLOW = %r{ (?<inline_yellow>
165
+ \[ [yY]
166
+ ## optional minute
167
+ (?: [ ]+
168
+ (?<minute> \d{1,3})
169
+ '?
170
+ (?:
171
+ \+
172
+ (?<offset>\d{1,2})
173
+ '?
174
+ )?
175
+ )?
176
+ \]
177
+ )}x
178
+
179
+ INLINE_RED = %r{ (?<inline_red>
180
+ \[ [rR]
181
+ ## optional minute
182
+ (?: [ ]+
183
+ (?<minute> \d{1,3})
184
+ '?
185
+ (?:
186
+ \+
187
+ (?<offset>\d{1,2})
188
+ '?
189
+ )?
190
+ )?
191
+ \]
192
+ )}x
193
+
194
+ INLINE_YELLOW_RED = %r{ (?<inline_yellow_red>
195
+ \[ (?:y/r |
196
+ Y/R )
197
+ ## optional minute
198
+ (?: [ ]+
199
+ (?<minute> \d{1,3})
200
+ '?
201
+ (?:
202
+ \+
203
+ (?<offset>\d{1,2})
204
+ '?
205
+ )?
206
+ )?
207
+ \]
208
+ )}x
209
+
210
+
211
+
212
+
213
+ ### simple prop key for inline use e.g.
214
+ ### Coach: or Trainer: or ... add more here later
215
+
216
+ PROP_KEY_INLINE_RE = %r{
217
+ \b
218
+ (?<prop_key> ## note: use prop_key (NOT prop_key_inline or such)
219
+ (?<key>
220
+ \p{L}+
221
+ )
222
+ ## note - NO spaces allowed for key for now!!!
223
+ :
224
+ ## possitive lookahead (must be followed by space!!)
225
+ (?=[ ]+)
226
+ )
227
+ }ix
228
+
229
+
230
+
231
+ ## note allow underscore inline e.g.
232
+ ## 5_000
233
+ ## discuss/check - allow space inline (e.g. 5 000) - why? why not?
234
+
235
+ PROP_NUM_RE = %r{
236
+ \b
237
+ (?<num>
238
+ (?<value> [0-9]+
239
+ (?: _ [0-9]+)*
240
+ )
241
+ )
242
+ \b
243
+ }x
244
+
245
+
246
+ ### todo/fix - allow more chars in enclosed name - why? why not?
247
+ ## e.g. (') - Cote D'Ivore etc.
248
+ ## change to PAREN_NAME or PARENTHESIS or such - why? why not?
249
+ ENCLOSED_NAME_RE = %r{
250
+ (?<enclosed_name>
251
+ \(
252
+ (?<name>
253
+ \p{L}+
254
+ (?:
255
+ [ ]
256
+ \p{L}+
257
+ )*
258
+ )
259
+ \)
260
+ )
261
+ }ix
262
+
263
+
264
+
265
+
266
+ ###
267
+ ## e.g. -; ... or
268
+ ## None - ... or
269
+ CARDS_NONE_LEFT_RE = %r{ (?<cards_none_left>
270
+ ## (i) w/ semicolon (;)
271
+ (?: (?: - | \bnone)
272
+ [ ]* ;
273
+ )
274
+ ## (ii) w/ dash (-)
275
+ | (?: (?: ∅ | \bnone)
276
+ [ ]+ - ## space REQUIRED
277
+ (?=[ ]|\z) ## positive lookahead - speace required
278
+ )
279
+ )}ix
280
+
281
+ ## e.g ... ;-
282
+ ## or ... ; None
283
+ CARDS_NONE_RIGHT_RE = %r{ (?<cards_none_right>
284
+ ## (i) w/ semicolon (;)
285
+ (?: ; [ ]*
286
+ (?: - | none\b)
287
+ )
288
+ ## (ii) w/ dash (-)
289
+ | (?:
290
+ (?<=[ ]) ## positive lookbehind - space required
291
+ - [ ]+ ## space REQUIRED
292
+ (?: ∅ | none\b)
293
+ )
294
+ )}ix
295
+
296
+
297
+ CARDS_SEP_ALT_RE = %r{(?<cards_sep_alt>
298
+ (?<=[ ]) ## positive lookbehind - space required
299
+ -
300
+ (?=[ ]|\z) ## positive lookahead - speace required
301
+ )}x
302
+
303
+
304
+
305
+
306
+
307
+
308
+ end # class Lexer
309
+ end # module Fbtxt
@@ -0,0 +1,83 @@
1
+ module Fbtxt
2
+ class Lexer
3
+
4
+
5
+ ##
6
+ ## see token-text for TEXT_RE
7
+ ## change PROP_NAME_RE to TEXT_II or TEXT_??? - why? why not?
8
+ ### no do NO change
9
+ ## change TEXT_RE to TEAM_RE or TEAM_NAME_RE !!!!
10
+ ## it is NOT generic TEXT regex!!!
11
+
12
+
13
+
14
+
15
+ PROP_NAME_WORD_ = %r{
16
+ \p{L}+
17
+ \.? ## optional dot
18
+ }ix
19
+
20
+
21
+ ## todo/fix - remove support for double quotes e.g. "Rodri" - why? why not?
22
+ ##
23
+
24
+ ## name different from text (**does NOT allow number in name/text**)
25
+ ## different from PROP_KEY too
26
+ PROP_NAME_RE = %r{
27
+ (?<prop_name>
28
+ \b
29
+ (?<name>
30
+ #{PROP_NAME_WORD_}
31
+
32
+ ## connectors
33
+ (?:
34
+ ## (i) space - only one single space allowed inline!!!
35
+ (?:
36
+ ### check if negative lookbehind is redudant!!
37
+ ## next char is \p{L} and NOT space
38
+ ## thus double space not possible!!
39
+ (?<! [ ]) ## use negative lookbehind
40
+ [ ]
41
+ (?= \p{L}|['"]\p{L}) ## use lookahead
42
+ )
43
+ ## (ii) support (inline) quoted name e.g. "Rodri" or such
44
+ | (?:
45
+ (?<=[ ]) ## use positive lookbehind
46
+ " \p{L}+ "
47
+ ## require space here too - why? why not?
48
+ )
49
+ ## (iii) dash (-)
50
+ | (?:
51
+ ## use POSITIVE lookBEHIND
52
+ ## note - allow leading dot (.) e.g. K.-H.Förster
53
+ ## short for Karl-Heinz Förster
54
+ ##
55
+ ## change to negative lookBEHIND [ '"-]
56
+ ## \p{L}\. | \p{L} - not MUST be fixed size
57
+ (?<=
58
+ [\p{L}.]
59
+ )
60
+ [-] ## must be surrounded by letters
61
+ ## e.g. One-Two NOT
62
+ ## One- Two or One - Two or One -Two etc.
63
+ (?= \p{L}) ## use lookahead
64
+ )
65
+ |
66
+ (?: ## flex rule for quote - allow any
67
+ ## only check for double quotes e.g. cannot follow other ' for now - why? why not?
68
+ ## allows rodrigez 'rodri' for example
69
+ (?<!') ## use negative lookbehind
70
+ '
71
+ )
72
+ | ## standard case with letter(s) and optional dot
73
+ #{PROP_NAME_WORD_}
74
+ )*
75
+ )
76
+ ## add lookahead - must be non-alphanum
77
+ ## add colon (:) too - why? why not?
78
+ (?= [ ,;\]\)]|$)
79
+ )}ix
80
+
81
+
82
+ end # class Lexer
83
+ end # module Fbtxt
@@ -0,0 +1,88 @@
1
+ module Fbtxt
2
+ class Lexer
3
+
4
+ ####
5
+ #
6
+ ## note - use \A (instead of ^) - \A strictly matches the start of the string.
7
+ ##
8
+ ## todo - add support for trailing markers e.g.
9
+ ## ▪ Round 1 ▪▪▪▪▪▪▪▪
10
+ ## :: Round 1 ::::::::::::
11
+ ##
12
+ ## check - allow without space (like in heading =Heading 1=) - why? why not?
13
+ ## ▪Round 1▪▪▪▪▪▪▪▪
14
+ ## ::Round 1::::::::::::
15
+
16
+ ROUND_OUTLINE_I_RE = %r{ \A
17
+ [ ]* ## ignore leading spaces (if any)
18
+ (?<round_marker>
19
+ [▪]{1,3} ## BLACK SMALL SQUARE e.g. ▪,▪▪,▪▪▪
20
+ )
21
+ [ ]+
22
+ (?<round_outline>
23
+ ## must start with letter - why? why not?
24
+ ### 1st round
25
+ ## allow numbers e.g. Group A - 1
26
+ ##
27
+ ## note - CANNOT incl. :| !!!
28
+ ## used for markers for defs/definitions
29
+ [^:|]+? ## use non-greedy
30
+ )
31
+ (?:
32
+ [ ]+
33
+ [▪]+
34
+ )?
35
+ [ ]* ## ignore trailing spaces (if any)
36
+ \z
37
+ }xi
38
+
39
+ ROUND_OUTLINE_II_RE = %r{ \A
40
+ [ ]* ## ignore leading spaces (if any)
41
+ (?<round_marker>
42
+ ::{1,3} ## e.g. ::,:::,::::
43
+ )
44
+ [ ]+
45
+ (?<round_outline>
46
+ ## must start with letter - why? why not?
47
+ ### 1st round
48
+ ## allow numbers e.g. Group A - 1
49
+ ##
50
+ ## note - CANNOT incl. :| !!!
51
+ ## used for markers for defs/definitions
52
+ [^:|]+? ## use non-greedy
53
+ )
54
+ (?:
55
+ [ ]+
56
+ ::+
57
+ )?
58
+ [ ]* ## ignore trailing spaces (if any)
59
+ \z
60
+ }xi
61
+
62
+ ROUND_OUTLINE_RE = Regexp.union( ROUND_OUTLINE_I_RE,
63
+ ROUND_OUTLINE_II_RE,
64
+ )
65
+
66
+
67
+ ###
68
+ # note - for def(initions) only one level support
69
+ # that is, no round outline additions possible (e.g ▪▪ 1st leg etc.)
70
+ ROUND_DEF_OUTLINE_RE = %r{ \A
71
+ [ ]* ## ignore leading spaces (if any)
72
+ (?: [▪] ## BLACK SMALL SQUARE
73
+ |
74
+ :: )
75
+ [ ]+
76
+ (?<round_outline>
77
+ [^:|]+? ## use non-greedy
78
+ )
79
+ [ ]* ## ignore trailing spaces (if any)
80
+ ### possitive lookahead MUST be : OR |
81
+ (?= [:|]
82
+ [ ]) ## note: requires space for now after [:|] - keep - why? why not?
83
+ }ix
84
+
85
+
86
+
87
+ end # class Lexer
88
+ end # module Fbtxt
@@ -0,0 +1,189 @@
1
+ module Fbtxt
2
+ class Lexer
3
+
4
+
5
+ def self._build_score( m )
6
+ ## note - score is "generic"
7
+ ## might be full-time (ft) or
8
+ ## after extra-time (aet) or such
9
+ ## or even undecided/unknown
10
+ ## thus, use score1/score2 and NOT ft1/ft2
11
+ ## thus, use (simply an) array e.g. [1,2]
12
+ ## and NOT hash (table) e.g. { ft: [1,2] } !!!
13
+
14
+ score = [m[:score1].to_i(10),
15
+ m[:score2].to_i(10)]
16
+
17
+ score
18
+ end
19
+
20
+ def self._build_score_awd( m ) # score awarded (awd/awd.)
21
+ ### note - use "generic" score for now
22
+ ## to match A 3-0 B [awarded] etc.
23
+ score = [m[:score1].to_i(10),
24
+ m[:score2].to_i(10)]
25
+ ## add score[:awarded] = true ???
26
+ ## note - for now uses its own token e.g SCORE_AWD
27
+ score
28
+ end
29
+
30
+ def self._build_score_abd( m ) # score abandonded (abd/abd.)
31
+ ### note - use "generic" score for now
32
+ score = [m[:score1].to_i(10),
33
+ m[:score2].to_i(10)]
34
+ ## add score[:abd] = true ???
35
+ ## note - for now uses its own token e.g SCORE_ABD
36
+ score
37
+ end
38
+
39
+
40
+ def self._build_score_full( m )
41
+ score = {}
42
+ score[:p] = [m[:p1].to_i(10),
43
+ m[:p2].to_i(10)] if m[:p1] && m[:p2]
44
+ score[:et] = [m[:et1].to_i(10),
45
+ m[:et2].to_i(10)] if m[:et1] && m[:et2]
46
+ score[:ft] = [m[:ft1].to_i(10),
47
+ m[:ft2].to_i(10)] if m[:ft1] && m[:ft2]
48
+ score[:ht] = [m[:ht1].to_i(10),
49
+ m[:ht2].to_i(10)] if m[:ht1] && m[:ht2]
50
+
51
+ ## add golden/silver flags
52
+ score[:golden] = true if m[:aetgg] ## golden goal (gg)/sudden death (sd)
53
+ score[:silver] = true if m[:aetsg] ## silver goal (sg)
54
+
55
+ score
56
+ end
57
+
58
+ def self._build_score_fuller( m )
59
+ score = {}
60
+ score[:p] = [m[:p1].to_i(10),
61
+ m[:p2].to_i(10)] if m[:p1] && m[:p2]
62
+ score[:et] = [m[:et1].to_i(10),
63
+ m[:et2].to_i(10)] if m[:et1] && m[:et2]
64
+ score[:ft] = [m[:ft1].to_i(10),
65
+ m[:ft2].to_i(10)] if m[:ft1] && m[:ft2]
66
+ score[:ht] = [m[:ht1].to_i(10),
67
+ m[:ht2].to_i(10)] if m[:ht1] && m[:ht2]
68
+ score[:agg] = [m[:agg1].to_i(10),
69
+ m[:agg2].to_i(10)] if m[:agg1] && m[:agg2]
70
+
71
+ if m[:away1] && m[:away2]
72
+ score[:away] = [m[:away1].to_i(10),
73
+ m[:away2].to_i(10)]
74
+ elsif m[:away] ## fallback if no away score; check away flag
75
+ score[:away] = true
76
+ end
77
+
78
+ ## add golden/silver flags
79
+ score[:golden] = true if m[:aetgg] ## golden goal (gg)/sudden death (sd)
80
+ score[:silver] = true if m[:aetsg] ## silver goal (sg)
81
+
82
+ score
83
+ end
84
+
85
+
86
+ def self._build_score_fuller_more( m )
87
+ ## SCORE + SCORE_FULLER_MORE
88
+ ## note - after extra-time (aet) or full-time (ft)
89
+ ## score may be present in SCORE!!!
90
+ score = {}
91
+ score[:p] = [m[:p1].to_i(10),
92
+ m[:p2].to_i(10)] if m[:p1] && m[:p2]
93
+ score[:et] = [m[:et1].to_i(10),
94
+ m[:et2].to_i(10)] if m[:et1] && m[:et2]
95
+ score[:ft] = [m[:ft1].to_i(10),
96
+ m[:ft2].to_i(10)] if m[:ft1] && m[:ft2]
97
+ score[:ht] = [m[:ht1].to_i(10),
98
+ m[:ht2].to_i(10)] if m[:ht1] && m[:ht2]
99
+ score[:agg] = [m[:agg1].to_i(10),
100
+ m[:agg2].to_i(10)] if m[:agg1] && m[:agg2]
101
+
102
+ if m[:away1] && m[:away2]
103
+ score[:away] = [m[:away1].to_i(10),
104
+ m[:away2].to_i(10)]
105
+ elsif m[:away] ## fallback if no away score; check away flag
106
+ score[:away] = true
107
+ end
108
+
109
+ ## add golden/silver flags
110
+ score[:golden] = true if m[:aetgg] ## golden goal (gg)/sudden death (sd)
111
+ score[:silver] = true if m[:aetsg] ## silver goal (sg)
112
+
113
+ ## add flag in score for et/ft/ht
114
+ ## used for "dangling" (generic) score
115
+ score[:score] = 'et' if m[:aet] || m[:aetgg] || m[:aetsg]
116
+ score[:score] = 'ft' if m[:ft]
117
+ score[:score] = 'ht' if m[:ht]
118
+
119
+ score
120
+ end
121
+
122
+
123
+ def self._build_score_legs( m )
124
+ legs = {}
125
+
126
+ ############
127
+ ### build leg1 (score)
128
+ score = {}
129
+ score[:ft] = [m[:leg1_ft1].to_i(10),
130
+ m[:leg1_ft2].to_i(10)]
131
+ legs['leg1'] = score
132
+
133
+ ##################
134
+ ### build leg2 (score)
135
+ score = {}
136
+ score[:ft] = [m[:leg2_ft1].to_i(10),
137
+ m[:leg2_ft2].to_i(10)] if m[:leg2_ft1] && m[:leg2_ft2]
138
+ score[:et] = [m[:leg2_et1].to_i(10),
139
+ m[:leg2_et2].to_i(10)] if m[:leg2_et1] && m[:leg2_et2]
140
+ score[:p] = [m[:leg2_p1].to_i(10),
141
+ m[:leg2_p2].to_i(10)] if m[:leg2_p1] && m[:leg2_p2]
142
+ legs['leg2'] = score
143
+
144
+ ## check for (opt) aggregate - keep on "top-level"
145
+ legs[:agg] = [m[:agg1].to_i(10),
146
+ m[:agg2].to_i(10)] if m[:agg1] && m[:agg2]
147
+ legs[:away] = true if m[:away]
148
+
149
+ legs
150
+ end
151
+
152
+
153
+ def _build_score( m ) self.class._build_score( m ); end
154
+ def _build_score_awd( m ) self.class._build_score_awd( m ); end
155
+ def _build_score_abd( m ) self.class._build_score_abd( m ); end
156
+ def _build_score_full( m ) self.class._build_score_full( m ); end
157
+ def _build_score_fuller( m ) self.class._build_score_fuller( m ); end
158
+ def _build_score_fuller_more( m ) self.class._build_score_fuller_more( m ); end
159
+ def _build_score_legs( m ) self.class._build_score_legs( m ); end
160
+
161
+
162
+
163
+
164
+ ###
165
+ ## add parser helpers
166
+
167
+ def self._parse_score_full( str )
168
+ ## note - strip - leading/trailing spaces automatic - why? why not?
169
+
170
+ m = Regexp.union(
171
+ SCORE_FULL_1ST_RE,
172
+ SCORE_FULL_RE ).match( str.strip )
173
+
174
+ if m && m.pre_match == '' && m.post_match == ''
175
+ pp m
176
+ _build_score_full( m )
177
+ elsif m
178
+ ## note - match BUT not anchored to start and end-of-string!!!
179
+ ## report, error somehow??
180
+ nil
181
+ else
182
+ nil ## no match - return nil
183
+ end
184
+ end
185
+
186
+
187
+
188
+ end # class Lexer
189
+ end # module Fbtxt