sportdb-formats 1.0.2 → 1.1.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 +4 -4
- data/Manifest.txt +5 -0
- data/Rakefile +2 -2
- data/lib/sportdb/formats.rb +17 -5
- data/lib/sportdb/formats/country/country_index.rb +7 -7
- data/lib/sportdb/formats/country/country_reader.rb +26 -6
- data/lib/sportdb/formats/datafile_package.rb +10 -7
- data/lib/sportdb/formats/league/league_outline_reader.rb +24 -7
- data/lib/sportdb/formats/league/league_reader.rb +3 -3
- data/lib/sportdb/formats/match/mapper.rb +63 -63
- data/lib/sportdb/formats/match/mapper_teams.rb +1 -1
- data/lib/sportdb/formats/match/match_parser.rb +99 -180
- data/lib/sportdb/formats/match/match_parser_csv.rb +321 -0
- data/lib/sportdb/formats/package.rb +165 -11
- data/lib/sportdb/formats/parser_helper.rb +11 -2
- data/lib/sportdb/formats/score/score_formats.rb +41 -1
- data/lib/sportdb/formats/score/score_parser.rb +6 -0
- data/lib/sportdb/formats/structs/country.rb +6 -3
- data/lib/sportdb/formats/structs/group.rb +5 -12
- data/lib/sportdb/formats/structs/round.rb +6 -13
- data/lib/sportdb/formats/structs/standings.rb +30 -9
- data/lib/sportdb/formats/structs/team.rb +1 -2
- data/lib/sportdb/formats/team/club_reader_props.rb +3 -3
- data/lib/sportdb/formats/version.rb +4 -2
- data/test/helper.rb +2 -1
- data/test/test_club_reader_props.rb +2 -2
- data/test/test_country_index.rb +4 -4
- data/test/test_country_reader.rb +34 -4
- data/test/test_csv_match_parser.rb +114 -0
- data/test/test_csv_match_parser_utils.rb +20 -0
- data/test/test_csv_reader.rb +5 -5
- data/test/test_datafile.rb +0 -32
- data/test/test_datafile_package.rb +46 -0
- data/test/test_match_auto_relegation.rb +41 -0
- data/test/test_package.rb +60 -28
- data/test/test_package_match.rb +27 -3
- data/test/test_regex.rb +25 -7
- data/test/test_scores.rb +58 -49
- metadata +9 -4
@@ -2,38 +2,79 @@
|
|
2
2
|
module SportDb
|
3
3
|
class Package
|
4
4
|
|
5
|
+
## todo/fix: make all regexes case-insensitive with /i option - why? why not?
|
6
|
+
## e.g. .TXT and .txt
|
7
|
+
## yes!! use /i option!!!!!
|
8
|
+
|
5
9
|
CONF_RE = %r{ (?: ^|/ ) # beginning (^) or beginning of path (/)
|
6
10
|
\.conf\.txt$
|
7
11
|
}x
|
8
12
|
|
13
|
+
## leagues.txt or leagues_en.txt
|
14
|
+
## remove support for en.leagues.txt - why? why not?
|
9
15
|
LEAGUES_RE = %r{ (?: ^|/ ) # beginning (^) or beginning of path (/)
|
10
16
|
(?: [a-z]{1,4}\. )? # optional country code/key e.g. eng.clubs.wiki.txt
|
11
|
-
leagues
|
17
|
+
leagues
|
18
|
+
(?:_[a-z0-9_-]+)?
|
19
|
+
\.txt$
|
12
20
|
}x
|
13
21
|
|
22
|
+
## clubs.txt or clubs_en.txt
|
23
|
+
## remove support for en.clubs.txt - why? why not?
|
14
24
|
CLUBS_RE = %r{ (?: ^|/ ) # beginning (^) or beginning of path (/)
|
15
25
|
(?: [a-z]{1,4}\. )? # optional country code/key e.g. eng.clubs.txt
|
16
|
-
clubs
|
26
|
+
clubs
|
27
|
+
(?:_[a-z0-9_-]+)?
|
28
|
+
\.txt$
|
17
29
|
}x
|
18
30
|
|
19
31
|
CLUBS_WIKI_RE = %r{ (?:^|/) # beginning (^) or beginning of path (/)
|
20
32
|
(?:[a-z]{1,4}\.)? # optional country code/key e.g. eng.clubs.wiki.txt
|
21
|
-
clubs
|
33
|
+
clubs
|
34
|
+
(?:_[a-z0-9_-]+)?
|
35
|
+
\.wiki\.txt$
|
22
36
|
}x
|
23
37
|
|
24
38
|
CLUB_PROPS_RE = %r{ (?: ^|/ ) # beginning (^) or beginning of path (/)
|
25
39
|
(?: [a-z]{1,4}\. )? # optional country code/key e.g. eng.clubs.props.txt
|
26
|
-
clubs
|
40
|
+
clubs
|
41
|
+
(?:_[a-z0-9_-]+)?
|
42
|
+
\.props\.txt$
|
43
|
+
}x
|
44
|
+
|
45
|
+
## teams.txt or teams_history.txt
|
46
|
+
TEAMS_RE = %r{ (?: ^|/ ) # beginning (^) or beginning of path (/)
|
47
|
+
teams
|
48
|
+
(?:_[a-z0-9_-]+)?
|
49
|
+
\.txt$
|
27
50
|
}x
|
28
51
|
|
52
|
+
### season folder:
|
53
|
+
## e.g. /2019-20 or
|
54
|
+
## year-only e.g. /2019 or
|
55
|
+
## /2016--france
|
56
|
+
SEASON_RE = %r{ (?:
|
57
|
+
\d{4}-\d{2}
|
58
|
+
| \d{4}(--[a-z0-9_-]+)?
|
59
|
+
)
|
60
|
+
}x
|
61
|
+
SEASON = SEASON_RE.source ## "inline" helper for embedding in other regexes - keep? why? why not?
|
62
|
+
|
63
|
+
|
29
64
|
## note: if pattern includes directory add here
|
30
65
|
## (otherwise move to more "generic" datafile) - why? why not?
|
31
|
-
MATCH_RE = %r{
|
32
|
-
|
33
|
-
|
34
|
-
/[a-z0-9_-]+\.txt$ ## txt e.g /1-premierleague.txt
|
66
|
+
MATCH_RE = %r{ (?: ^|/ ) # beginning (^) or beginning of path (/)
|
67
|
+
#{SEASON}
|
68
|
+
/[a-z0-9_-]+\.txt$ ## txt e.g /1-premierleague.txt
|
35
69
|
}x
|
36
70
|
|
71
|
+
MATCH_CSV_RE = %r{ (?: ^|/ ) # beginning (^) or beginning of path (/)
|
72
|
+
#{SEASON}
|
73
|
+
/[a-z0-9_.-]+\.csv$ ## note: allow dot (.) too e.g /eng.1.csv
|
74
|
+
}x
|
75
|
+
|
76
|
+
|
77
|
+
|
37
78
|
## move class-level "static" finders to DirPackage (do NOT work for now for zip packages) - why? why not?
|
38
79
|
|
39
80
|
def self.find( path, pattern )
|
@@ -41,7 +82,7 @@ module SportDb
|
|
41
82
|
|
42
83
|
## check all txt files
|
43
84
|
## note: incl. files starting with dot (.)) as candidates (normally excluded with just *)
|
44
|
-
candidates = Dir.glob( "#{path}/**/{*,.*}
|
85
|
+
candidates = Dir.glob( "#{path}/**/{*,.*}.*" )
|
45
86
|
pp candidates
|
46
87
|
candidates.each do |candidate|
|
47
88
|
datafiles << candidate if pattern.match( candidate )
|
@@ -52,6 +93,8 @@ module SportDb
|
|
52
93
|
end
|
53
94
|
|
54
95
|
|
96
|
+
def self.find_teams( path, pattern: TEAMS_RE ) find( path, pattern ); end
|
97
|
+
def self.match_teams( path ) TEAMS_RE.match( path ); end
|
55
98
|
|
56
99
|
def self.find_clubs( path, pattern: CLUBS_RE ) find( path, pattern ); end
|
57
100
|
def self.find_clubs_wiki( path, pattern: CLUBS_WIKI_RE ) find( path, pattern ); end
|
@@ -66,7 +109,19 @@ module SportDb
|
|
66
109
|
def self.find_conf( path, pattern: CONF_RE ) find( path, pattern ); end
|
67
110
|
def self.match_conf( path ) CONF_RE.match( path ); end
|
68
111
|
|
112
|
+
def self.find_match( path, format: 'txt' )
|
113
|
+
if format == 'csv'
|
114
|
+
find( path, MATCH_CSV_RE )
|
115
|
+
else ## otherwise always assume txt for now
|
116
|
+
find( path, MATCH_RE )
|
117
|
+
end
|
118
|
+
end
|
119
|
+
## add match_match and match_match_csv - why? why not?
|
120
|
+
|
69
121
|
class << self
|
122
|
+
alias_method :match_teams?, :match_teams
|
123
|
+
alias_method :teams?, :match_teams
|
124
|
+
|
70
125
|
alias_method :match_clubs?, :match_clubs
|
71
126
|
alias_method :clubs?, :match_clubs
|
72
127
|
|
@@ -149,7 +204,14 @@ module SportDb
|
|
149
204
|
end
|
150
205
|
|
151
206
|
def each_conf( &blk ) each( pattern: CONF_RE, &blk ); end
|
152
|
-
def each_match(
|
207
|
+
def each_match( format: 'txt', &blk )
|
208
|
+
if format == 'csv'
|
209
|
+
each( pattern: MATCH_CSV_RE, &blk );
|
210
|
+
else
|
211
|
+
each( pattern: MATCH_RE, &blk );
|
212
|
+
end
|
213
|
+
end
|
214
|
+
def each_match_csv( &blk ) each( pattern: MATCH_CSV_RE, &blk ); end
|
153
215
|
def each_club_props( &blk ) each( pattern: CLUB_PROPS_RE, &blk ); end
|
154
216
|
|
155
217
|
def each_leagues( &blk ) each( pattern: LEAGUES_RE, &blk ); end
|
@@ -157,8 +219,100 @@ module SportDb
|
|
157
219
|
def each_clubs_wiki( &blk ) each( pattern: CLUBS_WIKI_RE, &blk ); end
|
158
220
|
|
159
221
|
## return all match datafile entries
|
160
|
-
def match(
|
222
|
+
def match( format: 'txt' )
|
223
|
+
ary=[]; each_match( format: format ) {|entry| ary << entry }; ary;
|
224
|
+
end
|
161
225
|
alias_method :matches, :match
|
226
|
+
|
227
|
+
|
228
|
+
## todo/check: rename/change to match_by_dir - why? why not?
|
229
|
+
## still in use somewhere? move to attic? use match_by_season and delete by_season_dir? - why? why not?
|
230
|
+
def match_by_season_dir( format: 'txt' )
|
231
|
+
##
|
232
|
+
## [["1950s/1956-57",
|
233
|
+
## ["1950s/1956-57/1-division1.csv",
|
234
|
+
## "1950s/1956-57/2-division2.csv",
|
235
|
+
## "1950s/1956-57/3a-division3n.csv",
|
236
|
+
## "1950s/1956-57/3b-division3s.csv"]],
|
237
|
+
## ...]
|
238
|
+
|
239
|
+
h = {}
|
240
|
+
match( format: format ).each do |entry|
|
241
|
+
season_path = File.dirname( entry.name )
|
242
|
+
|
243
|
+
h[ season_path ] ||= []
|
244
|
+
h[ season_path ] << entry
|
245
|
+
end
|
246
|
+
|
247
|
+
## todo/fix: - add sort entries by name - why? why not?
|
248
|
+
## note: assume 1-,2- etc. gets us back sorted leagues
|
249
|
+
## - use sort. (will not sort by default?)
|
250
|
+
|
251
|
+
h.to_a ## return as array (or keep hash) - why? why not?
|
252
|
+
end # method match_by_season_dir
|
253
|
+
|
254
|
+
def match_by_season( format: 'txt', start: nil ) ## change/rename to by_season_key - why? why not?
|
255
|
+
|
256
|
+
## todo/note: in the future - season might be anything (e.g. part of a filename and NOT a directory) - why? why not?
|
257
|
+
|
258
|
+
## note: fold all sames seasons (even if in different directories)
|
259
|
+
## into same datafile list e.g.
|
260
|
+
## ["1957/58",
|
261
|
+
## ["1950s/1957-58/1-division1.csv",
|
262
|
+
## "1950s/1957-58/2-division2.csv",
|
263
|
+
## "1950s/1957-58/3a-division3n.csv",
|
264
|
+
## "1950s/1957-58/3b-division3s.csv"]],
|
265
|
+
## and
|
266
|
+
## ["1957/58",
|
267
|
+
## ["archives/1950s/1957-58/1-division1.csv",
|
268
|
+
## "archives/1950s/1957-58/2-division2.csv",
|
269
|
+
## "archives/1950s/1957-58/3a-division3n.csv",
|
270
|
+
## "archives/1950s/1957-58/3b-division3s.csv"]],
|
271
|
+
## should be together - why? why not?
|
272
|
+
|
273
|
+
####
|
274
|
+
# Example package:
|
275
|
+
# [["2012/13", ["2012-13/1-proleague.csv"]],
|
276
|
+
# ["2013/14", ["2013-14/1-proleague.csv"]],
|
277
|
+
# ["2014/15", ["2014-15/1-proleague.csv"]],
|
278
|
+
# ["2015/16", ["2015-16/1-proleague.csv"]],
|
279
|
+
# ["2016/17", ["2016-17/1-proleague.csv"]],
|
280
|
+
# ["2017/18", ["2017-18/1-proleague.csv"]]]
|
281
|
+
|
282
|
+
## todo/fix: (re)use a more generic filter instead of start for start of season only
|
283
|
+
|
284
|
+
## todo/fix: use a "generic" filter_season helper for easy reuse
|
285
|
+
## filter_season( clause, season_key )
|
286
|
+
## or better filter = SeasonFilter.new( clause )
|
287
|
+
## filter.skip? filter.include? ( season_sason_key )?
|
288
|
+
## fiteer.before?( season_key ) etc.
|
289
|
+
## find some good method names!!!!
|
290
|
+
season_start = start ? Import::Season.new( start ) : nil
|
291
|
+
|
292
|
+
h = {}
|
293
|
+
match( format: format ).each do |entry|
|
294
|
+
## note: assume last directory in datafile path is the season part/key
|
295
|
+
season_q = File.basename( File.dirname( entry.name ))
|
296
|
+
season = Import::Season.new( season_q ) ## normalize season
|
297
|
+
|
298
|
+
## skip if start season before this season
|
299
|
+
next if season_start && season_start.start_year > season.start_year
|
300
|
+
|
301
|
+
h[ season.key ] ||= []
|
302
|
+
h[ season.key ] << entry
|
303
|
+
end
|
304
|
+
|
305
|
+
## todo/fix: - add sort entries by name - why? why not?
|
306
|
+
## note: assume 1-,2- etc. gets us back sorted leagues
|
307
|
+
## - use sort. (will not sort by default?)
|
308
|
+
|
309
|
+
## sort by season
|
310
|
+
## latest / newest first (and oldest last)
|
311
|
+
|
312
|
+
h.to_a.sort do |l,r| ## return as array (or keep hash) - why? why not?
|
313
|
+
r[0] <=> l[0]
|
314
|
+
end
|
315
|
+
end # method match_by_season
|
162
316
|
end # class Package
|
163
317
|
|
164
318
|
|
@@ -18,10 +18,19 @@ module SportDb
|
|
18
18
|
|
19
19
|
|
20
20
|
def is_round?( line )
|
21
|
-
## note: =~
|
22
|
-
|
21
|
+
## note: =~ returns nil if not match found, and 0,1, etc for match
|
22
|
+
|
23
|
+
## note: allow "free standing" leg 1 and leg 2 too
|
24
|
+
## (e.g. Hinspiel, Rückspiel etc. used for now in Relegation, for example)
|
25
|
+
## note ONLY allowed if "free standing", that is, full line with nothing else
|
26
|
+
## use "custom" regex for special case for now
|
27
|
+
## avoids match HIN in PascHINg, for example (hin in german for leg 1)
|
28
|
+
line =~ SportDb.lang.regex_round ||
|
29
|
+
line =~ /^(#{SportDb.lang.leg1})$/i ||
|
30
|
+
line =~ /^(#{SportDb.lang.leg2})$/i
|
23
31
|
end
|
24
32
|
|
33
|
+
|
25
34
|
def is_knockout_round?( line )
|
26
35
|
|
27
36
|
## todo: check for adding ignore case for regex (e.g. 1st leg/1st Leg)
|
@@ -93,12 +93,51 @@ module ScoreFormats
|
|
93
93
|
(?=[ \]]|$)/xi ## todo/check: remove loakahead assertion here - why require space?
|
94
94
|
## note: \b works only after non-alphanum e.g. )
|
95
95
|
|
96
|
+
|
96
97
|
#####
|
97
98
|
# deutsch / german helpers (penalty, extra time, ...)
|
98
99
|
## todo add more marker e.g. im Elf. or such!!!
|
99
100
|
P_DE = '(?: ie | i\.e\.? )' # e.g. iE, i.E., i.E etc.
|
100
101
|
ET_DE = '(?: nv | n\.v\.? )' # e.g. nV, n.V., n.V etc.
|
101
102
|
|
103
|
+
|
104
|
+
## support alternate all-in-one score e.g.
|
105
|
+
## i.E. 2:4, n.V. 3:3 (1:1, 1:1) or
|
106
|
+
## n.V. 3:2 (2:2, 1:2)
|
107
|
+
DE__P_ET_FT_HT__RE = /\b
|
108
|
+
(?:
|
109
|
+
#{P_DE}
|
110
|
+
[ ]*
|
111
|
+
(?<score1p>\d{1,2})
|
112
|
+
[ ]* : [ ]*
|
113
|
+
(?<score2p>\d{1,2})
|
114
|
+
[ ]* (?:, [ ]*)?
|
115
|
+
)? # note: make penalty (P) score optional for now
|
116
|
+
#{ET_DE}
|
117
|
+
[ ]*
|
118
|
+
(?<score1et>\d{1,2})
|
119
|
+
[ ]* : [ ]*
|
120
|
+
(?<score2et>\d{1,2})
|
121
|
+
[ ]*
|
122
|
+
\(
|
123
|
+
[ ]*
|
124
|
+
(?<score1>\d{1,2})
|
125
|
+
[ ]* : [ ]*
|
126
|
+
(?<score2>\d{1,2})
|
127
|
+
[ ]*
|
128
|
+
(?:
|
129
|
+
, [ ]*
|
130
|
+
(?:
|
131
|
+
(?<score1i>\d{1,2})
|
132
|
+
[ ]* : [ ]*
|
133
|
+
(?<score2i>\d{1,2})
|
134
|
+
[ ]*
|
135
|
+
)?
|
136
|
+
)? # note: make half time (HT) score optional for now
|
137
|
+
\)
|
138
|
+
(?=[ \]]|$)
|
139
|
+
/xi
|
140
|
+
|
102
141
|
## support all-in-one "literal form e.g.
|
103
142
|
# 2:2 (1:1, 1:0) n.V. 5:1 i.E. or
|
104
143
|
# 2-2 (1-1, 1-0) n.V. 5-1 i.E.
|
@@ -168,7 +207,8 @@ FORMATS_EN = [
|
|
168
207
|
]
|
169
208
|
|
170
209
|
FORMATS_DE = [
|
171
|
-
[ DE__ET_FT_HT_P__RE, '[SCORE.DE__ET_(FT_HT?)_P?]' ], # e.g.
|
210
|
+
[ 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.
|
211
|
+
[ 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)
|
172
212
|
[ DE__FT_HT__RE, '[SCORE.DE__FT_(HT)?]' ], # e.g. 1:1 (1:0)
|
173
213
|
]
|
174
214
|
|
@@ -90,6 +90,12 @@ class ScoreParser
|
|
90
90
|
|
91
91
|
|
92
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
|
+
|
93
99
|
score = nil
|
94
100
|
@formats.each do |format|
|
95
101
|
re = format[0]
|
@@ -11,11 +11,14 @@ class Country
|
|
11
11
|
|
12
12
|
## note: is read-only/immutable for now - why? why not?
|
13
13
|
## add cities (array/list) - why? why not?
|
14
|
-
attr_reader :key, :name, :
|
14
|
+
attr_reader :key, :name, :code, :tags
|
15
15
|
attr_accessor :alt_names
|
16
16
|
|
17
|
-
def initialize( key
|
18
|
-
|
17
|
+
def initialize( key: nil, name:, code:, tags: [] )
|
18
|
+
## note: auto-generate key "on-the-fly" if missing for now - why? why not?
|
19
|
+
## note: quick hack - auto-generate key, that is, remove all non-ascii chars and downcase
|
20
|
+
@key = key || name.downcase.gsub( /[^a-z]/, '' )
|
21
|
+
@name, @code = name, code
|
19
22
|
@alt_names = []
|
20
23
|
@tags = tags
|
21
24
|
end
|
@@ -2,20 +2,13 @@ module SportDb
|
|
2
2
|
module Import
|
3
3
|
|
4
4
|
class Group
|
5
|
-
attr_reader
|
5
|
+
attr_reader :key, :name, :teams
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
## make start and end date optional
|
10
|
-
## change pos to num - why? why not?
|
11
|
-
## make pos/num optional too
|
12
|
-
##
|
13
|
-
## sort round by scheduled/planed start date
|
14
|
-
def initialize( title:,
|
15
|
-
pos:,
|
7
|
+
def initialize( key: nil,
|
8
|
+
name:,
|
16
9
|
teams: )
|
17
|
-
@
|
18
|
-
@
|
10
|
+
@key = key ## e.g. A,B,C or 1,2,3, - note: always a string or nil
|
11
|
+
@name = name
|
19
12
|
@teams = teams
|
20
13
|
end
|
21
14
|
end # class Group
|
@@ -2,24 +2,17 @@ module SportDb
|
|
2
2
|
module Import
|
3
3
|
|
4
4
|
class Round
|
5
|
-
attr_reader :
|
6
|
-
attr_accessor :
|
5
|
+
attr_reader :name, :start_date, :end_date, :knockout
|
6
|
+
attr_accessor :num # note: make read & writable - why? why not?
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
## make start and end date optional
|
11
|
-
## change pos to num - why? why not?
|
12
|
-
## make pos/num optional too
|
13
|
-
##
|
14
|
-
## sort round by scheduled/planed start date
|
15
|
-
def initialize( title:,
|
16
|
-
pos: nil,
|
8
|
+
def initialize( name:,
|
9
|
+
num: nil,
|
17
10
|
start_date: nil,
|
18
11
|
end_date: nil,
|
19
12
|
knockout: false,
|
20
13
|
auto: true )
|
21
|
-
@
|
22
|
-
@
|
14
|
+
@name = name
|
15
|
+
@num = num
|
23
16
|
@start_date = start_date
|
24
17
|
@end_date = end_date
|
25
18
|
@knockout = knockout
|
@@ -12,7 +12,7 @@ module SportDb
|
|
12
12
|
|
13
13
|
class Standings
|
14
14
|
|
15
|
-
class StandingsLine ## nested class StandinsLine
|
15
|
+
class StandingsLine ## nested class StandinsLine - todo/fix: change to Line - why? why not?
|
16
16
|
attr_accessor :rank, :team,
|
17
17
|
:played, :won, :lost, :drawn, ## -- total
|
18
18
|
:goals_for, :goals_against, :pts,
|
@@ -21,8 +21,13 @@ class Standings
|
|
21
21
|
:away_played, :away_won, :away_lost, :away_drawn, ## -- away
|
22
22
|
:away_goals_for, :away_goals_against, :away_pts
|
23
23
|
|
24
|
+
alias_method :team_name, :team ## note: team for now always a string
|
25
|
+
alias_method :pos, :rank ## rename back to use pos instead of rank - why? why not?
|
26
|
+
|
27
|
+
|
24
28
|
def initialize( team )
|
25
29
|
@rank = nil # use 0? why? why not?
|
30
|
+
## change rank back to pos - why? why not?
|
26
31
|
@team = team
|
27
32
|
@played = @home_played = @away_played = 0
|
28
33
|
@won = @home_won = @away_won = 0
|
@@ -49,7 +54,12 @@ class Standings
|
|
49
54
|
|
50
55
|
def update( match_or_matches )
|
51
56
|
## convenience - update all matches at once
|
52
|
-
|
57
|
+
## todo/check: check for ActiveRecord_Associations_CollectionProxy and than use to_a (to "force" array) - why? why not?
|
58
|
+
matches = if match_or_matches.is_a?(Array)
|
59
|
+
match_or_matches
|
60
|
+
else
|
61
|
+
[match_or_matches]
|
62
|
+
end
|
53
63
|
|
54
64
|
matches.each_with_index do |match,i| # note: index(i) starts w/ zero (0)
|
55
65
|
update_match( match )
|
@@ -171,19 +181,30 @@ class Standings
|
|
171
181
|
private
|
172
182
|
def update_match( m ) ## add a match
|
173
183
|
|
174
|
-
##
|
184
|
+
## note: always use team as string for now
|
185
|
+
## for now allow passing in of string OR struct - why? why not?
|
186
|
+
## todo/fix: change to m.team1_name and m.team2_name - why? why not?
|
187
|
+
team1 = m.team1.is_a?( String ) ? m.team1 : m.team1.name
|
188
|
+
team2 = m.team2.is_a?( String ) ? m.team2 : m.team2.name
|
189
|
+
|
190
|
+
score = m.score_str
|
191
|
+
|
192
|
+
## puts " #{team1} - #{team2} #{score}"
|
193
|
+
|
175
194
|
unless m.over?
|
176
|
-
puts " !!!! skipping match - not yet over (
|
195
|
+
puts " !!!! skipping match - not yet over (date in the future) => #{m.date}"
|
177
196
|
return
|
178
197
|
end
|
179
198
|
|
180
199
|
unless m.complete?
|
181
|
-
puts "!!! [calc_standings] skipping match #{
|
200
|
+
puts "!!! [calc_standings] skipping match #{team1} - #{team2} w/ past date #{m.date} - scores incomplete => #{score}"
|
182
201
|
return
|
183
202
|
end
|
184
203
|
|
185
|
-
|
186
|
-
|
204
|
+
|
205
|
+
|
206
|
+
line1 = @lines[ team1 ] || StandingsLine.new( team1 )
|
207
|
+
line2 = @lines[ team2 ] || StandingsLine.new( team2 )
|
187
208
|
|
188
209
|
line1.played += 1
|
189
210
|
line1.home_played += 1
|
@@ -236,8 +257,8 @@ private
|
|
236
257
|
puts "*** warn: [standings] skipping match with missing scores: #{m.inspect}"
|
237
258
|
end
|
238
259
|
|
239
|
-
@lines[
|
240
|
-
@lines[
|
260
|
+
@lines[ team1 ] = line1
|
261
|
+
@lines[ team2 ] = line2
|
241
262
|
end # method update_match
|
242
263
|
|
243
264
|
end # class Standings
|