sportdb-formats 1.0.6 → 1.1.4

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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/Manifest.txt +6 -33
  3. data/Rakefile +2 -5
  4. data/lib/sportdb/formats.rb +54 -70
  5. data/lib/sportdb/formats/country/country_index.rb +2 -2
  6. data/lib/sportdb/formats/event/event_index.rb +141 -0
  7. data/lib/sportdb/formats/event/event_reader.rb +183 -0
  8. data/lib/sportdb/formats/league/league_index.rb +22 -18
  9. data/lib/sportdb/formats/league/league_outline_reader.rb +45 -13
  10. data/lib/sportdb/formats/league/league_reader.rb +7 -1
  11. data/lib/sportdb/formats/match/match_parser.rb +101 -111
  12. data/lib/sportdb/formats/package.rb +59 -11
  13. data/lib/sportdb/formats/parser_helper.rb +11 -2
  14. data/lib/sportdb/formats/team/club_index.rb +13 -11
  15. data/lib/sportdb/formats/team/club_index_history.rb +134 -0
  16. data/lib/sportdb/formats/team/club_reader_history.rb +203 -0
  17. data/lib/sportdb/formats/team/club_reader_props.rb +20 -5
  18. data/lib/sportdb/formats/version.rb +2 -2
  19. data/test/helper.rb +51 -81
  20. data/test/test_club_index_history.rb +107 -0
  21. data/test/test_club_reader_history.rb +212 -0
  22. data/test/test_datafile_package.rb +1 -1
  23. data/test/test_regex.rb +25 -7
  24. metadata +9 -78
  25. data/lib/sportdb/formats/config.rb +0 -40
  26. data/lib/sportdb/formats/match/match_parser_csv.rb +0 -314
  27. data/lib/sportdb/formats/name_helper.rb +0 -84
  28. data/lib/sportdb/formats/score/score_formats.rb +0 -220
  29. data/lib/sportdb/formats/score/score_parser.rb +0 -202
  30. data/lib/sportdb/formats/season_utils.rb +0 -27
  31. data/lib/sportdb/formats/structs/country.rb +0 -31
  32. data/lib/sportdb/formats/structs/group.rb +0 -18
  33. data/lib/sportdb/formats/structs/league.rb +0 -37
  34. data/lib/sportdb/formats/structs/match.rb +0 -151
  35. data/lib/sportdb/formats/structs/matchlist.rb +0 -220
  36. data/lib/sportdb/formats/structs/round.rb +0 -25
  37. data/lib/sportdb/formats/structs/season.rb +0 -123
  38. data/lib/sportdb/formats/structs/standings.rb +0 -247
  39. data/lib/sportdb/formats/structs/team.rb +0 -150
  40. data/lib/sportdb/formats/structs/team_usage.rb +0 -88
  41. data/test/test_clubs.rb +0 -40
  42. data/test/test_conf.rb +0 -65
  43. data/test/test_csv_match_parser.rb +0 -114
  44. data/test/test_csv_match_parser_utils.rb +0 -20
  45. data/test/test_csv_reader.rb +0 -31
  46. data/test/test_match.rb +0 -30
  47. data/test/test_match_auto.rb +0 -72
  48. data/test/test_match_auto_champs.rb +0 -45
  49. data/test/test_match_auto_euro.rb +0 -37
  50. data/test/test_match_auto_worldcup.rb +0 -61
  51. data/test/test_match_champs.rb +0 -27
  52. data/test/test_match_eng.rb +0 -26
  53. data/test/test_match_euro.rb +0 -27
  54. data/test/test_match_worldcup.rb +0 -27
  55. data/test/test_name_helper.rb +0 -67
  56. data/test/test_scores.rb +0 -122
  57. data/test/test_season.rb +0 -62
@@ -95,36 +95,40 @@ class LeagueIndex
95
95
  end # method add
96
96
 
97
97
 
98
+ ## helper to always convert (possible) country key to existing country record
99
+ ## todo: make private - why? why not?
100
+ def country( country )
101
+ if country.is_a?( String ) || country.is_a?( Symbol )
102
+ ## note: use own "global" countries index setting for ClubIndex - why? why not?
103
+ rec = catalog.countries.find( country.to_s )
104
+ if rec.nil?
105
+ puts "** !!! ERROR !!! - unknown country >#{country}< - no match found, sorry - add to world/countries.txt in config"
106
+ exit 1
107
+ end
108
+ rec
109
+ else
110
+ country ## (re)use country struct - no need to run lookup again
111
+ end
112
+ end
113
+
114
+
98
115
  def match( name )
99
- ## todo/check: return empty array if no match!!! and NOT nil (add || []) - why? why not?
116
+ ## note: returns empty array if no match and NOT nil
100
117
  name = normalize( name )
101
- @leagues_by_name[ name ]
118
+ @leagues_by_name[ name ] || []
102
119
  end
103
120
 
104
-
105
121
  def match_by( name:, country: )
106
122
  ## note: match must for now always include name
107
123
  m = match( name )
108
- if m ## filter by country
124
+ if country ## filter by country
109
125
  ## note: country assumes / allows the country key or fifa code for now
110
-
111
126
  ## note: allow passing in of country struct too
112
- country_rec = if country.is_a?( Country )
113
- country ## (re)use country struct - no need to run lookup again
114
- else
115
- ## note: use own "global" countries index setting for ClubIndex - why? why not?
116
- rec = catalog.countries.find( country )
117
- if rec.nil?
118
- puts "** !!! ERROR !!! - unknown country >#{country}< - no match found, sorry - add to world/countries.txt in config"
119
- exit 1
120
- end
121
- rec
122
- end
127
+ country_rec = country( country )
123
128
 
124
129
  ## note: also skip international leagues & cups (e.g. champions league etc.) for now - why? why not?
125
130
  m = m.select { |league| league.country &&
126
131
  league.country.key == country_rec.key }
127
- m = nil if m.empty? ## note: reset to nil if no more matches
128
132
  end
129
133
  m
130
134
  end
@@ -144,7 +148,7 @@ class LeagueIndex
144
148
  m = match( name )
145
149
  # pp m
146
150
 
147
- if m.nil?
151
+ if m.empty?
148
152
  ## fall through/do nothing
149
153
  elsif m.size > 1
150
154
  puts "** !!! ERROR - ambigious league name; too many leagues (#{m.size}) found:"
@@ -65,7 +65,7 @@ class LeagueOutlineReader ## todo/check - rename to LeaguePageReader / LeagueP
65
65
  filtered_secs = []
66
66
  filter = norm_seasons( season )
67
67
  secs.each do |sec|
68
- if filter.include?( Import::Season.new( sec[:season] ).key )
68
+ if filter.include?( Season.parse( sec[:season] ).key )
69
69
  filtered_secs << sec
70
70
  else
71
71
  puts " skipping season >#{sec[:season]}< NOT matched by filter"
@@ -76,7 +76,7 @@ class LeagueOutlineReader ## todo/check - rename to LeaguePageReader / LeagueP
76
76
 
77
77
  ## pass 3 - check & map; replace inline (string with data struct record)
78
78
  secs.each do |sec|
79
- sec[:season] = Import::Season.new( sec[:season ] )
79
+ sec[:season] = Season.parse( sec[:season ] )
80
80
  sec[:league] = catalog.leagues.find!( sec[:league] )
81
81
 
82
82
  check_stage( sec[:stage] ) if sec[:stage] ## note: only check for now (no remapping etc.)
@@ -100,14 +100,18 @@ class LeagueOutlineReader ## todo/check - rename to LeaguePageReader / LeagueP
100
100
  )
101
101
  $}x
102
102
 
103
+
103
104
  def norm_seasons( season_or_seasons ) ## todo/check: add alias norm_seasons - why? why not?
104
- seasons = if season_or_seasons.is_a?( String ) ## wrap in array
105
+
106
+ seasons = if season_or_seasons.is_a?( Array ) # is it an array already
107
+ season_or_seasons
108
+ elsif season_or_seasons.is_a?( Range ) # e.g. Season(1999)..Season(2001) or such
109
+ season_or_seasons.to_a
110
+ else ## assume - single entry - wrap in array
105
111
  [season_or_seasons]
106
- else ## assume it's an array already
107
- season_or_seasons
108
112
  end
109
113
 
110
- seasons.map { |season| Import::Season.new( season ).key }
114
+ seasons.map { |season| Season( season ).key }
111
115
  end
112
116
 
113
117
 
@@ -121,14 +125,42 @@ class LeagueOutlineReader ## todo/check - rename to LeaguePageReader / LeagueP
121
125
  values
122
126
  end
123
127
 
124
- def check_stage( name )
125
- known_stages = ['regular season',
126
- 'championship round',
127
- 'relegation round',
128
- 'play-offs'
129
- ]
130
128
 
131
- if known_stages.include?( name.downcase )
129
+ # note: normalize names e.g. downcase and remove all non a-z chars (e.g. space, dash, etc.)
130
+ KNOWN_STAGES = [
131
+ 'Regular Season',
132
+ 'Regular Stage',
133
+ 'Championship Round',
134
+ 'Championship Playoff', # or Championship play-off
135
+ 'Relegation Round',
136
+ 'Relegation Playoff',
137
+ 'Play-offs',
138
+ 'Playoff Stage',
139
+ 'Grunddurchgang',
140
+ 'Finaldurchgang - Qualifikationsgruppe',
141
+ 'Finaldurchgang - Qualifikation',
142
+ 'Finaldurchgang - Meistergruppe',
143
+ 'Finaldurchgang - Meister',
144
+ 'EL Play-off',
145
+ 'Europa League Play-off',
146
+ 'Europa-League-Play-offs',
147
+ 'Playoffs - Championship',
148
+ 'Playoffs - Europa League',
149
+ 'Playoffs - Europa League - Finals',
150
+ 'Playoffs - Relegation',
151
+ 'Finals',
152
+
153
+ 'Apertura',
154
+ 'Apertura - Liguilla',
155
+ 'Clausura',
156
+ 'Clausura - Liguilla',
157
+
158
+ ].map {|name| name.downcase.gsub( /[^a-z]/, '' ) }
159
+
160
+
161
+ def check_stage( name )
162
+ # note: normalize names e.g. downcase and remove all non a-z chars (e.g. space, dash, etc.)
163
+ if KNOWN_STAGES.include?( name.downcase.gsub( /[^a-z]/, '' ) )
132
164
  ## everything ok
133
165
  else
134
166
  puts "** !!! ERROR - no (league) stage match found for >#{name}<, add to (builtin) stages table; sorry"
@@ -118,12 +118,18 @@ def parse
118
118
  alt_names_auto << "#{country.code}" if league_key == '1' ## add shortcut for top level 1 (just country key)
119
119
  end
120
120
  alt_names_auto << "#{country.name} #{league_key}" if league_key =~ /^[0-9]+$/ ## if all numeric e.g. add Austria 1 etc.
121
+
122
+ ## auto-add with country prepended
123
+ ## e.g. England Premier League, Austria Bundesliga etc.
124
+ ## todo/check: also add variants with country alt name if present!!!
125
+ ## todo/check: exclude cups or such from country + league name auto-add - why? why not?
126
+ alt_names_auto << "#{country.name} #{league_name}"
121
127
  else ## assume int'l (no country) e.g. champions league, etc.
122
128
  ## only auto-add key (e.g. CL, EL, etc.)
123
129
  alt_names_auto << league_key.upcase.gsub('.', ' ') ## note: no country code (prefix/leading) used
124
130
  end
125
131
 
126
- pp alt_names_auto
132
+ ## pp alt_names_auto
127
133
 
128
134
  ## prepend country key/code if country present
129
135
  ## todo/fix: only auto-prepend country if key/code start with a number (level) or incl. cup
@@ -82,10 +82,9 @@ class MatchParser ## simple match parser for team match schedules
82
82
  # team1 team2 - match (will get new auto-matchday! not last round)
83
83
  @last_round = nil
84
84
 
85
- name, pos = find_group_name_and_pos!( line )
85
+ name = find_group_name!( line )
86
86
 
87
87
  logger.debug " name: >#{name}<"
88
- logger.debug " pos: >#{pos}<"
89
88
  logger.debug " line: >#{line}<"
90
89
 
91
90
  group = @groups[ name ]
@@ -104,7 +103,7 @@ class MatchParser ## simple match parser for team match schedules
104
103
  @mapper_teams.map_teams!( line )
105
104
  teams = @mapper_teams.find_teams!( line )
106
105
 
107
- name, pos = find_group_name_and_pos!( line )
106
+ name = find_group_name!( line )
108
107
 
109
108
  logger.debug " line: >#{line}<"
110
109
 
@@ -116,7 +115,7 @@ class MatchParser ## simple match parser for team match schedules
116
115
  end
117
116
 
118
117
 
119
- def find_group_name_and_pos!( line )
118
+ def find_group_name!( line )
120
119
  ## group pos - for now support single digit e.g 1,2,3 or letter e.g. A,B,C or HEX
121
120
  ## nb: (?:) = is for non-capturing group(ing)
122
121
 
@@ -125,37 +124,25 @@ class MatchParser ## simple match parser for team match schedules
125
124
 
126
125
  ## todo:
127
126
  ## check if Group A: or [Group A] works e.g. : or ] get matched by \b ???
128
- regex = /(?:Group|Gruppe|Grupo)\s+((?:\d{1}|[A-Z]{1,3}))\b/
127
+ regex = /\b
128
+ (?:
129
+ (Group | Gruppe | Grupo)
130
+ [ ]+
131
+ (\d+ | [A-Z]+)
132
+ )
133
+ \b/x
129
134
 
130
135
  m = regex.match( line )
131
136
 
132
- return [nil,nil] if m.nil?
133
-
134
- pos = case m[1]
135
- when 'A' then 1
136
- when 'B' then 2
137
- when 'C' then 3
138
- when 'D' then 4
139
- when 'E' then 5
140
- when 'F' then 6
141
- when 'G' then 7
142
- when 'H' then 8
143
- when 'I' then 9
144
- when 'J' then 10
145
- when 'K' then 11
146
- when 'L' then 12
147
- when 'HEX' then 666 # HEX for Hexagonal - todo/check: map to something else ??
148
- else m[1].to_i
149
- end
137
+ return nil if m.nil?
150
138
 
151
139
  name = m[0]
152
140
 
153
141
  logger.debug " name: >#{name}<"
154
- logger.debug " pos: >#{pos}<"
155
142
 
156
- line.sub!( regex, '[GROUP.NAME+POS]' )
143
+ line.sub!( name, '[GROUP.NAME]' )
157
144
 
158
- [name,pos]
145
+ name
159
146
  end
160
147
 
161
148
 
@@ -180,7 +167,6 @@ class MatchParser ## simple match parser for team match schedules
180
167
  end_date = end_date.to_date
181
168
 
182
169
 
183
- pos = find_round_pos!( line )
184
170
  name = find_round_def_name!( line )
185
171
  # NB: use extracted round name for knockout check
186
172
  knockout_flag = is_knockout_round?( name )
@@ -188,15 +174,11 @@ class MatchParser ## simple match parser for team match schedules
188
174
 
189
175
  logger.debug " start_date: #{start_date}"
190
176
  logger.debug " end_date: #{end_date}"
191
- logger.debug " pos: #{pos}"
192
177
  logger.debug " name: >#{name}<"
193
178
  logger.debug " knockout_flag: #{knockout_flag}"
194
179
 
195
180
  logger.debug " line: >#{line}<"
196
181
 
197
- #######################################
198
- # todo/fix: add auto flag is false !!!! - why? why not?
199
- # todo/fix/check: add num if present!!!!
200
182
  round = Import::Round.new( name: name,
201
183
  start_date: start_date,
202
184
  end_date: end_date,
@@ -208,52 +190,6 @@ class MatchParser ## simple match parser for team match schedules
208
190
 
209
191
 
210
192
 
211
- def find_round_pos!( line )
212
- # pass #1) extract optional round pos from line
213
- # e.g. (1) - must start line
214
- regex_pos = /^[ \t]*\((\d{1,3})\)[ \t]+/
215
-
216
- # pass #2) find free standing number e.g. Matchday 3 or Round 5 or 3. Spieltag etc.
217
- # note: /\b(\d{1,3})\b/
218
- # will match -12
219
- # thus, use space required - will NOT match -2 e.g. Group-2 Play-off
220
- # note: allow 1. Runde n
221
- # 1^ Giornata
222
- regex_num = /(?:^|\s)(\d{1,3})(?:[.\^\s]|$)/
223
-
224
- if line =~ regex_pos
225
- logger.debug " pos: >#{$1}<"
226
-
227
- line.sub!( regex_pos, '[ROUND.POS] ' ) ## NB: add back trailing space that got swallowed w/ regex -> [ \t]+
228
- return $1.to_i
229
- elsif line =~ regex_num
230
- ## assume number in name is pos (e.g. Jornada 3, 3 Runde etc.)
231
- ## NB: do NOT remove pos from string (will get removed by round name)
232
-
233
- num = $1.to_i # note: clone capture; keep a copy (another regex follows; will redefine $1)
234
-
235
- #### fix:
236
- # use/make keywords required
237
- # e.g. Round of 16 -> should NOT match 16!
238
- # Spiel um Platz 3 (or 5) etc -> should NOT match 3!
239
- # Round 16 - ok
240
- # thus, check for required keywords
241
-
242
- ## quick hack for round of 16
243
- # todo: mask match e.g. Round of xxx ... and try again - might include something
244
- # reuse pattern for Group XX Replays for example
245
- if line =~ /^\s*Round of \d{1,3}\b/
246
- return nil
247
- end
248
-
249
- logger.debug " pos: >#{num}<"
250
- return num
251
- else
252
- ## fix: add logger.warn no round pos found in line
253
- return nil
254
- end
255
- end # method find_round_pos!
256
-
257
193
  def find_round_def_name!( line )
258
194
  # assume everything before pipe (\) is the round name
259
195
  # strip [ROUND.POS], todo:?? [ROUND.NAME2]
@@ -266,10 +202,6 @@ class MatchParser ## simple match parser for team match schedules
266
202
 
267
203
  ## cut-off everything after (including) pipe (|)
268
204
  buf = buf[ 0...buf.index('|') ]
269
-
270
- # e.g. remove [ROUND.POS], [ROUND.NAME2], [GROUP.NAME+POS] etc.
271
- buf.gsub!( /\[[^\]]+\]/, '' ) ## fix: use helper for (re)use e.g. remove_match_placeholder/marker or similar?
272
- # remove leading and trailing whitespace
273
205
  buf.strip!
274
206
 
275
207
  logger.debug " find_round_def_name! line-after: >>#{buf}<<"
@@ -280,20 +212,38 @@ class MatchParser ## simple match parser for team match schedules
280
212
  buf
281
213
  end
282
214
 
215
+
216
+ ## split by or || or |||
217
+ ## or ++ or +++
218
+ ## or -- or ---
219
+ ## or // or ///
220
+ ## note: allow Final | First Leg as ONE name same as
221
+ ## Final - First Leg or
222
+ ## Final, First Leg
223
+ ## for cut-off always MUST be more than two chars
224
+ ##
225
+ ## todo/check: find a better name than HEADER_SEP(ARATOR) - why? why not?
226
+ ## todo/fix: move to parser utils and add a method split_name or such?
227
+ HEADER_SEP_RE = / [ ]* ## allow (strip) leading spaces
228
+ (?:\|{2,} |
229
+ \+{2,} |
230
+ -{2,} |
231
+ \/{2,}
232
+ )
233
+ [ ]* ## allow (strip) trailing spaces
234
+ /x
235
+
283
236
  def find_round_header_name!( line )
284
237
  # assume everything left is the round name
285
238
  # extract all other items first (round name2, round pos, group name n pos, etc.)
286
239
 
287
- ## todo/fix:
288
- ## cleanup method
289
- ## use buf.index( '//' ) to split string (see found_round_def)
290
- ## why? simpler why not?
291
- ## - do we currently allow groups if name2 present? add example if it works?
292
-
293
240
  buf = line.dup
294
241
  logger.debug " find_round_header_name! line-before: >>#{buf}<<"
295
242
 
296
- buf.gsub!( /\[[^\]]+\]/, '' ) # e.g. remove [ROUND.POS], [ROUND.NAME2], [GROUP.NAME+POS] etc.
243
+
244
+ parts = buf.split( HEADER_SEP_RE )
245
+ buf = parts[0]
246
+
297
247
  buf.strip! # remove leading and trailing whitespace
298
248
 
299
249
  logger.debug " find_round_name! line-after: >>#{buf}<<"
@@ -306,19 +256,30 @@ class MatchParser ## simple match parser for team match schedules
306
256
  buf
307
257
  end
308
258
 
259
+ ## quick hack- collect all "fillwords" by language!!!!
260
+ ## change later and add to sportdb-langs!!!!
261
+ ##
262
+ ## strip all "fillwords" e.g.:
263
+ ## Nachtrag/Postponed/Addition/Supplemento names
264
+ ##
265
+ ## todo/change: find a better name for ROUND_EXTRA_WORDS - why? why not?
266
+ ROUND_EXTRA_WORDS_RE = /\b(?:
267
+ Nachtrag | ## de
268
+ Postponed | ## en
269
+ Addition | ## en
270
+ Supplemento ## es
271
+ )
272
+ \b/ix
309
273
 
310
274
  def parse_round_header( line )
311
275
  logger.debug "parsing round header line: >#{line}<"
312
276
 
313
- ## todo/check/fix:
314
- # make sure Round of 16 will not return pos 16 -- how? possible?
315
- # add unit test too to verify
316
- pos = find_round_pos!( line )
317
-
318
277
  name = find_round_header_name!( line )
319
278
 
320
279
  logger.debug " line: >#{line}<"
321
280
 
281
+ name = name.sub( ROUND_EXTRA_WORDS_RE, '' )
282
+ name = name.strip
322
283
 
323
284
  round = @rounds[ name ]
324
285
  if round.nil? ## auto-add / create if missing
@@ -341,6 +302,11 @@ class MatchParser ## simple match parser for team match schedules
341
302
  ScoreFormats.find!( line )
342
303
  end
343
304
 
305
+ def find_status!( line )
306
+ StatusParser.find!( line )
307
+ end
308
+
309
+
344
310
  def try_parse_game( line )
345
311
  # note: clone line; for possible test do NOT modify in place for now
346
312
  # note: returns true if parsed, false if no match
@@ -368,6 +334,10 @@ class MatchParser ## simple match parser for team match schedules
368
334
  return false
369
335
  end
370
336
 
337
+ ## find (optional) match status e.g. [abandoned] or [replay] or [awarded]
338
+ ## or [cancelled] or [postponed] etc.
339
+ status = find_status!( line ) ## todo/check: allow match status also in geo part (e.g. after @) - why? why not?
340
+
371
341
  ## pos = find_game_pos!( line )
372
342
 
373
343
  date = find_date!( line, start: @start )
@@ -392,20 +362,23 @@ class MatchParser ## simple match parser for team match schedules
392
362
  if @last_round
393
363
  round = @last_round
394
364
  else
395
- ## find (first) matching round by date
396
- @rounds.values.each do |round_rec|
397
- ## note: convert date to date only (no time) with to_date!!!
398
- if (round_rec.start_date && round_rec.end_date) &&
399
- (date.to_date >= round_rec.start_date &&
400
- date.to_date <= round_rec.end_date)
401
- round = round_rec
402
- break
365
+ ## find (first) matching round by date if rounds / matchdays defined
366
+ ## if not rounds / matchdays defined - YES, allow matches WITHOUT rounds!!!
367
+ if @rounds.size > 0
368
+ @rounds.values.each do |round_rec|
369
+ ## note: convert date to date only (no time) with to_date!!!
370
+ if (round_rec.start_date && round_rec.end_date) &&
371
+ (date.to_date >= round_rec.start_date &&
372
+ date.to_date <= round_rec.end_date)
373
+ round = round_rec
374
+ break
375
+ end
376
+ end
377
+ if round.nil?
378
+ puts "!! ERROR - no matching round found for match date:"
379
+ pp date
380
+ exit 1
403
381
  end
404
- end
405
- if round.nil?
406
- puts "!! ERROR - no matching round found for match date:"
407
- pp date
408
- exit 1
409
382
  end
410
383
  end
411
384
 
@@ -419,8 +392,8 @@ class MatchParser ## simple match parser for team match schedules
419
392
  team2: team2, ## note: for now always use mapping value e.g. rec (NOT string e.g. team2.name)
420
393
  score: score,
421
394
  round: round ? round.name : nil, ## note: for now always use string (assume unique canonical name for event)
422
- group: @last_group ? @last_group.name : nil ) ## note: for now always use string (assume unique canonical name for event)
423
-
395
+ group: @last_group ? @last_group.name : nil, ## note: for now always use string (assume unique canonical name for event)
396
+ status: status )
424
397
  ### todo: cache team lookups in hash?
425
398
 
426
399
  =begin
@@ -602,12 +575,29 @@ class MatchParser ## simple match parser for team match schedules
602
575
 
603
576
  if date && team1.nil? && team2.nil?
604
577
  logger.debug( "date header line found: >#{line}<")
605
- logger.debug( " date: #{date}")
578
+ logger.debug( " date: #{date} with start: #{@start}")
606
579
 
607
580
  @last_date = date # keep a reference for later use
608
- return true
581
+
582
+ ### quick "corona" hack - support seasons going beyond 12 month (see swiss league 2019/20 and others!!)
583
+ ## find a better way??
584
+ ## set @start date to full year (e.g. 1.1.) if date.year is @start.year+1
585
+ ## todo/fix: add to linter to check for chronological dates!! - warn if NOT chronological
586
+ ### todo/check: just turn on for 2019/20 season or always? why? why not?
587
+
588
+ ## todo/fix: add switch back to old @start_org
589
+ ## if year is date.year == @start.year-1 -- possible when full date with year set!!!
590
+ if @start.month != 1
591
+ if date.year == @start.year+1
592
+ logger.debug( "!! hack - extending start date to full (next/end) year; assumes all dates are chronologigal - always moving forward" )
593
+ @start_org = @start ## keep a copy of the original (old) start date - why? why not? - not used for now
594
+ @start = Date.new( @start.year+1, 1, 1 )
595
+ end
596
+ end
597
+
598
+ true
609
599
  else
610
- return false
600
+ false
611
601
  end
612
602
  end
613
603