sportdb-formats 1.0.6 → 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -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,247 +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
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
- def initialize( team )
25
- @rank = nil # use 0? why? why not?
26
- @team = team
27
- @played = @home_played = @away_played = 0
28
- @won = @home_won = @away_won = 0
29
- @lost = @home_lost = @away_lost = 0
30
- @drawn = @home_drawn = @away_drawn = 0
31
- @goals_for = @home_goals_for = @away_goals_for = 0
32
- @goals_against = @home_goals_against = @away_goals_against = 0
33
- @pts = @home_pts = @away_pts = 0
34
- end
35
- end # (nested) class StandingsLine
36
-
37
-
38
- def initialize( opts={} )
39
- ## fix:
40
- # passing in e.g. pts for win (3? 2? etc.)
41
- # default to 3 for now
42
-
43
- ## lets you pass in 2 as an alterantive, for example
44
- @pts_won = opts[:pts_won] || 3
45
-
46
- @lines = {} # StandingsLines cached by team name/key
47
- end
48
-
49
-
50
- def update( match_or_matches )
51
- ## convenience - update all matches at once
52
- matches = match_or_matches.is_a?(Array) ? match_or_matches : [match_or_matches]
53
-
54
- matches.each_with_index do |match,i| # note: index(i) starts w/ zero (0)
55
- update_match( match )
56
- end
57
- self # note: return self to allow chaining
58
- end
59
-
60
-
61
- def to_a
62
- ## return lines; sort and add rank
63
- ## note: will update rank!!!! (side effect)
64
-
65
- #############################
66
- ### calc ranking position (rank)
67
- ## fix/allow same rank e.g. all 1 or more than one team 3rd etc.
68
-
69
- # build array from hash
70
- ary = []
71
- @lines.each do |k,v|
72
- ary << v
73
- end
74
-
75
- ary.sort! do |l,r|
76
- ## note: reverse order (thus, change l,r to r,l)
77
- value = r.pts <=> l.pts
78
- if value == 0 # same pts try goal diff
79
- value = (r.goals_for-r.goals_against) <=> (l.goals_for-l.goals_against)
80
- if value == 0 # same goal diff too; try assume more goals better for now
81
- value = r.goals_for <=> l.goals_for
82
- end
83
- end
84
- value
85
- end
86
-
87
- ## update rank using ordered array
88
- ary.each_with_index do |line,i|
89
- line.rank = i+1 ## add ranking (e.g. 1,2,3 etc.) - note: i starts w/ zero (0)
90
- end
91
-
92
- ary
93
- end # to_a
94
-
95
-
96
-
97
- #####
98
- ###
99
- ## fix: move build to StandingsPart/Report !!!!
100
- def build( source: nil ) ## build / pretty print standings table in string buffer
101
- ## keep pretty printer in struct - why? why not?
102
-
103
-
104
- ## add standings table in markdown to buffer (buf)
105
-
106
- ## todo: use different styles/formats (simple/ etc ???)
107
-
108
- ## simple table (only totals - no home/away)
109
- ## standings.to_a.each do |l|
110
- ## buf << '%2d. ' % l.rank
111
- ## buf << '%-28s ' % l.team
112
- ## buf << '%2d ' % l.played
113
- ## buf << '%3d ' % l.won
114
- ## buf << '%3d ' % l.drawn
115
- ## buf << '%3d ' % l.lost
116
- ## buf << '%3d:%-3d ' % [l.goals_for,l.goals_against]
117
- ## buf << '%3d' % l.pts
118
- ## buf << "\n"
119
- ## end
120
-
121
- buf = ''
122
- buf << "\n"
123
- buf << "```\n"
124
- buf << " - Home - - Away - - Total -\n"
125
- buf << " Pld W D L F:A W D L F:A F:A +/- Pts\n"
126
-
127
- to_a.each do |l|
128
- buf << '%2d. ' % l.rank
129
- buf << '%-28s ' % l.team
130
- buf << '%2d ' % l.played
131
-
132
- buf << '%2d ' % l.home_won
133
- buf << '%2d ' % l.home_drawn
134
- buf << '%2d ' % l.home_lost
135
- buf << '%3d:%-3d ' % [l.home_goals_for,l.home_goals_against]
136
-
137
- buf << '%2d ' % l.away_won
138
- buf << '%2d ' % l.away_drawn
139
- buf << '%2d ' % l.away_lost
140
- buf << '%3d:%-3d ' % [l.away_goals_for,l.away_goals_against]
141
-
142
- buf << '%3d:%-3d ' % [l.goals_for,l.goals_against]
143
-
144
- goals_diff = l.goals_for-l.goals_against
145
- if goals_diff > 0
146
- buf << '%3s ' % "+#{goals_diff}"
147
- elsif goals_diff < 0
148
- buf << '%3s ' % "#{goals_diff}"
149
- else ## assume 0
150
- buf << ' '
151
- end
152
-
153
- buf << '%3d' % l.pts
154
- buf << "\n"
155
- end
156
-
157
- buf << "```\n"
158
- buf << "\n"
159
-
160
- ## optinal: add data source if known / present
161
- ## assume (relative) markdown link for now in README.md
162
- if source
163
- buf << "(Source: [`#{source}`](#{source}))\n"
164
- buf << "\n"
165
- end
166
-
167
- buf
168
- end
169
-
170
-
171
- private
172
- def update_match( m ) ## add a match
173
-
174
- ## puts " #{m.team1} - #{m.team2} #{m.score_str}"
175
- unless m.over?
176
- puts " !!!! skipping match - not yet over (play_at date in the future)"
177
- return
178
- end
179
-
180
- unless m.complete?
181
- puts "!!! [calc_standings] skipping match #{m.team1} - #{m.team2} - scores incomplete #{m.score_str}"
182
- return
183
- end
184
-
185
- line1 = @lines[ m.team1 ] || StandingsLine.new( m.team1 )
186
- line2 = @lines[ m.team2 ] || StandingsLine.new( m.team2 )
187
-
188
- line1.played += 1
189
- line1.home_played += 1
190
-
191
- line2.played += 1
192
- line2.away_played += 1
193
-
194
- if m.winner == 1
195
- line1.won += 1
196
- line1.home_won += 1
197
-
198
- line2.lost += 1
199
- line2.away_lost += 1
200
-
201
- line1.pts += @pts_won
202
- line1.home_pts += @pts_won
203
- elsif m.winner == 2
204
- line1.lost += 1
205
- line1.home_lost += 1
206
-
207
- line2.won += 1
208
- line2.away_won += 1
209
-
210
- line2.pts += @pts_won
211
- line2.away_pts += @pts_won
212
- else ## assume drawn/tie (that is, 0)
213
- line1.drawn += 1
214
- line1.home_drawn += 1
215
-
216
- line2.drawn += 1
217
- line2.away_drawn += 1
218
-
219
- line1.pts += 1
220
- line1.home_pts += 1
221
- line2.pts += 1
222
- line2.away_pts += 1
223
- end
224
-
225
- if m.score1 && m.score2
226
- line1.goals_for += m.score1
227
- line1.home_goals_for += m.score1
228
- line1.goals_against += m.score2
229
- line1.home_goals_against += m.score2
230
-
231
- line2.goals_for += m.score2
232
- line2.away_goals_for += m.score2
233
- line2.goals_against += m.score1
234
- line2.away_goals_against += m.score1
235
- else
236
- puts "*** warn: [standings] skipping match with missing scores: #{m.inspect}"
237
- end
238
-
239
- @lines[ m.team1 ] = line1
240
- @lines[ m.team2 ] = line2
241
- end # method update_match
242
-
243
- end # class Standings
244
-
245
-
246
- end # module Import
247
- 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