sportdb-formats 1.1.1 → 1.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4cdd2bc410771494ed506a24d384ca3c8b1c9684
4
- data.tar.gz: 066f5288da503a00efe280369f57d6cd65bf4bf7
3
+ metadata.gz: 89c3ae173bed0c7a68f30a897e4cf34da8d72d6e
4
+ data.tar.gz: f3898e8b03177b62075cced2a90be2502555bf63
5
5
  SHA512:
6
- metadata.gz: f61edee9495047fc49dfb5720c7afc1e0e316e5fab024d8fc0b1bd5fcdad70524f6e22d24d8fad0aa679380565e0a0c7e36fae79c170655f8a7a496dee170aca
7
- data.tar.gz: b378202d2c8152ac46386618d3c69c03d802b1439e74175f8d84fad304ce111edb0bb1cd848fc969848ce55e0cf8de15a46bec322351d5d199652ed16d41b164
6
+ metadata.gz: 4c938af88f6dd86f1736532c9d8271a3e56f1769b955a31ce6d84a0b1fcf5a6eec7cfa42e0c019bd7072351d777a1988d6637c4297bee0dad9592bb8ec7450e8
7
+ data.tar.gz: a80df68f64e13eeb9a85931e2d2dd4381f204f94a4ea9254c89b4b28346db4c1542321aed4fd123aef5ddedc7e4cd2c08731dd340326fae5dc94b57fa6797835
@@ -8,6 +8,8 @@ lib/sportdb/formats/country/country_index.rb
8
8
  lib/sportdb/formats/country/country_reader.rb
9
9
  lib/sportdb/formats/datafile.rb
10
10
  lib/sportdb/formats/datafile_package.rb
11
+ lib/sportdb/formats/event/event_index.rb
12
+ lib/sportdb/formats/event/event_reader.rb
11
13
  lib/sportdb/formats/goals.rb
12
14
  lib/sportdb/formats/league/league_index.rb
13
15
  lib/sportdb/formats/league/league_outline_reader.rb
@@ -68,6 +70,7 @@ test/test_match_auto_worldcup.rb
68
70
  test/test_match_champs.rb
69
71
  test/test_match_eng.rb
70
72
  test/test_match_euro.rb
73
+ test/test_match_start_date.rb
71
74
  test/test_match_worldcup.rb
72
75
  test/test_name_helper.rb
73
76
  test/test_outline_reader.rb
@@ -136,6 +136,20 @@ end # module Import
136
136
  end # module SportDb
137
137
 
138
138
 
139
+ require 'sportdb/formats/event/event_reader'
140
+ require 'sportdb/formats/event/event_index'
141
+
142
+ ## add convenience helper
143
+ module SportDb
144
+ module Import
145
+ class EventInfo
146
+ def self.read( path ) EventInfoReader.read( path ); end
147
+ def self.parse( txt ) EventInfoReader.parse( txt ); end
148
+ end # class EventInfo
149
+ end # module Import
150
+ end # module SportDb
151
+
152
+
139
153
 
140
154
 
141
155
 
@@ -0,0 +1,143 @@
1
+ module SportDb
2
+ module Import
3
+
4
+
5
+ class EventIndex
6
+
7
+ def self.build( path )
8
+ datafiles = Package.find_seasons( path )
9
+
10
+ puts
11
+ puts "#{datafiles.size} seasons datafile(s):"
12
+ pp datafiles
13
+
14
+ index = new
15
+ datafiles.each do |datafile|
16
+ recs = EventInfoReader.read( datafile )
17
+ # pp recs
18
+
19
+ index.add( recs )
20
+ end
21
+
22
+ index
23
+ end
24
+
25
+
26
+ attr_reader :events
27
+ def initialize
28
+ @events = []
29
+ @leagues = {}
30
+ end
31
+
32
+ def add( recs )
33
+ @events += recs ## add to "linear" records
34
+
35
+ recs.each do |rec|
36
+ league = rec.league
37
+ season = rec.season
38
+
39
+ seasons = @leagues[ league.key ] ||= {}
40
+ seasons[season.key] = rec
41
+ end
42
+ ## build search index by leagues (and season)
43
+ end
44
+
45
+ def find_by( league:, season: )
46
+ league_key = league.is_a?( String ) ? league : league.key
47
+ season_key = season.is_a?( String ) ? season : season.key
48
+
49
+ seasons = @leagues[ league_key ]
50
+ if seasons
51
+ seasons[ season_key ]
52
+ else
53
+ nil
54
+ end
55
+ end # method find_by
56
+ end ## class EventIndex
57
+
58
+
59
+
60
+ class SeasonIndex
61
+ def initialize( *args )
62
+ @leagues = {} ## use a league hash by years for now; change later
63
+
64
+ if args.size == 1 && args[0].is_a?( EventIndex )
65
+ ## convenience setup/hookup
66
+ ## (auto-)add all events from event index
67
+ add( args[0].events )
68
+ else
69
+ pp args
70
+ raise ArgumentError.new( 'unsupported arguments' )
71
+ end
72
+ end
73
+
74
+ def add( recs )
75
+ ## use a lookup index by year for now
76
+ ## todo - find something better/more generic for searching/matching date periods!!!
77
+ recs.each do |rec|
78
+ league = rec.league
79
+ season = rec.season
80
+
81
+ years = @leagues[ league.key ] ||= {}
82
+ if season.year?
83
+ years[season.start_year] ||= []
84
+ years[season.start_year] << rec
85
+ else
86
+ years[season.start_year] ||= []
87
+ years[season.end_year] ||= []
88
+ years[season.start_year] << rec
89
+ years[season.end_year] << rec
90
+ end
91
+ end
92
+ end # method add
93
+
94
+ def find_by( date:, league: )
95
+ date = Date.strptime( date, '%Y-%m-%d' ) if date.is_a?( String )
96
+ league_key = league.is_a?( String ) ? league : league.key
97
+
98
+ years = @leagues[ league_key ]
99
+ if years
100
+ year = years[ date.year ]
101
+ if year
102
+ season_key = nil
103
+ year.each do |event|
104
+ ## todo/check: rename/use between? instead of include? - why? why not?
105
+ if event.include?( date )
106
+ season_key = event.season.key
107
+ break
108
+ end
109
+ end
110
+ if season_key.nil?
111
+ puts "!! WARN: date >#{date}< out-of-seasons for year #{date.year} in league #{league_key}:"
112
+ year.each do |event|
113
+ puts " #{event.season.key} | #{event.start_date} - #{event.end_date}"
114
+ end
115
+ ## retry again and pick season with "overflow" at the end (date is great end_date)
116
+ year.each do |event|
117
+ if date > event.end_date
118
+ diff_in_days = date.to_date.jd - event.end_date.to_date.jd
119
+ puts " +#{diff_in_days} days - adding overflow to #{event.season.key} ending on #{event.end_date} ++ #{date}"
120
+ season_key = event.season.key
121
+ break
122
+ end
123
+ end
124
+ ## exit now for sure - if still empty!!!!
125
+ if season_key.nil?
126
+ puts "!! ERROR: CANNOT auto-fix / (auto-)append date at the end of an event; check season setup - sorry"
127
+ exit 1
128
+ end
129
+ end
130
+ season_key
131
+ else
132
+ nil ## no year defined / found for league
133
+ end
134
+ else
135
+ nil ## no league defined / found
136
+ end
137
+ end # method find
138
+
139
+ end # class SeasonIndex
140
+
141
+
142
+ end # module Import
143
+ end # module SportDb
@@ -0,0 +1,183 @@
1
+
2
+ module SportDb
3
+ module Import
4
+
5
+
6
+ class EventInfo
7
+ ## "high level" info (summary) about event (like a "wikipedia infobox")
8
+ ## use for checking dataset imports; lets you check e.g.
9
+ ## - dates within range
10
+ ## - number of teams e.g. 20
11
+ ## - matches played e.g. 380
12
+ ## - goals scored e.g. 937
13
+ ## etc.
14
+
15
+ attr_reader :league,
16
+ :season,
17
+ :teams,
18
+ :matches,
19
+ :goals,
20
+ :start_date,
21
+ :end_date
22
+
23
+ def initialize( league:, season:,
24
+ start_date: nil, end_date: nil,
25
+ teams: nil,
26
+ matches: nil,
27
+ goals: nil )
28
+
29
+ @league = league
30
+ @season = season
31
+
32
+ @start_date = start_date
33
+ @end_date = end_date
34
+
35
+ @teams = teams ## todo/check: rename/use teams_count ??
36
+ @matches = matches ## todo/check: rename/use match_count ??
37
+ @goals = goals
38
+ end
39
+
40
+ def include?( date )
41
+ ## todo/fix: add options e.g.
42
+ ## - add delta/off_by_one or such?
43
+ ## - add strict (for) only return true if date range (really) defined (no generic auto-rules)
44
+
45
+ ### note: for now allow off by one error (via timezone/local time errors)
46
+ ## todo/fix: issue warning if off by one!!!!
47
+ if @start_date && @end_date
48
+ date >= (@start_date-1) &&
49
+ date <= (@end_date+1)
50
+ else
51
+ if @season.year?
52
+ # assume generic rule
53
+ ## same year e.g. Jan 1 - Dec 31; always true for now
54
+ date.year == @season.start_year
55
+ else
56
+ # assume generic rule
57
+ ## July 1 - June 30 (Y+1)
58
+ ## - todo/check -start for some countries/leagues in June 1 or August 1 ????
59
+ date >= Date.new( @season.start_year, 7, 1 ) &&
60
+ date <= Date.new( @season.end_year, 6, 30 )
61
+ end
62
+ end
63
+ end # method include?
64
+ alias_method :between?, :include?
65
+ end # class EventInfo
66
+
67
+
68
+ class EventInfoReader
69
+ def catalog() Import.catalog; end
70
+
71
+
72
+ def self.read( path )
73
+ txt = File.open( path, 'r:utf-8') {|f| f.read }
74
+ new( txt ).parse
75
+ end
76
+
77
+ def self.parse( txt )
78
+ new( txt ).parse
79
+ end
80
+
81
+ def initialize( txt )
82
+ @txt = txt
83
+ end
84
+
85
+ def parse
86
+ recs = []
87
+
88
+ parse_csv( @txt ).each do |row|
89
+ league_col = row['League']
90
+ season_col = row['Season'] || row['Year']
91
+ dates_col = row['Dates']
92
+
93
+ season = Import::Season.new( season_col )
94
+ league = catalog.leagues.find!( league_col )
95
+
96
+
97
+ dates = []
98
+ if dates_col.nil? || dates_col.empty?
99
+ ## do nothing; no dates - keep dates array empty
100
+ else
101
+ ## squish spaces
102
+ dates_col = dates_col.gsub( /[ ]{2,}/, ' ' ) ## squish/fold spaces
103
+
104
+ puts "#{league.name} (#{league.key}) | #{season.key} | #{dates_col}"
105
+
106
+ ### todo/check: check what parts "Aug 15" return ???
107
+ ### short form for "Aug 15 -" - works?
108
+
109
+ ## todo/fix!!! - check EventInfo.include?
110
+ ## now allow dates with only start_date too!! (WITHOUT end_date)
111
+ parts = dates_col.split( /[ ]*[–-][ ]*/ )
112
+ if parts.size == 1
113
+ pp parts
114
+ dates << DateFormats.parse( parts[0], start: Date.new( season.start_year, 1, 1 ), lang: 'en' )
115
+ pp dates
116
+ elsif parts.size == 2
117
+ pp parts
118
+ dates << DateFormats.parse( parts[0], start: Date.new( season.start_year, 1, 1 ), lang: 'en' )
119
+ dates << DateFormats.parse( parts[1], start: Date.new( season.end_year ? season.end_year : season.start_year, 1, 1 ), lang: 'en' )
120
+ pp dates
121
+
122
+ ## assert/check if period is less than 365 days for now
123
+ diff = dates[1].to_date.jd - dates[0].to_date.jd
124
+ puts "#{diff}d"
125
+ if diff > 365
126
+ puts "!! ERROR - date range / period assertion failed; expected diff < 365 days"
127
+ exit 1
128
+ end
129
+ else
130
+ puts "!! ERRROR - expected data range / period - one or two dates; got #{parts.size}:"
131
+ pp dates_col
132
+ pp parts
133
+ exit 1
134
+ end
135
+ end
136
+
137
+
138
+ teams_col = row['Clubs'] || row['Teams']
139
+ goals_col = row['Goals']
140
+
141
+ ## note: remove (and allow) all non-digits e.g. 370 goals, 20 clubs, etc.
142
+ teams_col = teams_col.gsub( /[^0-9]/, '' ) if teams_col
143
+ goals_col = goals_col.gsub( /[^0-9]/, '' ) if goals_col
144
+
145
+ teams = (teams_col.nil? || teams_col.empty?) ? nil : teams_col.to_i
146
+ goals = (goals_col.nil? || goals_col.empty?) ? nil : goals_col.to_i
147
+
148
+ matches_col = row['Matches']
149
+ ## note: support additions in matches (played) e.g.
150
+ # 132 + 63 Play-off-Spiele
151
+ matches_col = matches_col.gsub( /[^0-9+]/, '' ) if matches_col
152
+
153
+ matches = if matches_col.nil? || matches_col.empty?
154
+ nil
155
+ else
156
+ if matches_col.index( '+' ) ### check for calculations
157
+ ## note: for now only supports additions
158
+ matches_col.split( '+' ).reduce( 0 ) do |sum,str|
159
+ sum + str.to_i
160
+ end
161
+ else ## assume single (integer) number
162
+ matches_col.to_i
163
+ end
164
+ end
165
+
166
+ rec = EventInfo.new( league: league,
167
+ season: season,
168
+ start_date: dates[0],
169
+ end_date: dates[1],
170
+ teams: teams,
171
+ matches: matches,
172
+ goals: goals
173
+ )
174
+ recs << rec
175
+ end # each row
176
+ recs
177
+ end # method parse
178
+ end # class EventInfoReader
179
+
180
+
181
+ end ## module Import
182
+ end ## module SportDb
183
+
@@ -563,12 +563,29 @@ class MatchParser ## simple match parser for team match schedules
563
563
 
564
564
  if date && team1.nil? && team2.nil?
565
565
  logger.debug( "date header line found: >#{line}<")
566
- logger.debug( " date: #{date}")
566
+ logger.debug( " date: #{date} with start: #{@start}")
567
567
 
568
568
  @last_date = date # keep a reference for later use
569
- return true
569
+
570
+ ### quick "corona" hack - support seasons going beyond 12 month (see swiss league 2019/20 and others!!)
571
+ ## find a better way??
572
+ ## set @start date to full year (e.g. 1.1.) if date.year is @start.year+1
573
+ ## todo/fix: add to linter to check for chronological dates!! - warn if NOT chronological
574
+ ### todo/check: just turn on for 2019/20 season or always? why? why not?
575
+
576
+ ## todo/fix: add switch back to old @start_org
577
+ ## if year is date.year == @start.year-1 -- possible when full date with year set!!!
578
+ if @start.month != 1
579
+ if date.year == @start.year+1
580
+ logger.debug( "!! hack - extending start date to full (next/end) year; assumes all dates are chronologigal - always moving forward" )
581
+ @start_org = @start ## keep a copy of the original (old) start date - why? why not? - not used for now
582
+ @start = Date.new( @start.year+1, 1, 1 )
583
+ end
584
+ end
585
+
586
+ true
570
587
  else
571
- return false
588
+ false
572
589
  end
573
590
  end
574
591
 
@@ -95,7 +95,7 @@ module SportDb
95
95
  headers_mapping[:score] = find_header( headers, ['FT'] )
96
96
  headers_mapping[:scorei] = find_header( headers, ['HT'] )
97
97
 
98
- headers_mapping[:round] = find_header( headers, ['Round'] )
98
+ headers_mapping[:round] = find_header( headers, ['Round', 'Matchday'] )
99
99
 
100
100
  ## optional headers - note: find_header returns nil if header NOT found
101
101
  header_stage = find_header( headers, ['Stage'] )
@@ -221,6 +221,9 @@ module SportDb
221
221
  end
222
222
 
223
223
 
224
+ ##
225
+ ## todo/fix: round might not always be just a simple integer number!!!
226
+ ## might be text such as Final | Leg 1 or such!!!!
224
227
  round = nil
225
228
  ## check for (optional) round / matchday
226
229
  if headers_mapping[ :round ]
@@ -13,12 +13,22 @@ module SportDb
13
13
  ## leagues.txt or leagues_en.txt
14
14
  ## remove support for en.leagues.txt - why? why not?
15
15
  LEAGUES_RE = %r{ (?: ^|/ ) # beginning (^) or beginning of path (/)
16
- (?: [a-z]{1,4}\. )? # optional country code/key e.g. eng.clubs.wiki.txt
16
+ (?: [a-z]{1,4}\. )? # optional country code/key e.g. eng.leagues.txt
17
17
  leagues
18
18
  (?:_[a-z0-9_-]+)?
19
19
  \.txt$
20
20
  }x
21
21
 
22
+ ## seasons.txt or seasons_en.txt
23
+ ## remove support for br.seasons.txt - why? why not?
24
+ SEASONS_RE = %r{ (?: ^|/ ) # beginning (^) or beginning of path (/)
25
+ (?: [a-z]{1,4}\. )? # optional country code/key e.g. eng.seasons.txt
26
+ seasons
27
+ (?:_[a-z0-9_-]+)?
28
+ \.txt$
29
+ }x
30
+
31
+
22
32
  ## clubs.txt or clubs_en.txt
23
33
  ## remove support for en.clubs.txt - why? why not?
24
34
  CLUBS_RE = %r{ (?: ^|/ ) # beginning (^) or beginning of path (/)
@@ -49,6 +59,8 @@ module SportDb
49
59
  \.txt$
50
60
  }x
51
61
 
62
+
63
+ ### todo/fix: change SEASON_RE to SEASON_KEY_RE (avoid confusion w/ SEASONS_RE for datafile?) - why? why not? !!!!!!!
52
64
  ### season folder:
53
65
  ## e.g. /2019-20 or
54
66
  ## year-only e.g. /2019 or
@@ -110,6 +122,10 @@ module SportDb
110
122
  def self.find_leagues( path, pattern: LEAGUES_RE ) find( path, pattern ); end
111
123
  def self.match_leagues( path ) LEAGUES_RE.match( path ); end
112
124
 
125
+ def self.find_seasons( path, pattern: SEASONS_RE ) find( path, pattern ); end
126
+ def self.match_seasons( path ) SEASONS_RE.match( path ); end
127
+
128
+
113
129
  def self.find_conf( path, pattern: CONF_RE ) find( path, pattern ); end
114
130
  def self.match_conf( path ) CONF_RE.match( path ); end
115
131
 
@@ -139,6 +155,9 @@ module SportDb
139
155
  alias_method :match_leagues?, :match_leagues
140
156
  alias_method :leagues?, :match_leagues
141
157
 
158
+ alias_method :match_seasons?, :match_seasons
159
+ alias_method :seasons?, :match_seasons
160
+
142
161
  alias_method :match_conf?, :match_conf
143
162
  alias_method :conf?, :match_conf
144
163
  end
@@ -2,21 +2,10 @@
2
2
 
3
3
 
4
4
  module SeasonHelper ## use Helpers why? why not?
5
-
6
5
  ##############################################
7
6
  ### deprecated!!! use new Season class!!!
8
7
  ## this code will get removed!!!!
9
8
  ###################################################
10
-
11
- def prev( str ) SportDb::Import::Season.new( str ).prev; end
12
- def key( str ) SportDb::Import::Season.new( str ).key; end
13
- def directory( str, format: nil ) SportDb::Import::Season.new( str ).directory( format: format ); end
14
-
15
- ## note: new start_year now returns an integer number (no longer a string)!!!
16
- def start_year( str ) SportDb::Import::Season.new( str ).start_year; end
17
- ## note: new end_year now returns an integer number (no longer a string)!!!
18
- ## if now end_year (year? == true) than returns nil (no longer the start_year "as fallback")!!!
19
- def end_year( str ) SportDb::Import::Season.new( str ).end_year; end
20
9
  end # module SeasonHelper
21
10
 
22
11
 
@@ -1,26 +1,19 @@
1
1
  # encoding: utf-8
2
2
 
3
3
 
4
- module SportDb
5
- module Import
4
+ ### note: make Season like Date a "top-level" / "generic" class
5
+
6
6
 
7
7
 
8
8
  class Season
9
9
  ##
10
10
  ## todo: add (optional) start_date and end_date - why? why not?
11
- ## add next
12
-
13
-
14
- attr_reader :start_year,
15
- :end_year
16
11
 
17
- def year?() @end_year.nil?; end ## single-year season e.g. 2011 if no end_year present
18
-
19
-
20
- def initialize( str ) ## assume only string / line gets passed in for now
21
- @start_year, @end_year = parse( str )
22
- end
12
+ ## todo/todo/todo/check/check/check !!!
13
+ ## todo: add a kernel Seaons e.g. Season('2011/12')
14
+ ## forward to Season.convert( *args ) - why? why not?
23
15
 
16
+ ## todo: add unicode - too - why? why not? see wikipedia pages, for example
24
17
 
25
18
  YYYY_YYYY_RE = %r{^ ## e.g. 2011-2012 or 2011/2012
26
19
  (\d{4})
@@ -45,79 +38,155 @@ class Season
45
38
  $
46
39
  }x
47
40
 
48
- def parse( str )
41
+
42
+ def self.parse( str )
43
+ new( *_parse( str ))
44
+ end
45
+
46
+ def self._parse( str ) ## "internal" parse helper
49
47
  if str =~ YYYY_YYYY_RE ## e.g. 2011/2012
50
48
  [$1.to_i, $2.to_i]
51
49
  elsif str =~ YYYY_YY_RE ## e.g. 2011/12
52
50
  fst = $1.to_i
53
51
  snd = $2.to_i
54
52
  snd_exp = '%02d' % [(fst+1) % 100] ## double check: e.g 00 == 00, 01==01 etc.
55
- raise ArgumentError.new( "[Season#parse] invalid year in season >>#{str}<<; expected #{snd_exp} but got #{$2}") if snd_exp != $2
53
+ raise ArgumentError, "[Season.parse] invalid year in season >>#{str}<<; expected #{snd_exp} but got #{$2}" if snd_exp != $2
56
54
  [fst, fst+1]
57
55
  elsif str =~ YYYY_Y_RE ## e.g. 2011/2
58
56
  fst = $1.to_i
59
57
  snd = $2.to_i
60
58
  snd_exp = '%d' % [(fst+1) % 10] ## double check: e.g 0 == 0, 1==1 etc.
61
- raise ArgumentError.new( "[Season#parse] invalid year in season >>#{str}<<; expected #{snd_exp} but got #{$2}") if snd_exp != $2
59
+ raise ArgumentError, "[Season.parse] invalid year in season >>#{str}<<; expected #{snd_exp} but got #{$2}" if snd_exp != $2
62
60
  [fst, fst+1]
63
61
  elsif str =~ YYYY_RE ## e.g. 2011
64
62
  [$1.to_i]
65
63
  else
66
- raise ArgumentError.new( "[Season#parse] unkown season format >>#{str}<<; sorry cannot parse")
64
+ raise ArgumentError, "[Season.parse] unkown season format >>#{str}<<; sorry cannot parse"
65
+ end
66
+ end
67
+
68
+
69
+
70
+ attr_reader :start_year,
71
+ :end_year
72
+
73
+ def initialize( *args ) ## assume only string / line gets passed in for now
74
+ if args.size == 1 && args[0].is_a?( String )
75
+ @start_year, @end_year = self.class._parse( args[0] )
76
+ elsif args.size == 1 && args[0].is_a?( Integer )
77
+ @start_year = args[0]
78
+ @end_year = nil
79
+ elsif args.size == 2 && args[0].is_a?( Integer ) &&
80
+ args[1].is_a?( Integer )
81
+ @start_year = args[0]
82
+ @end_year = args[1]
83
+ end_year_exp = @start_year+1
84
+ raise ArgumentError, "[Season] invalid year in season >>#{to_s}<<; expected #{end_year_exp} but got #{@end_year}" if end_year_exp != @end_year
85
+ else
86
+ pp args
87
+ raise ArgumentError, "[Season] expected season string or season start year (integer) with opt. end year"
88
+ end
89
+ end
90
+
91
+
92
+ ###
93
+ ## convenience helper
94
+ def start_date ## generate "generic / syntetic start date" - keep helper - why? why not?
95
+ if year?
96
+ Date.new( start_year, 1, 1 )
97
+ else
98
+ Date.new( start_year 1, 7 )
67
99
  end
68
100
  end
69
101
 
70
102
 
103
+ ## single-year season e.g. 2011 if no end_year present - todo - find a better name?
104
+ def year?() @end_year.nil?; end
71
105
 
72
106
  def prev
73
107
  if year?
74
- Season.new( "#{@start_year-1}" )
108
+ Season.new( @start_year-1 )
75
109
  else
76
- Season.new( "#{@start_year-1}/#{@start_year}" )
110
+ Season.new( @start_year-1, @start_year )
77
111
  end
78
112
  end
79
113
 
80
- def key
114
+ def next
81
115
  if year?
82
- '%d' % @start_year
116
+ Season.new( @start_year+1 )
83
117
  else
84
- '%d/%02d' % [@start_year, @end_year % 100]
118
+ Season.new( @end_year, @end_year+1 )
85
119
  end
86
120
  end
87
- alias_method :to_key, :key
88
- alias_method :to_s, :key
121
+ alias_method :succ, :next ## add support for ranges
122
+
123
+ include Comparable
124
+ def <=>(other)
125
+ ## todo/fix/fix: check if other is_a?( Season )!!!
126
+ ## what to return if other type/class ??
89
127
 
90
- alias_method :name, :key
91
- alias_method :title, :key
128
+ res = @start_year <=> other.start_year
92
129
 
130
+ ## check special edge case - year season and other e.g.
131
+ ## 2010 <=> 2010/2011
132
+ if res == 0 && @end_year != other.end_year
133
+ res = @end_year ? 1 : -1 # the season with an end year is greater / wins for now
134
+ end
93
135
 
94
- def path( format: nil )
95
- ## todo: find better names for formats - why? why not?:
96
- ## long | archive | decade(?) => 1980s/1988-89, 2010s/2017-18, ...
97
- ## short | std(?) => 1988-89, 2017-18, ...
136
+ res
137
+ end
98
138
 
99
- ## convert season name to "standard" season name for directory
100
139
 
101
- if ['l', 'long', 'archive' ].include?( format.to_s ) ## note: allow passing in of symbol to e.g. 'long' or :long
102
- if year? ## e.g. 2000s/2001
103
- "%3d0s/%4d" % [@start_year / 10, @start_year]
104
- else ## e.g. 2000s/2001-02
105
- "%3d0s/%4d-%02d" % [@start_year / 10, @start_year, @end_year % 100]
106
- end
107
- else ## default 'short' format / fallback
108
- if year? ## e.g. 2001
109
- "%4d" % @start_year
110
- else ## e.g. 2001-02
111
- "%4d-%02d" % [@start_year, @end_year % 100]
140
+
141
+ def to_formatted_s( format=:default, sep: '/' )
142
+ if year?
143
+ '%d' % @start_year
144
+ else
145
+ case format
146
+ when :default, :short, :s ## e.g. 1999/00 or 2019/20
147
+ "%d#{sep}%02d" % [@start_year, @end_year % 100]
148
+ when :long, :l ## e.g. 1999/2000 or 2019/2020
149
+ "%d#{sep}%d" % [@start_year, @end_year]
150
+ else
151
+ raise ArgumentError, "[Season.to_s] unsupported format >#{format}<"
112
152
  end
113
153
  end
114
- end # method path
115
- alias_method :directory, :path ## keep "legacy" directory alias - why? why not?
116
- alias_method :to_path, :path
154
+ end
155
+ alias_method :to_s, :to_formatted_s
156
+
157
+ def key() to_s( :short ); end
158
+ alias_method :to_key, :key
159
+ alias_method :name, :key
160
+ alias_method :title, :key
117
161
 
162
+ alias_method :inspect, :key ## note: add inspect debug support change debug output to string!!
163
+
164
+
165
+
166
+ def to_path( format=:default )
167
+ case format
168
+ when :default, :short, :s ## e.g. 1999-00 or 2019-20
169
+ to_s( :short, sep: '-' )
170
+ when :long, :l ## e.g. 1999-2000 or 2019-2000
171
+ to_s( :long, sep: '-' )
172
+ when :archive, :decade, :d ## e.g. 1990s/1999-00 or 2010s/2019-20
173
+ "%3d0s/%s" % [@start_year / 10, to_s( :short, sep: '-' )]
174
+ when :century, :c ## e.g. 1900s/1990-00 or 2000s/2019-20
175
+ "%2d00s/%s" % [@start_year / 100, to_s( :short, sep: '-' )]
176
+ else
177
+ raise ArgumentError, "[Season.to_path] unsupported format >#{format}<"
178
+ end
179
+ end # method to_path
180
+ alias_method :directory, :to_path ## keep "legacy" directory alias - why? why not?
181
+ alias_method :path, :to_path
118
182
 
119
183
  end # class Season
120
184
 
121
185
 
186
+
187
+
188
+ module SportDb
189
+ module Import
190
+ Season = ::Season ## add a convenience alias
122
191
  end # module Import
123
192
  end # module SportDb
@@ -7,7 +7,7 @@ module Formats
7
7
 
8
8
  MAJOR = 1 ## todo: namespace inside version or something - why? why not??
9
9
  MINOR = 1
10
- PATCH = 1
10
+ PATCH = 2
11
11
  VERSION = [MAJOR,MINOR,PATCH].join('.')
12
12
 
13
13
  def self.version
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+
3
+ ###
4
+ # to run use
5
+ # ruby -I ./lib -I ./test test/test_match_start_date.rb
6
+
7
+
8
+ require 'helper'
9
+
10
+
11
+ class TestMatchStart < MiniTest::Test
12
+
13
+ def test_eng
14
+ txt =<<TXT
15
+ Matchday 1
16
+ [Aug 2]
17
+ A - B
18
+ Matchday 2
19
+ [Jan 3]
20
+ A - B
21
+ Matchday 3
22
+ [Aug 4]
23
+ A - B
24
+ TXT
25
+
26
+ teams =<<TXT
27
+ A
28
+ B
29
+ TXT
30
+ SportDb::Import.config.lang = 'en'
31
+
32
+ start = Date.new( 2017, 7, 1 )
33
+
34
+ parser = SportDb::MatchParser.new( txt, teams, start )
35
+ matches, rounds = parser.parse
36
+
37
+ pp rounds
38
+ pp matches ## only dump last record for now
39
+
40
+ assert_equal Date.new( 2017, 8, 2), matches[0].date
41
+ assert_equal Date.new( 2018, 1, 3), matches[1].date
42
+ assert_equal Date.new( 2018, 8, 4), matches[2].date
43
+ end # method test_end
44
+ end # class TestMatchStart
@@ -9,25 +9,35 @@ require 'helper'
9
9
 
10
10
  class TestSeason < MiniTest::Test
11
11
 
12
- Season = SportDb::Import::Season
13
-
14
- def test_path
15
- assert_equal '2010-11', Season.new( '2010-11' ).path
16
- assert_equal '2010-11', Season.new( '2010-2011' ).path
17
- assert_equal '2010-11', Season.new( '2010/11' ).path
18
- assert_equal '2010-11', Season.new( '2010/1' ).path
19
- assert_equal '2010-11', Season.new( '2010/2011' ).path
20
- assert_equal '2010', Season.new( '2010' ).path
21
-
22
- assert_equal '2010s/2010-11', Season.new( '2010-11' ).path( format: 'long' )
23
- assert_equal '2010s/2010-11', Season.new( '2010-2011' ).path( format: 'long' )
24
- assert_equal '2010s/2010', Season.new( '2010' ).path( format: 'long' )
25
-
26
- assert_equal '1999-00', Season.new( '1999-00' ).path
27
- assert_equal '1999-00', Season.new( '1999-2000' ).path
28
- assert_equal '1990s/1999-00', Season.new( '1999-00' ).path( format: 'long' )
29
- assert_equal '1990s/1999-00', Season.new( '1999-2000' ).path( format: 'long' )
30
- end # method test_path
12
+
13
+ def test_to_path
14
+ assert_equal '2010-11', Season.new( '2010-11' ).to_path
15
+ assert_equal '2010-11', Season.new( '2010-2011' ).to_path
16
+ assert_equal '2010-11', Season.new( '2010/11' ).to_path
17
+ assert_equal '2010-11', Season.new( '2010/1' ).to_path
18
+ assert_equal '2010-11', Season.new( '2010/2011' ).to_path
19
+ assert_equal '2010', Season.new( '2010' ).to_path
20
+
21
+ assert_equal '2010-11', Season.new( 2010, 2011 ).to_path
22
+ assert_equal '2010', Season.new( 2010 ).to_path
23
+
24
+ assert_equal '2010s/2010-11', Season.new( '2010-11' ).to_path( :decade )
25
+ assert_equal '2010s/2010-11', Season.new( '2010-2011' ).to_path( :decade )
26
+ assert_equal '2010s/2010', Season.new( '2010' ).to_path( :decade )
27
+
28
+ assert_equal '1999-00', Season.new( '1999-00' ).to_path
29
+ assert_equal '1999-00', Season.new( '1999-2000' ).to_path
30
+ assert_equal '1990s/1999-00', Season.new( '1999-00' ).to_path( :decade )
31
+ assert_equal '1990s/1999-00', Season.new( '1999-2000' ).to_path( :decade )
32
+
33
+ assert_equal '2000s/2010-11', Season.new( '2010-11' ).to_path( :century )
34
+ assert_equal '2000s/2010-11', Season.new( '2010-2011' ).to_path( :century )
35
+ assert_equal '2000s/2010', Season.new( '2010' ).to_path( :century )
36
+
37
+ assert_equal '1900s/1999-00', Season.new( '1999-00' ).to_path( :century )
38
+ assert_equal '1900s/1999-00', Season.new( '1999-2000' ).to_path( :century )
39
+ end # method test_to_path
40
+
31
41
 
32
42
  def test_key
33
43
  assert_equal '2010/11', Season.new( '2010-11' ).key
@@ -59,4 +69,43 @@ class TestSeason < MiniTest::Test
59
69
  assert_equal '1998/99', Season.new( '1999-00' ).prev.key
60
70
  assert_equal '1998/99', Season.new( '1999-2000' ).prev.key
61
71
  end
72
+
73
+ def test_next
74
+ assert_equal '2009/10', Season.new( '2008-09' ).next.key
75
+ assert_equal '2009/10', Season.new( '2008-2009' ).next.key
76
+ assert_equal '2009', Season.new( '2008' ).next.key
77
+
78
+ assert_equal '1998/99', Season.new( '1997-98' ).next.key
79
+ assert_equal '1998/99', Season.new( '1997-1998' ).next.key
80
+ end
81
+
82
+
83
+ def test_range
84
+ s2010 = Season.new( '2010' )..Season.new( '2019' )
85
+ pp s2010.to_a
86
+ # => [2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019]
87
+
88
+ s2010 = Season.new( '2010-11')..Season.new( '2019-20')
89
+ pp s2010.to_a
90
+ # => [2010/11, 2011/12, 2012/13, 2013/14, 2014/15,
91
+ # 2015/16, 2016/17, 2017/18, 2018/19, 2019/20]
92
+
93
+ puts s2010 === Season.new( '2015-16' ) # true
94
+ puts s2010 === Season.new( '2015' ) # false - why? if using >= <=
95
+ puts s2010 === Season.new( '1999-00' ) # false
96
+ puts s2010 === Season.new( '2020-21' ) # false
97
+
98
+ puts Season.new( '2010-11' ) < Season.new( '2015' ) # true
99
+ puts Season.new( '2015' ) < Season.new( '2019-20') # true
100
+
101
+ puts Season.new( '2015' ) == Season.new( '2015-16') # false
102
+ puts Season.new( '2015' ) < Season.new( '2015-16') # true
103
+ puts Season.new( '2015' ) == Season.new( '2015') # true
104
+
105
+ puts
106
+ puts s2010.include? Season.new( '2015-16' ) # true
107
+ puts s2010.include? Season.new( '2015' ) # false
108
+ puts s2010.include? Season.new( '1999-00' ) # false
109
+ end
110
+
62
111
  end # class TestSeason
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sportdb-formats
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerald Bauer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-15 00:00:00.000000000 Z
11
+ date: 2020-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: alphabets
@@ -127,6 +127,8 @@ files:
127
127
  - lib/sportdb/formats/country/country_reader.rb
128
128
  - lib/sportdb/formats/datafile.rb
129
129
  - lib/sportdb/formats/datafile_package.rb
130
+ - lib/sportdb/formats/event/event_index.rb
131
+ - lib/sportdb/formats/event/event_reader.rb
130
132
  - lib/sportdb/formats/goals.rb
131
133
  - lib/sportdb/formats/league/league_index.rb
132
134
  - lib/sportdb/formats/league/league_outline_reader.rb
@@ -187,6 +189,7 @@ files:
187
189
  - test/test_match_champs.rb
188
190
  - test/test_match_eng.rb
189
191
  - test/test_match_euro.rb
192
+ - test/test_match_start_date.rb
190
193
  - test/test_match_worldcup.rb
191
194
  - test/test_name_helper.rb
192
195
  - test/test_outline_reader.rb