sportdb-formats 1.1.0 → 1.1.5

Sign up to get free protection for your applications and to get access to all the features.
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