sportdb-formats 1.1.3 → 1.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Manifest.txt +0 -24
- data/Rakefile +2 -5
- data/lib/sportdb/formats.rb +39 -74
- data/lib/sportdb/formats/event/event_reader.rb +1 -1
- data/lib/sportdb/formats/league/league_outline_reader.rb +18 -6
- data/lib/sportdb/formats/package.rb +2 -2
- data/lib/sportdb/formats/team/club_index_history.rb +2 -6
- data/lib/sportdb/formats/team/club_reader_history.rb +1 -1
- data/lib/sportdb/formats/team/club_reader_props.rb +18 -2
- data/lib/sportdb/formats/version.rb +1 -1
- data/test/helper.rb +3 -0
- metadata +5 -71
- data/lib/sportdb/formats/config.rb +0 -40
- data/lib/sportdb/formats/match/match_parser_csv.rb +0 -458
- data/lib/sportdb/formats/match/match_status_parser.rb +0 -86
- data/lib/sportdb/formats/name_helper.rb +0 -87
- data/lib/sportdb/formats/score/score_formats.rb +0 -239
- data/lib/sportdb/formats/score/score_parser.rb +0 -204
- data/lib/sportdb/formats/season_utils.rb +0 -16
- data/lib/sportdb/formats/structs/country.rb +0 -31
- data/lib/sportdb/formats/structs/group.rb +0 -18
- data/lib/sportdb/formats/structs/league.rb +0 -37
- data/lib/sportdb/formats/structs/match.rb +0 -157
- data/lib/sportdb/formats/structs/matchlist.rb +0 -220
- data/lib/sportdb/formats/structs/round.rb +0 -25
- data/lib/sportdb/formats/structs/season.rb +0 -192
- data/lib/sportdb/formats/structs/standings.rb +0 -268
- data/lib/sportdb/formats/structs/team.rb +0 -157
- data/lib/sportdb/formats/structs/team_usage.rb +0 -88
- data/test/test_clubs.rb +0 -40
- data/test/test_csv_reader.rb +0 -31
- data/test/test_match.rb +0 -30
- data/test/test_match_status_parser.rb +0 -49
- data/test/test_name_helper.rb +0 -67
- data/test/test_scores.rb +0 -124
- data/test/test_season.rb +0 -111
@@ -1,86 +0,0 @@
|
|
1
|
-
#####################
|
2
|
-
# helpers for parsing & finding match status e.g.
|
3
|
-
# - cancelled / canceled
|
4
|
-
# - awarded
|
5
|
-
# - abandoned
|
6
|
-
# - replay
|
7
|
-
# etc.
|
8
|
-
|
9
|
-
|
10
|
-
module SportDb
|
11
|
-
|
12
|
-
class Status
|
13
|
-
# note: use a class as an "enum"-like namespace for now - why? why not?
|
14
|
-
# move class into Match e.g. Match::Status - why? why not?
|
15
|
-
CANCELLED = 'CANCELLED' # canceled (US spelling), cancelled (UK spelling) - what to use?
|
16
|
-
AWARDED = 'AWARDED'
|
17
|
-
POSTPONED = 'POSTPONED'
|
18
|
-
ABANDONED = 'ABANDONED'
|
19
|
-
REPLAY = 'REPLAY'
|
20
|
-
end # class Status
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
class StatusParser
|
25
|
-
|
26
|
-
def self.parse( str )
|
27
|
-
## note: returns nil if no match found
|
28
|
-
## note: english usage - cancelled (in UK), canceled (in US)
|
29
|
-
if str =~ /^(cancelled|
|
30
|
-
canceled|
|
31
|
-
can\.
|
32
|
-
)/xi
|
33
|
-
Status::CANCELLED
|
34
|
-
elsif str =~ /^(awarded|
|
35
|
-
awd\.
|
36
|
-
)/xi
|
37
|
-
Status::AWARDED
|
38
|
-
elsif str =~ /^(postponed
|
39
|
-
)/xi
|
40
|
-
Status::POSTPONED
|
41
|
-
elsif str =~ /^(abandoned|
|
42
|
-
abd\.
|
43
|
-
)/xi
|
44
|
-
Status::ABANDONED
|
45
|
-
elsif str =~ /^(replay
|
46
|
-
)/xi
|
47
|
-
Status::REPLAY
|
48
|
-
else
|
49
|
-
# no match
|
50
|
-
nil
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
|
55
|
-
RUN_RE = /\[
|
56
|
-
(?<text>[^\]]+)
|
57
|
-
\]
|
58
|
-
/x
|
59
|
-
def self.find!( line )
|
60
|
-
## for now check all "protected" text run blocks e.g. []
|
61
|
-
## puts "line: >#{line}<"
|
62
|
-
|
63
|
-
status = nil
|
64
|
-
|
65
|
-
str = line
|
66
|
-
while m = str.match( RUN_RE )
|
67
|
-
str = m.post_match ## keep on processing rest of line/str (a.k.a. post match string)
|
68
|
-
|
69
|
-
## check for status match
|
70
|
-
match_str = m[0] ## keep a copy of the match string (for later sub)
|
71
|
-
text = m[:text].strip
|
72
|
-
## puts " text: >#{text}<"
|
73
|
-
|
74
|
-
status = parse( text )
|
75
|
-
|
76
|
-
if status
|
77
|
-
line.sub!( match_str, "[STATUS.#{status}]" )
|
78
|
-
break
|
79
|
-
end
|
80
|
-
end # while match
|
81
|
-
|
82
|
-
status
|
83
|
-
end # method find!
|
84
|
-
end # class StatusParser
|
85
|
-
|
86
|
-
end # module SportDb
|
@@ -1,87 +0,0 @@
|
|
1
|
-
|
2
|
-
module SportDb
|
3
|
-
module NameHelper
|
4
|
-
|
5
|
-
|
6
|
-
## note: allow placeholder years to e.g. (-___) or (-????)
|
7
|
-
## for marking missing (to be filled in) years
|
8
|
-
## e.g. (1887-1911), (-2013),
|
9
|
-
## (1946-2001, 2013-) etc.
|
10
|
-
## todo/check: make more strict e.g. only accept 4-digit years? - why? why not?
|
11
|
-
YEAR_RE = %r{\(
|
12
|
-
[0-9, ?_-]+? # note: non-greedy (minimum/first) match
|
13
|
-
\)}x
|
14
|
-
|
15
|
-
def strip_year( name )
|
16
|
-
## check for year(s) e.g. (1887-1911), (-2013),
|
17
|
-
## (1946-2001, 2013-) etc.
|
18
|
-
## todo/check: only sub once (not global) - why? why not?
|
19
|
-
name.gsub( YEAR_RE, '' ).strip
|
20
|
-
end
|
21
|
-
|
22
|
-
def has_year?( name ) name =~ YEAR_RE; end
|
23
|
-
|
24
|
-
|
25
|
-
LANG_RE = %r{\[
|
26
|
-
[a-z]{1,2} # note also allow single-letter [a] or [d] or [e] - why? why not?
|
27
|
-
\]}x
|
28
|
-
def strip_lang( name )
|
29
|
-
name.gsub( LANG_RE, '' ).strip
|
30
|
-
end
|
31
|
-
|
32
|
-
def has_lang?( name ) name =~ LANG_RE; end
|
33
|
-
|
34
|
-
|
35
|
-
def sanitize( name )
|
36
|
-
## check for year(s) e.g. (1887-1911), (-2013),
|
37
|
-
## (1946-2001,2013-) etc.
|
38
|
-
name = strip_year( name )
|
39
|
-
## check lang codes e.g. [en], [fr], etc.
|
40
|
-
name = strip_lang( name )
|
41
|
-
name
|
42
|
-
end
|
43
|
-
|
44
|
-
|
45
|
-
## note: also add (),’,− etc. e.g.
|
46
|
-
## Estudiantes (LP) => Estudiantes LP
|
47
|
-
## Saint Patrick’s Athletic FC => Saint Patricks Athletic FC
|
48
|
-
## Myllykosken Pallo −47 => Myllykosken Pallo 47
|
49
|
-
##
|
50
|
-
## add & too!!
|
51
|
-
## e.g. Brighton & Hove Albion => Brighton Hove Albion -- and others in England
|
52
|
-
|
53
|
-
NORM_RE = %r{
|
54
|
-
[.'’º/()&_−-]
|
55
|
-
}x # note: in [] dash (-) if last doesn't need to get escaped
|
56
|
-
## note: remove all dots (.), dash (-), ', º, /, etc.
|
57
|
-
# . U+002E (46) - FULL STOP
|
58
|
-
# ' U+0027 (39) - APOSTROPHE
|
59
|
-
# ’ U+2019 (8217) - RIGHT SINGLE QUOTATION MARK
|
60
|
-
# º U+00BA (186) - MASCULINE ORDINAL INDICATOR
|
61
|
-
# / U+002F (47) - SOLIDUS
|
62
|
-
# ( U+0028 (40) - LEFT PARENTHESIS
|
63
|
-
# ) U+0029 (41) - RIGHT PARENTHESIS
|
64
|
-
# − U+2212 (8722) - MINUS SIGN
|
65
|
-
# - U+002D (45) - HYPHEN-MINUS
|
66
|
-
|
67
|
-
## for norm(alizing) names
|
68
|
-
def strip_norm( name )
|
69
|
-
name.gsub( NORM_RE, '' )
|
70
|
-
end
|
71
|
-
|
72
|
-
def normalize( name )
|
73
|
-
# note: do NOT call sanitize here (keep normalize "atomic" for reuse)
|
74
|
-
name = strip_norm( name )
|
75
|
-
name = name.gsub( ' ', '' ) # note: also remove all spaces!!!
|
76
|
-
|
77
|
-
## todo/check: use our own downcase - why? why not?
|
78
|
-
name = downcase_i18n( name ) ## do NOT care about upper and lowercase for now
|
79
|
-
name
|
80
|
-
end
|
81
|
-
|
82
|
-
|
83
|
-
def variants( name ) Variant.find( name ); end
|
84
|
-
|
85
|
-
end # module NameHelper
|
86
|
-
end # module SportDb
|
87
|
-
|
@@ -1,239 +0,0 @@
|
|
1
|
-
|
2
|
-
module ScoreFormats
|
3
|
-
|
4
|
-
## todo/check: use ‹› (unicode chars) to mark optional parts in regex constant name - why? why not?
|
5
|
-
|
6
|
-
#####
|
7
|
-
# english helpers (penalty, extra time, ...)
|
8
|
-
P_EN = '(?: p | pen\.? | pso )' # e.g. p, pen, pen., PSO, etc.
|
9
|
-
ET_EN = '(?: aet | a\.e\.t\.? )' # note: make last . optional (e.g a.e.t) allowed too
|
10
|
-
|
11
|
-
|
12
|
-
## note: allow SPECIAL cases WITHOUT full time scores (just a.e.t or pen. + a.e.t.)
|
13
|
-
## 3-4 pen. 2-2 a.e.t.
|
14
|
-
## 2-2 a.e.t.
|
15
|
-
EN__P_ET__RE = /\b
|
16
|
-
(?:
|
17
|
-
(?<score1p>\d{1,2})
|
18
|
-
[ ]* - [ ]* # note: sep in optional block; CANNOT use a reference
|
19
|
-
(?<score2p>\d{1,2})
|
20
|
-
[ ]* #{P_EN} [ ]*
|
21
|
-
)? # note: make penalty (P) score optional for now
|
22
|
-
(?<score1et>\d{1,2})
|
23
|
-
[ ]* - [ ]*
|
24
|
-
(?<score2et>\d{1,2})
|
25
|
-
[ ]* #{ET_EN}
|
26
|
-
(?=[ \]]|$)/xi ## todo/check: remove loakahead assertion here - why require space?
|
27
|
-
## note: \b works only after non-alphanum e.g. )
|
28
|
-
|
29
|
-
|
30
|
-
## e.g. 3-4 pen. 2-2 a.e.t. (1-1, 1-1) or
|
31
|
-
## 3-4 pen. 2-2 a.e.t. (1-1, ) or
|
32
|
-
## 3-4 pen. 2-2 a.e.t. (1-1) or
|
33
|
-
## 2-2 a.e.t. (1-1, 1-1) or
|
34
|
-
## 2-2 a.e.t. (1-1, ) or
|
35
|
-
## 2-2 a.e.t. (1-1)
|
36
|
-
|
37
|
-
EN__P_ET_FT_HT__RE = /\b
|
38
|
-
(?:
|
39
|
-
(?<score1p>\d{1,2})
|
40
|
-
[ ]* - [ ]* # note: sep in optional block; CANNOT use a reference
|
41
|
-
(?<score2p>\d{1,2})
|
42
|
-
[ ]* #{P_EN} [ ]*
|
43
|
-
)? # note: make penalty (P) score optional for now
|
44
|
-
(?<score1et>\d{1,2})
|
45
|
-
[ ]* - [ ]*
|
46
|
-
(?<score2et>\d{1,2})
|
47
|
-
[ ]* #{ET_EN} [ ]*
|
48
|
-
\(
|
49
|
-
[ ]*
|
50
|
-
(?<score1>\d{1,2})
|
51
|
-
[ ]* - [ ]*
|
52
|
-
(?<score2>\d{1,2})
|
53
|
-
[ ]*
|
54
|
-
(?:
|
55
|
-
, [ ]*
|
56
|
-
(?: (?<score1i>\d{1,2})
|
57
|
-
[ ]* - [ ]*
|
58
|
-
(?<score2i>\d{1,2})
|
59
|
-
[ ]*
|
60
|
-
)?
|
61
|
-
)? # note: make half time (HT) score optional for now
|
62
|
-
\)
|
63
|
-
(?=[ \]]|$)/xi ## todo/check: remove loakahead assertion here - why require space?
|
64
|
-
## note: \b works only after non-alphanum e.g. )
|
65
|
-
|
66
|
-
###
|
67
|
-
## special case for case WITHOUT extra time!!
|
68
|
-
## same as above (but WITHOUT extra time and pen required)
|
69
|
-
EN__P_FT_HT__RE = /\b
|
70
|
-
(?<score1p>\d{1,2})
|
71
|
-
[ ]* - [ ]* # note: sep in optional block; CANNOT use a reference
|
72
|
-
(?<score2p>\d{1,2})
|
73
|
-
[ ]* #{P_EN} [ ]*
|
74
|
-
\(
|
75
|
-
[ ]*
|
76
|
-
(?<score1>\d{1,2})
|
77
|
-
[ ]* - [ ]*
|
78
|
-
(?<score2>\d{1,2})
|
79
|
-
[ ]*
|
80
|
-
(?:
|
81
|
-
, [ ]*
|
82
|
-
(?: (?<score1i>\d{1,2})
|
83
|
-
[ ]* - [ ]*
|
84
|
-
(?<score2i>\d{1,2})
|
85
|
-
[ ]*
|
86
|
-
)?
|
87
|
-
)? # note: make half time (HT) score optional for now
|
88
|
-
\)
|
89
|
-
(?=[ \]]|$)/xi ## todo/check: remove loakahead assertion here - why require space?
|
90
|
-
## note: \b works only after non-alphanum e.g. )
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
## e.g. 2-1 (1-1) or
|
95
|
-
## 2-1
|
96
|
-
## note: for now add here used in Brazil / Portugal
|
97
|
-
## e.g 1x1 or 1X1 or 0x2 or 3x3 too
|
98
|
-
## todo/check/fix: move to its own use PT__FT_HT etc!!!!
|
99
|
-
|
100
|
-
EN__FT_HT__RE = /\b
|
101
|
-
(?<score1>\d{1,2})
|
102
|
-
[ ]* (?<sep>[x-]) [ ]*
|
103
|
-
(?<score2>\d{1,2})
|
104
|
-
(?:
|
105
|
-
[ ]* \( [ ]*
|
106
|
-
(?<score1i>\d{1,2})
|
107
|
-
[ ]* \k<sep> [ ]*
|
108
|
-
(?<score2i>\d{1,2})
|
109
|
-
[ ]* \)
|
110
|
-
)? # note: make half time (HT) score optional for now
|
111
|
-
(?=[ \]]|$)/xi ## todo/check: remove loakahead assertion here - why require space?
|
112
|
-
## note: \b works only after non-alphanum e.g. )
|
113
|
-
|
114
|
-
|
115
|
-
#####
|
116
|
-
# deutsch / german helpers (penalty, extra time, ...)
|
117
|
-
## todo add more marker e.g. im Elf. or such!!!
|
118
|
-
P_DE = '(?: ie | i\.e\.? )' # e.g. iE, i.E., i.E etc.
|
119
|
-
ET_DE = '(?: nv | n\.v\.? )' # e.g. nV, n.V., n.V etc.
|
120
|
-
|
121
|
-
|
122
|
-
## support alternate all-in-one score e.g.
|
123
|
-
## i.E. 2:4, n.V. 3:3 (1:1, 1:1) or
|
124
|
-
## n.V. 3:2 (2:2, 1:2)
|
125
|
-
DE__P_ET_FT_HT__RE = /\b
|
126
|
-
(?:
|
127
|
-
#{P_DE}
|
128
|
-
[ ]*
|
129
|
-
(?<score1p>\d{1,2})
|
130
|
-
[ ]* : [ ]*
|
131
|
-
(?<score2p>\d{1,2})
|
132
|
-
[ ]* (?:, [ ]*)?
|
133
|
-
)? # note: make penalty (P) score optional for now
|
134
|
-
#{ET_DE}
|
135
|
-
[ ]*
|
136
|
-
(?<score1et>\d{1,2})
|
137
|
-
[ ]* : [ ]*
|
138
|
-
(?<score2et>\d{1,2})
|
139
|
-
[ ]*
|
140
|
-
\(
|
141
|
-
[ ]*
|
142
|
-
(?<score1>\d{1,2})
|
143
|
-
[ ]* : [ ]*
|
144
|
-
(?<score2>\d{1,2})
|
145
|
-
[ ]*
|
146
|
-
(?:
|
147
|
-
, [ ]*
|
148
|
-
(?:
|
149
|
-
(?<score1i>\d{1,2})
|
150
|
-
[ ]* : [ ]*
|
151
|
-
(?<score2i>\d{1,2})
|
152
|
-
[ ]*
|
153
|
-
)?
|
154
|
-
)? # note: make half time (HT) score optional for now
|
155
|
-
\)
|
156
|
-
(?=[ \]]|$)
|
157
|
-
/xi
|
158
|
-
|
159
|
-
## support all-in-one "literal form e.g.
|
160
|
-
# 2:2 (1:1, 1:0) n.V. 5:1 i.E. or
|
161
|
-
# 2-2 (1-1, 1-0) n.V. 5-1 i.E.
|
162
|
-
DE__ET_FT_HT_P__RE = /\b
|
163
|
-
(?<score1et>\d{1,2})
|
164
|
-
[ ]* (?<sep>[:-]) [ ]* ## note: for now allow : or - as separator!!
|
165
|
-
(?<score2et>\d{1,2})
|
166
|
-
[ ]*
|
167
|
-
\(
|
168
|
-
[ ]*
|
169
|
-
(?<score1>\d{1,2})
|
170
|
-
[ ]* \k<sep> [ ]*
|
171
|
-
(?<score2>\d{1,2})
|
172
|
-
[ ]*
|
173
|
-
(?:
|
174
|
-
, [ ]*
|
175
|
-
(?:
|
176
|
-
(?<score1i>\d{1,2})
|
177
|
-
[ ]* \k<sep> [ ]*
|
178
|
-
(?<score2i>\d{1,2})
|
179
|
-
[ ]*
|
180
|
-
)?
|
181
|
-
)? # note: make half time (HT) score optional for now
|
182
|
-
\)
|
183
|
-
[ ]*
|
184
|
-
#{ET_DE}
|
185
|
-
(?:
|
186
|
-
[ ]*
|
187
|
-
(?<score1p>\d{1,2})
|
188
|
-
[ ]* \k<sep> [ ]*
|
189
|
-
(?<score2p>\d{1,2})
|
190
|
-
[ ]*
|
191
|
-
#{P_DE}
|
192
|
-
)? # note: make penalty (P) score optional for now
|
193
|
-
(?=[ \]]|$)
|
194
|
-
/xi ## todo/check: remove loakahead assertion here - why require space?
|
195
|
-
## note: \b works only after non-alphanum e.g. )
|
196
|
-
|
197
|
-
|
198
|
-
## e.g. 2:1 (1:1) or
|
199
|
-
## 2-1 (1-1) or
|
200
|
-
## 2:1 or
|
201
|
-
## 2-1
|
202
|
-
DE__FT_HT__RE = /\b
|
203
|
-
(?<score1>\d{1,2})
|
204
|
-
[ ]* (?<sep>[:-]) [ ]*
|
205
|
-
(?<score2>\d{1,2})
|
206
|
-
(?:
|
207
|
-
[ ]* \( [ ]*
|
208
|
-
(?<score1i>\d{1,2})
|
209
|
-
[ ]* \k<sep> [ ]*
|
210
|
-
(?<score2i>\d{1,2})
|
211
|
-
[ ]* \)
|
212
|
-
)? # note: make half time (HT) score optional for now
|
213
|
-
(?=[ \]]|$)/x ## todo/check: remove loakahead assertion here - why require space?
|
214
|
-
## note: \b works only after non-alphanum e.g. )
|
215
|
-
|
216
|
-
|
217
|
-
#############################################
|
218
|
-
# map tables - 1) regex, 2) tag - note: order matters; first come-first matched/served
|
219
|
-
|
220
|
-
|
221
|
-
FORMATS_EN = [
|
222
|
-
[ EN__P_ET_FT_HT__RE, '[SCORE.EN__P?_ET_(FT_HT?)]' ], # e.g. 5-1 pen. 2-2 a.e.t. (1-1, 1-0)
|
223
|
-
[ EN__P_FT_HT__RE, '[SCORE.EN__P_(FT_HT?)]' ], # e.g. 5-1 pen. (1-1)
|
224
|
-
[ EN__P_ET__RE, '[SCORE.EN__P?_ET]' ], # e.g. 2-2 a.e.t. or 5-1 pen. 2-2 a.e.t.
|
225
|
-
[ EN__FT_HT__RE, '[SCORE.EN__FT_(HT)?]' ], # e.g. 1-1 (1-0)
|
226
|
-
]
|
227
|
-
|
228
|
-
FORMATS_DE = [
|
229
|
-
[ DE__ET_FT_HT_P__RE, '[SCORE.DE__ET_(FT_HT?)_P?]' ], # e.g. 2:2 (1:1, 1:0) n.V. 5:1 i.E.
|
230
|
-
[ DE__P_ET_FT_HT__RE, '[SCORE.DE__P?_ET_(FT_HT?)]' ], # e.g. i.E. 2:4, n.V. 3:3 (1:1, 1:1)
|
231
|
-
[ DE__FT_HT__RE, '[SCORE.DE__FT_(HT)?]' ], # e.g. 1:1 (1:0)
|
232
|
-
]
|
233
|
-
|
234
|
-
FORMATS = {
|
235
|
-
en: FORMATS_EN,
|
236
|
-
de: FORMATS_DE,
|
237
|
-
}
|
238
|
-
|
239
|
-
end # module ScoreFormats
|
@@ -1,204 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
|
4
|
-
## note: lets follow the model of DateFormats -see DateFormats gem for more!!!
|
5
|
-
|
6
|
-
|
7
|
-
## note: make Score top-level and use like Date - why? why not?
|
8
|
-
class Score
|
9
|
-
|
10
|
-
attr_reader :score1i, :score2i, # half time (ht) score
|
11
|
-
:score1, :score2, # full time (ft) score
|
12
|
-
:score1et, :score2et, # extra time (et) score
|
13
|
-
:score1p, :score2p # penalty (p) score
|
14
|
-
## todo/fix: add :score1agg, score2agg too - why? why not?!!!
|
15
|
-
## add state too e.g. canceled or abadoned etc - why? why not?
|
16
|
-
|
17
|
-
def initialize( *values )
|
18
|
-
## note: for now always assumes integers
|
19
|
-
## todo/check - check/require integer args - why? why not?
|
20
|
-
|
21
|
-
@score1i = values[0] # half time (ht) score
|
22
|
-
@score2i = values[1]
|
23
|
-
|
24
|
-
@score1 = values[2] # full time (ft) score
|
25
|
-
@score2 = values[3]
|
26
|
-
|
27
|
-
@score1et = values[4] # extra time (et) score
|
28
|
-
@score2et = values[5]
|
29
|
-
|
30
|
-
@score1p = values[6] # penalty (p) score
|
31
|
-
@score2p = values[7]
|
32
|
-
end
|
33
|
-
|
34
|
-
def to_a
|
35
|
-
## todo: how to handle game w/o extra time
|
36
|
-
# but w/ optional penalty ??? e.g. used in copa liberatores, for example
|
37
|
-
# retrun 0,0 or nil,nil for extra time score ?? or -1, -1 ??
|
38
|
-
# for now use nil,nil
|
39
|
-
score = []
|
40
|
-
score += [score1i, score2i] if score1p || score2p || score1et || score2et || score1 || score2 || score1i || score2i
|
41
|
-
score += [score1, score2] if score1p || score2p || score1et || score2et || score1 || score2
|
42
|
-
score += [score1et, score2et] if score1p || score2p || score1et || score2et
|
43
|
-
score += [score1p, score2p] if score1p || score2p
|
44
|
-
score
|
45
|
-
end
|
46
|
-
|
47
|
-
end # class Score
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
module ScoreFormats
|
52
|
-
|
53
|
-
def self.lang
|
54
|
-
@@lang ||= :en ## defaults to english (:en)
|
55
|
-
end
|
56
|
-
def self.lang=( value )
|
57
|
-
@@lang = value.to_sym ## note: make sure lang is always a symbol for now (NOT a string)
|
58
|
-
@@lang ## todo/check: remove =() method always returns passed in value? double check
|
59
|
-
end
|
60
|
-
|
61
|
-
|
62
|
-
def self.parser( lang: ) ## find parser
|
63
|
-
lang = lang.to_sym ## note: make sure lang is always a symbol for now (NOT a string)
|
64
|
-
|
65
|
-
## note: cache all "built-in" lang versions (e.g. formats == nil)
|
66
|
-
@@parser ||= {}
|
67
|
-
parser = @@parser[ lang ] ||= ScoreParser.new( lang: lang )
|
68
|
-
end
|
69
|
-
|
70
|
-
def self.parse( line, lang: ScoreFormats.lang )
|
71
|
-
parser( lang: lang ).parse( line )
|
72
|
-
end
|
73
|
-
|
74
|
-
def self.find!( line, lang: ScoreFormats.lang )
|
75
|
-
parser( lang: lang ).find!( line )
|
76
|
-
end
|
77
|
-
|
78
|
-
|
79
|
-
class ScoreParser
|
80
|
-
|
81
|
-
include LogUtils::Logging
|
82
|
-
|
83
|
-
def initialize( lang: )
|
84
|
-
@lang = lang.to_sym ## note: make sure lang is always a symbol for now (NOT a string)
|
85
|
-
|
86
|
-
## fallback to english if lang not available
|
87
|
-
## todo/fix: add/issue warning - why? why not?
|
88
|
-
@formats = FORMATS[ @lang ] || FORMATS[ :en ]
|
89
|
-
end
|
90
|
-
|
91
|
-
|
92
|
-
def parse( line )
|
93
|
-
|
94
|
-
##########
|
95
|
-
## todo/fix/check: add unicode to regular dash conversion - why? why not?
|
96
|
-
## e.g. – becomes - (yes, the letters a different!!!)
|
97
|
-
#############
|
98
|
-
|
99
|
-
score = nil
|
100
|
-
@formats.each do |format|
|
101
|
-
re = format[0]
|
102
|
-
m = re.match( line )
|
103
|
-
if m
|
104
|
-
score = parse_matchdata( m )
|
105
|
-
break
|
106
|
-
end
|
107
|
-
# no match; continue; try next regex pattern
|
108
|
-
end
|
109
|
-
|
110
|
-
## todo/fix - raise ArgumentError - invalid score; no format match found
|
111
|
-
score # note: nil if no match found
|
112
|
-
end # method parse
|
113
|
-
|
114
|
-
|
115
|
-
def find!( line )
|
116
|
-
### fix: add and match all-in-one literal first, followed by
|
117
|
-
|
118
|
-
# note: always call after find_dates !!!
|
119
|
-
# scores match date-like patterns!! e.g. 10-11 or 10:00 etc.
|
120
|
-
# -- note: score might have two digits too
|
121
|
-
|
122
|
-
### fix: depending on language allow 1:1 or 1-1
|
123
|
-
## do NOT allow mix and match
|
124
|
-
## e.g. default to en is 1-1
|
125
|
-
## de is 1:1 etc.
|
126
|
-
|
127
|
-
|
128
|
-
# extract score from line
|
129
|
-
# and return it
|
130
|
-
# note: side effect - removes date from line string
|
131
|
-
|
132
|
-
score = nil
|
133
|
-
@formats.each do |format|
|
134
|
-
re = format[0]
|
135
|
-
tag = format[1]
|
136
|
-
m = re.match( line )
|
137
|
-
if m
|
138
|
-
score = parse_matchdata( m )
|
139
|
-
line.sub!( m[0], tag )
|
140
|
-
break
|
141
|
-
end
|
142
|
-
# no match; continue; try next regex pattern
|
143
|
-
end
|
144
|
-
|
145
|
-
score # note: nil if no match found
|
146
|
-
end # method find!
|
147
|
-
|
148
|
-
private
|
149
|
-
def parse_matchdata( m )
|
150
|
-
# convert regex match_data captures to hash
|
151
|
-
# - note: cannont use match_data like a hash (e.g. raises exception if key/name not present/found)
|
152
|
-
h = {}
|
153
|
-
# - note: do NOT forget to turn name into symbol for lookup in new hash (name.to_sym)
|
154
|
-
m.names.each { |name| h[name.to_sym] = m[name] } # or use match_data.names.zip( match_data.captures ) - more cryptic but "elegant"??
|
155
|
-
|
156
|
-
## puts "[parse_date_time] match_data:"
|
157
|
-
## pp h
|
158
|
-
logger.debug " [parse_matchdata] hash: >#{h.inspect}<"
|
159
|
-
|
160
|
-
score1i = nil # half time (ht) scores
|
161
|
-
score2i = nil
|
162
|
-
|
163
|
-
score1 = nil # full time (ft) scores
|
164
|
-
score2 = nil
|
165
|
-
|
166
|
-
score1et = nil # extra time (et) scores
|
167
|
-
score2et = nil
|
168
|
-
|
169
|
-
score1p = nil # penalty (p) scores
|
170
|
-
score2p = nil
|
171
|
-
|
172
|
-
|
173
|
-
if h[:score1i] && h[:score2i] ## note: half time (HT) score is optional now
|
174
|
-
score1i = h[:score1i].to_i
|
175
|
-
score2i = h[:score2i].to_i
|
176
|
-
end
|
177
|
-
|
178
|
-
if h[:score1] && h[:score2] ## note: full time (FT) score can be optional too!!!
|
179
|
-
score1 = h[:score1].to_i
|
180
|
-
score2 = h[:score2].to_i
|
181
|
-
end
|
182
|
-
|
183
|
-
if h[:score1et] && h[:score2et]
|
184
|
-
score1et = h[:score1et].to_i
|
185
|
-
score2et = h[:score2et].to_i
|
186
|
-
end
|
187
|
-
|
188
|
-
if h[:score1p] && h[:score2p]
|
189
|
-
score1p = h[:score1p].to_i
|
190
|
-
score2p = h[:score2p].to_i
|
191
|
-
end
|
192
|
-
|
193
|
-
score = Score.new( score1i, score2i,
|
194
|
-
score1, score2,
|
195
|
-
score1et, score2et,
|
196
|
-
score1p, score2p )
|
197
|
-
score
|
198
|
-
end # method parse_matchdata
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
end # class ScoreParser
|
203
|
-
end # module ScoreFormats
|
204
|
-
|