sportdb-formats 1.1.0 → 1.1.5

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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/Manifest.txt +6 -34
  3. data/Rakefile +3 -6
  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 +24 -7
  10. data/lib/sportdb/formats/league/league_reader.rb +7 -1
  11. data/lib/sportdb/formats/match/match_parser.rb +47 -18
  12. data/lib/sportdb/formats/package.rb +59 -11
  13. data/lib/sportdb/formats/team/club_index.rb +13 -11
  14. data/lib/sportdb/formats/team/club_index_history.rb +134 -0
  15. data/lib/sportdb/formats/team/club_reader_history.rb +203 -0
  16. data/lib/sportdb/formats/team/club_reader_props.rb +20 -5
  17. data/lib/sportdb/formats/version.rb +1 -1
  18. data/test/helper.rb +50 -81
  19. data/test/test_club_index_history.rb +107 -0
  20. data/test/test_club_reader_history.rb +212 -0
  21. data/test/test_datafile_package.rb +1 -1
  22. metadata +11 -81
  23. data/lib/sportdb/formats/config.rb +0 -40
  24. data/lib/sportdb/formats/match/match_parser_csv.rb +0 -321
  25. data/lib/sportdb/formats/name_helper.rb +0 -84
  26. data/lib/sportdb/formats/score/score_formats.rb +0 -220
  27. data/lib/sportdb/formats/score/score_parser.rb +0 -202
  28. data/lib/sportdb/formats/season_utils.rb +0 -27
  29. data/lib/sportdb/formats/structs/country.rb +0 -31
  30. data/lib/sportdb/formats/structs/group.rb +0 -18
  31. data/lib/sportdb/formats/structs/league.rb +0 -37
  32. data/lib/sportdb/formats/structs/match.rb +0 -151
  33. data/lib/sportdb/formats/structs/matchlist.rb +0 -220
  34. data/lib/sportdb/formats/structs/round.rb +0 -25
  35. data/lib/sportdb/formats/structs/season.rb +0 -123
  36. data/lib/sportdb/formats/structs/standings.rb +0 -268
  37. data/lib/sportdb/formats/structs/team.rb +0 -150
  38. data/lib/sportdb/formats/structs/team_usage.rb +0 -88
  39. data/test/test_clubs.rb +0 -40
  40. data/test/test_conf.rb +0 -65
  41. data/test/test_csv_match_parser.rb +0 -114
  42. data/test/test_csv_match_parser_utils.rb +0 -20
  43. data/test/test_csv_reader.rb +0 -31
  44. data/test/test_match.rb +0 -30
  45. data/test/test_match_auto.rb +0 -72
  46. data/test/test_match_auto_champs.rb +0 -45
  47. data/test/test_match_auto_euro.rb +0 -37
  48. data/test/test_match_auto_relegation.rb +0 -41
  49. data/test/test_match_auto_worldcup.rb +0 -61
  50. data/test/test_match_champs.rb +0 -27
  51. data/test/test_match_eng.rb +0 -26
  52. data/test/test_match_euro.rb +0 -27
  53. data/test/test_match_worldcup.rb +0 -27
  54. data/test/test_name_helper.rb +0 -67
  55. data/test/test_scores.rb +0 -122
  56. data/test/test_season.rb +0 -62
@@ -1,25 +0,0 @@
1
- module SportDb
2
- module Import
3
-
4
- class Round
5
- attr_reader :name, :start_date, :end_date, :knockout
6
- attr_accessor :num # note: make read & writable - why? why not?
7
-
8
- def initialize( name:,
9
- num: nil,
10
- start_date: nil,
11
- end_date: nil,
12
- knockout: false,
13
- auto: true )
14
- @name = name
15
- @num = num
16
- @start_date = start_date
17
- @end_date = end_date
18
- @knockout = knockout
19
- @auto = auto # auto-created (inline reference/header without proper definition before)
20
- end
21
- end # class Round
22
-
23
- end # module Import
24
- end # module SportDb
25
-
@@ -1,123 +0,0 @@
1
- # encoding: utf-8
2
-
3
-
4
- module SportDb
5
- module Import
6
-
7
-
8
- class Season
9
- ##
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
-
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
23
-
24
-
25
- YYYY_YYYY_RE = %r{^ ## e.g. 2011-2012 or 2011/2012
26
- (\d{4})
27
- [/-]
28
- (\d{4})
29
- $
30
- }x
31
- YYYY_YY_RE = %r{^ ## e.g. 2011-12 or 2011/12
32
- (\d{4})
33
- [/-]
34
- (\d{2})
35
- $
36
- }x
37
- YYYY_Y_RE = %r{^ ## e.g. 2011-2 or 2011/2
38
- (\d{4})
39
- [/-]
40
- (\d{1})
41
- $
42
- }x
43
- YYYY_RE = %r{^ ## e.g. 2011
44
- (\d{4})
45
- $
46
- }x
47
-
48
- def parse( str )
49
- if str =~ YYYY_YYYY_RE ## e.g. 2011/2012
50
- [$1.to_i, $2.to_i]
51
- elsif str =~ YYYY_YY_RE ## e.g. 2011/12
52
- fst = $1.to_i
53
- snd = $2.to_i
54
- 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
56
- [fst, fst+1]
57
- elsif str =~ YYYY_Y_RE ## e.g. 2011/2
58
- fst = $1.to_i
59
- snd = $2.to_i
60
- 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
62
- [fst, fst+1]
63
- elsif str =~ YYYY_RE ## e.g. 2011
64
- [$1.to_i]
65
- else
66
- raise ArgumentError.new( "[Season#parse] unkown season format >>#{str}<<; sorry cannot parse")
67
- end
68
- end
69
-
70
-
71
-
72
- def prev
73
- if year?
74
- Season.new( "#{@start_year-1}" )
75
- else
76
- Season.new( "#{@start_year-1}/#{@start_year}" )
77
- end
78
- end
79
-
80
- def key
81
- if year?
82
- '%d' % @start_year
83
- else
84
- '%d/%02d' % [@start_year, @end_year % 100]
85
- end
86
- end
87
- alias_method :to_key, :key
88
- alias_method :to_s, :key
89
-
90
- alias_method :name, :key
91
- alias_method :title, :key
92
-
93
-
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, ...
98
-
99
- ## convert season name to "standard" season name for directory
100
-
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]
112
- end
113
- end
114
- end # method path
115
- alias_method :directory, :path ## keep "legacy" directory alias - why? why not?
116
- alias_method :to_path, :path
117
-
118
-
119
- end # class Season
120
-
121
-
122
- end # module Import
123
- end # module SportDb
@@ -1,268 +0,0 @@
1
- # encoding: utf-8
2
-
3
- ##########
4
- # todo/fix:
5
- ## reuse standings helper/calculator from sportdb
6
- ## do NOT duplicate
7
-
8
-
9
- module SportDb
10
- module Import
11
-
12
-
13
- class Standings
14
-
15
- class StandingsLine ## nested class StandinsLine - todo/fix: change to Line - why? why not?
16
- attr_accessor :rank, :team,
17
- :played, :won, :lost, :drawn, ## -- total
18
- :goals_for, :goals_against, :pts,
19
- :home_played, :home_won, :home_lost, :home_drawn, ## -- home
20
- :home_goals_for, :home_goals_against, :home_pts,
21
- :away_played, :away_won, :away_lost, :away_drawn, ## -- away
22
- :away_goals_for, :away_goals_against, :away_pts
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
-
28
- def initialize( team )
29
- @rank = nil # use 0? why? why not?
30
- ## change rank back to pos - why? why not?
31
- @team = team
32
- @played = @home_played = @away_played = 0
33
- @won = @home_won = @away_won = 0
34
- @lost = @home_lost = @away_lost = 0
35
- @drawn = @home_drawn = @away_drawn = 0
36
- @goals_for = @home_goals_for = @away_goals_for = 0
37
- @goals_against = @home_goals_against = @away_goals_against = 0
38
- @pts = @home_pts = @away_pts = 0
39
- end
40
- end # (nested) class StandingsLine
41
-
42
-
43
- def initialize( opts={} )
44
- ## fix:
45
- # passing in e.g. pts for win (3? 2? etc.)
46
- # default to 3 for now
47
-
48
- ## lets you pass in 2 as an alterantive, for example
49
- @pts_won = opts[:pts_won] || 3
50
-
51
- @lines = {} # StandingsLines cached by team name/key
52
- end
53
-
54
-
55
- def update( match_or_matches )
56
- ## convenience - update all matches at once
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
63
-
64
- matches.each_with_index do |match,i| # note: index(i) starts w/ zero (0)
65
- update_match( match )
66
- end
67
- self # note: return self to allow chaining
68
- end
69
-
70
-
71
- def to_a
72
- ## return lines; sort and add rank
73
- ## note: will update rank!!!! (side effect)
74
-
75
- #############################
76
- ### calc ranking position (rank)
77
- ## fix/allow same rank e.g. all 1 or more than one team 3rd etc.
78
-
79
- # build array from hash
80
- ary = []
81
- @lines.each do |k,v|
82
- ary << v
83
- end
84
-
85
- ary.sort! do |l,r|
86
- ## note: reverse order (thus, change l,r to r,l)
87
- value = r.pts <=> l.pts
88
- if value == 0 # same pts try goal diff
89
- value = (r.goals_for-r.goals_against) <=> (l.goals_for-l.goals_against)
90
- if value == 0 # same goal diff too; try assume more goals better for now
91
- value = r.goals_for <=> l.goals_for
92
- end
93
- end
94
- value
95
- end
96
-
97
- ## update rank using ordered array
98
- ary.each_with_index do |line,i|
99
- line.rank = i+1 ## add ranking (e.g. 1,2,3 etc.) - note: i starts w/ zero (0)
100
- end
101
-
102
- ary
103
- end # to_a
104
-
105
-
106
-
107
- #####
108
- ###
109
- ## fix: move build to StandingsPart/Report !!!!
110
- def build( source: nil ) ## build / pretty print standings table in string buffer
111
- ## keep pretty printer in struct - why? why not?
112
-
113
-
114
- ## add standings table in markdown to buffer (buf)
115
-
116
- ## todo: use different styles/formats (simple/ etc ???)
117
-
118
- ## simple table (only totals - no home/away)
119
- ## standings.to_a.each do |l|
120
- ## buf << '%2d. ' % l.rank
121
- ## buf << '%-28s ' % l.team
122
- ## buf << '%2d ' % l.played
123
- ## buf << '%3d ' % l.won
124
- ## buf << '%3d ' % l.drawn
125
- ## buf << '%3d ' % l.lost
126
- ## buf << '%3d:%-3d ' % [l.goals_for,l.goals_against]
127
- ## buf << '%3d' % l.pts
128
- ## buf << "\n"
129
- ## end
130
-
131
- buf = ''
132
- buf << "\n"
133
- buf << "```\n"
134
- buf << " - Home - - Away - - Total -\n"
135
- buf << " Pld W D L F:A W D L F:A F:A +/- Pts\n"
136
-
137
- to_a.each do |l|
138
- buf << '%2d. ' % l.rank
139
- buf << '%-28s ' % l.team
140
- buf << '%2d ' % l.played
141
-
142
- buf << '%2d ' % l.home_won
143
- buf << '%2d ' % l.home_drawn
144
- buf << '%2d ' % l.home_lost
145
- buf << '%3d:%-3d ' % [l.home_goals_for,l.home_goals_against]
146
-
147
- buf << '%2d ' % l.away_won
148
- buf << '%2d ' % l.away_drawn
149
- buf << '%2d ' % l.away_lost
150
- buf << '%3d:%-3d ' % [l.away_goals_for,l.away_goals_against]
151
-
152
- buf << '%3d:%-3d ' % [l.goals_for,l.goals_against]
153
-
154
- goals_diff = l.goals_for-l.goals_against
155
- if goals_diff > 0
156
- buf << '%3s ' % "+#{goals_diff}"
157
- elsif goals_diff < 0
158
- buf << '%3s ' % "#{goals_diff}"
159
- else ## assume 0
160
- buf << ' '
161
- end
162
-
163
- buf << '%3d' % l.pts
164
- buf << "\n"
165
- end
166
-
167
- buf << "```\n"
168
- buf << "\n"
169
-
170
- ## optinal: add data source if known / present
171
- ## assume (relative) markdown link for now in README.md
172
- if source
173
- buf << "(Source: [`#{source}`](#{source}))\n"
174
- buf << "\n"
175
- end
176
-
177
- buf
178
- end
179
-
180
-
181
- private
182
- def update_match( m ) ## add a match
183
-
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
-
194
- unless m.over?
195
- puts " !!!! skipping match - not yet over (date in the future) => #{m.date}"
196
- return
197
- end
198
-
199
- unless m.complete?
200
- puts "!!! [calc_standings] skipping match #{team1} - #{team2} w/ past date #{m.date} - scores incomplete => #{score}"
201
- return
202
- end
203
-
204
-
205
-
206
- line1 = @lines[ team1 ] || StandingsLine.new( team1 )
207
- line2 = @lines[ team2 ] || StandingsLine.new( team2 )
208
-
209
- line1.played += 1
210
- line1.home_played += 1
211
-
212
- line2.played += 1
213
- line2.away_played += 1
214
-
215
- if m.winner == 1
216
- line1.won += 1
217
- line1.home_won += 1
218
-
219
- line2.lost += 1
220
- line2.away_lost += 1
221
-
222
- line1.pts += @pts_won
223
- line1.home_pts += @pts_won
224
- elsif m.winner == 2
225
- line1.lost += 1
226
- line1.home_lost += 1
227
-
228
- line2.won += 1
229
- line2.away_won += 1
230
-
231
- line2.pts += @pts_won
232
- line2.away_pts += @pts_won
233
- else ## assume drawn/tie (that is, 0)
234
- line1.drawn += 1
235
- line1.home_drawn += 1
236
-
237
- line2.drawn += 1
238
- line2.away_drawn += 1
239
-
240
- line1.pts += 1
241
- line1.home_pts += 1
242
- line2.pts += 1
243
- line2.away_pts += 1
244
- end
245
-
246
- if m.score1 && m.score2
247
- line1.goals_for += m.score1
248
- line1.home_goals_for += m.score1
249
- line1.goals_against += m.score2
250
- line1.home_goals_against += m.score2
251
-
252
- line2.goals_for += m.score2
253
- line2.away_goals_for += m.score2
254
- line2.goals_against += m.score1
255
- line2.away_goals_against += m.score1
256
- else
257
- puts "*** warn: [standings] skipping match with missing scores: #{m.inspect}"
258
- end
259
-
260
- @lines[ team1 ] = line1
261
- @lines[ team2 ] = line2
262
- end # method update_match
263
-
264
- end # class Standings
265
-
266
-
267
- end # module Import
268
- end # module SportDb
@@ -1,150 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module SportDb
4
- module Import
5
-
6
-
7
- ##
8
- ## todo/fix: remove self.create in structs!!! use just new!!!
9
-
10
- class Team
11
- ## todo: use just names for alt_names - why? why not?
12
- attr_accessor :key, :name, :alt_names,
13
- :code, ## code == abbreviation e.g. ARS etc.
14
- :year, :year_end, ## todo/fix: change year to start_year and year_end to end_year (like in season)!!!
15
- :country
16
-
17
-
18
- def names
19
- ## todo/check: add alt_names_auto too? - why? why not?
20
- [@name] + @alt_names
21
- end ## all names
22
-
23
- def key
24
- ## note: auto-generate key "on-the-fly" if missing for now - why? why not?
25
- ## note: quick hack - auto-generate key, that is, remove all non-ascii chars and downcase
26
- @key || @name.downcase.gsub( /[^a-z]/, '' )
27
- end
28
-
29
-
30
- ## special import only attribs
31
- attr_accessor :alt_names_auto ## auto-generated alt names
32
- attr_accessor :wikipedia # wikipedia page name (for english (en))
33
-
34
-
35
- def historic?() @year_end ? true : false; end
36
- alias_method :past?, :historic?
37
-
38
- def wikipedia?() @wikipedia; end
39
- def wikipedia_url
40
- if @wikipedia
41
- ## note: replace spaces with underscore (-)
42
- ## e.g. Club Brugge KV => Club_Brugge_KV
43
- ## todo/check/fix:
44
- ## check if "plain" dash (-) needs to get replaced with typographic dash??
45
- "https://en.wikipedia.org/wiki/#{@wikipedia.gsub(' ','_')}"
46
- else
47
- nil
48
- end
49
- end
50
-
51
-
52
- def initialize( **kwargs )
53
- @alt_names = []
54
- @alt_names_auto = []
55
-
56
- update( kwargs ) unless kwargs.empty?
57
- end
58
-
59
- def update( **kwargs )
60
- @key = kwargs[:key] if kwargs.has_key? :key
61
- @name = kwargs[:name] if kwargs.has_key? :name
62
- @code = kwargs[:code] if kwargs.has_key? :code
63
- @alt_names = kwargs[:alt_names] if kwargs.has_key? :alt_names
64
- self ## note - MUST return self for chaining
65
- end
66
-
67
-
68
- ## helper methods for import only
69
- ## check for duplicates
70
- include NameHelper
71
-
72
- def duplicates?
73
- names = [name] + alt_names + alt_names_auto
74
- names = names.map { |name| normalize( sanitize(name) ) }
75
-
76
- names.size != names.uniq.size
77
- end
78
-
79
- def duplicates
80
- names = [name] + alt_names + alt_names_auto
81
-
82
- ## calculate (count) frequency and select if greater than one
83
- names.reduce( {} ) do |h,name|
84
- norm = normalize( sanitize(name) )
85
- h[norm] ||= []
86
- h[norm] << name; h
87
- end.select { |norm,names| names.size > 1 }
88
- end
89
-
90
-
91
- def add_variants( name_or_names )
92
- names = name_or_names.is_a?(Array) ? name_or_names : [name_or_names]
93
- names.each do |name|
94
- name = sanitize( name )
95
- self.alt_names_auto += variants( name )
96
- end
97
- end
98
- end # class Team
99
-
100
-
101
-
102
- class NationalTeam < Team
103
- def initialize( **kwargs )
104
- super
105
- end
106
-
107
- def update( **kwargs )
108
- super
109
- self ## note - MUST return self for chaining
110
- end
111
-
112
- end # class NationalTeam
113
-
114
-
115
- ########
116
- # more attribs - todo/fix - also add "upstream" to struct & model!!!!!
117
- # district, geos, year_end, country, etc.
118
-
119
- class Club < Team
120
- attr_accessor :ground
121
-
122
- attr_accessor :a, :b
123
- def a?() @a == nil; end ## is a (1st) team / club (i)? if a is NOT set
124
- def b?() @a != nil; end ## is b (2nd/reserve/jr) team / club (ii) if a is set
125
-
126
- ## note: delegate/forward all geo attributes for team b for now (to team a) - keep - why? why not?
127
- attr_writer :city, :district, :geos
128
- def city() @a == nil ? @city : @a.city; end
129
- def district() @a == nil ? @district : @a.district; end
130
- def country() @a == nil ? @country : @a.country; end
131
- def geos() @a == nil ? @geos : @a.geos; end
132
-
133
-
134
- def initialize( **kwargs )
135
- super
136
- end
137
-
138
- def update( **kwargs )
139
- super
140
- @city = kwargs[:city] if kwargs.has_key? :city
141
- ## todo/fix: use city struct - why? why not?
142
- ## todo/fix: add country too or report unused keywords / attributes - why? why not?
143
-
144
- self ## note - MUST return self for chaining
145
- end
146
- end # class Club
147
-
148
-
149
- end # module Import
150
- end # module SportDb