sportdb-models 1.18.5 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (162) hide show
  1. checksums.yaml +4 -4
  2. data/Manifest.txt +27 -145
  3. data/Rakefile +4 -5
  4. data/lib/sportdb/models.rb +93 -160
  5. data/lib/sportdb/{deleter.rb → models/deleter.rb} +4 -10
  6. data/lib/sportdb/models/formats.rb +23 -0
  7. data/lib/sportdb/models/models/assoc.rb +38 -0
  8. data/lib/sportdb/models/{badge.rb → models/badge.rb} +1 -1
  9. data/lib/sportdb/models/models/event.rb +55 -0
  10. data/lib/sportdb/models/{forward.rb → models/forward.rb} +3 -3
  11. data/lib/sportdb/models/{goal.rb → models/goal.rb} +1 -1
  12. data/lib/sportdb/models/models/ground.rb +16 -0
  13. data/lib/sportdb/models/{group.rb → models/group.rb} +10 -7
  14. data/lib/sportdb/models/models/league.rb +20 -0
  15. data/lib/sportdb/models/{roster.rb → models/lineup.rb} +3 -4
  16. data/lib/sportdb/models/{game.rb → models/match.rb} +18 -61
  17. data/lib/sportdb/models/{person.rb → models/person.rb} +0 -0
  18. data/lib/sportdb/models/{round.rb → models/round.rb} +1 -6
  19. data/lib/sportdb/models/{season.rb → models/season.rb} +2 -1
  20. data/lib/sportdb/models/{stage.rb → models/stage.rb} +9 -5
  21. data/lib/sportdb/models/{stats/alltime_standing_entry.rb → models/stats/alltime_standing.rb} +9 -1
  22. data/lib/sportdb/models/{stats/event_standing_entry.rb → models/stats/event_standing.rb} +11 -1
  23. data/lib/sportdb/models/{stats/group_standing_entry.rb → models/stats/group_standing.rb} +10 -1
  24. data/lib/sportdb/models/models/team.rb +56 -0
  25. data/lib/sportdb/models/{world → models/world}/city.rb +2 -2
  26. data/lib/sportdb/models/{world → models/world}/continent.rb +0 -0
  27. data/lib/sportdb/models/{world → models/world}/country.rb +0 -0
  28. data/lib/sportdb/models/{world → models/world}/state.rb +0 -0
  29. data/lib/sportdb/{schema.rb → models/schema.rb} +165 -100
  30. data/lib/sportdb/models/stats.rb +23 -0
  31. data/lib/sportdb/models/utils.rb +24 -24
  32. data/lib/sportdb/{version.rb → models/version.rb} +12 -5
  33. data/test/helper.rb +10 -114
  34. data/test/test_changes.rb +38 -38
  35. data/test/test_cursor.rb +15 -15
  36. data/test/test_winner.rb +75 -70
  37. metadata +29 -161
  38. data/lib/sportdb/calc.rb +0 -279
  39. data/lib/sportdb/indexers/team.rb +0 -87
  40. data/lib/sportdb/mapper_teams.rb +0 -24
  41. data/lib/sportdb/matcher.rb +0 -31
  42. data/lib/sportdb/models/assoc.rb +0 -106
  43. data/lib/sportdb/models/assoc_assoc.rb +0 -15
  44. data/lib/sportdb/models/event.rb +0 -66
  45. data/lib/sportdb/models/event_ground.rb +0 -15
  46. data/lib/sportdb/models/event_team.rb +0 -16
  47. data/lib/sportdb/models/ground.rb +0 -100
  48. data/lib/sportdb/models/group_team.rb +0 -14
  49. data/lib/sportdb/models/league.rb +0 -83
  50. data/lib/sportdb/models/stage_team.rb +0 -14
  51. data/lib/sportdb/models/stats/alltime_standing.rb +0 -44
  52. data/lib/sportdb/models/stats/event_standing.rb +0 -55
  53. data/lib/sportdb/models/stats/group_standing.rb +0 -50
  54. data/lib/sportdb/models/team.rb +0 -119
  55. data/lib/sportdb/models/team_compat.rb +0 -64
  56. data/lib/sportdb/patterns.rb +0 -37
  57. data/lib/sportdb/pretty_printer.rb +0 -175
  58. data/lib/sportdb/reader.rb +0 -132
  59. data/lib/sportdb/reader_file.rb +0 -131
  60. data/lib/sportdb/reader_zip.rb +0 -172
  61. data/lib/sportdb/readers/assoc.rb +0 -54
  62. data/lib/sportdb/readers/event.rb +0 -253
  63. data/lib/sportdb/readers/event_meta.rb +0 -133
  64. data/lib/sportdb/readers/event_table.rb +0 -196
  65. data/lib/sportdb/readers/game.rb +0 -912
  66. data/lib/sportdb/readers/ground.rb +0 -53
  67. data/lib/sportdb/readers/league.rb +0 -54
  68. data/lib/sportdb/readers/season.rb +0 -83
  69. data/lib/sportdb/readers/squad_club.rb +0 -201
  70. data/lib/sportdb/readers/squad_national_team.rb +0 -173
  71. data/lib/sportdb/readers/team.rb +0 -53
  72. data/lib/sportdb/rsssf_reader.rb +0 -367
  73. data/lib/sportdb/standings.rb +0 -178
  74. data/lib/sportdb/stats.rb +0 -27
  75. data/lib/sportdb/utils.rb +0 -89
  76. data/lib/sportdb/utils_date.rb +0 -26
  77. data/lib/sportdb/utils_goals.rb +0 -20
  78. data/lib/sportdb/utils_group.rb +0 -63
  79. data/lib/sportdb/utils_map.rb +0 -44
  80. data/lib/sportdb/utils_round.rb +0 -165
  81. data/lib/sportdb/utils_scores.rb +0 -17
  82. data/lib/sportdb/utils_teams.rb +0 -48
  83. data/test/data/at-austria/2013_14/bl.txt +0 -227
  84. data/test/data/at-austria/2013_14/bl.yml +0 -30
  85. data/test/data/at-austria/2013_14/bl_ii.txt +0 -154
  86. data/test/data/at-austria/2013_14/el.txt +0 -4
  87. data/test/data/at-austria/2013_14/el.yml +0 -25
  88. data/test/data/at-austria/2013_14/squads/austria.txt +0 -40
  89. data/test/data/at-austria/2013_14/squads/salzburg.txt +0 -35
  90. data/test/data/at-austria/2014_15/1-bundesliga-ii.txt +0 -158
  91. data/test/data/at-austria/2014_15/1-bundesliga.yml +0 -18
  92. data/test/data/at-austria/2015_16/1-bundesliga-v2.conf.txt +0 -20
  93. data/test/data/at-austria/2015_16/1-bundesliga-v2.yml +0 -20
  94. data/test/data/at-austria/2015_16/1-bundesliga.conf.txt +0 -20
  95. data/test/data/at-austria/2015_16/1-bundesliga.yml +0 -24
  96. data/test/data/at-austria/2015_16/cup.yml +0 -77
  97. data/test/data/at-austria/leagues.txt +0 -11
  98. data/test/data/at-austria/teams.txt +0 -68
  99. data/test/data/at-austria/teams_2.txt +0 -21
  100. data/test/data/csv/de-2013-14--1-bundesliga.txt +0 -307
  101. data/test/data/de-deutschland/2013-14/1-bundesliga.yml +0 -26
  102. data/test/data/de-deutschland/leagues.txt +0 -4
  103. data/test/data/de-deutschland/teams.txt +0 -53
  104. data/test/data/eng-england/2015-16/1-premierleague-v2.yml +0 -2
  105. data/test/data/eng-england/2015-16/1-premierleague.yml +0 -5
  106. data/test/data/national-teams/assocs.txt +0 -231
  107. data/test/data/national-teams/europe/assocs.txt +0 -13
  108. data/test/data/national-teams/europe/teams.txt +0 -13
  109. data/test/data/national-teams/north-america/assocs.txt +0 -10
  110. data/test/data/national-teams/north-america/teams.txt +0 -7
  111. data/test/data/national-teams/teams.txt +0 -19
  112. data/test/data/players/europe/at-austria/players.txt +0 -45
  113. data/test/data/players/europe/de-deutschland/players.txt +0 -41
  114. data/test/data/players/south-america/br-brazil/players.txt +0 -51
  115. data/test/data/rsssf/at-2014-15--1-bundesliga.txt +0 -339
  116. data/test/data/rsssf/at-2015-16--1-bundesliga.txt +0 -18
  117. data/test/data/world-cup/1930/cup.txt +0 -71
  118. data/test/data/world-cup/1930/cup.yml +0 -23
  119. data/test/data/world-cup/1930/cup_goals.txt +0 -47
  120. data/test/data/world-cup/1930/cup_goals.yml +0 -23
  121. data/test/data/world-cup/1954/cup.txt +0 -90
  122. data/test/data/world-cup/1954/cup.yml +0 -30
  123. data/test/data/world-cup/1962/cup.txt +0 -86
  124. data/test/data/world-cup/1962/cup.yml +0 -32
  125. data/test/data/world-cup/1974/cup.yml +0 -35
  126. data/test/data/world-cup/1974/cup_finals.txt +0 -14
  127. data/test/data/world-cup/1974/cup_i.txt +0 -55
  128. data/test/data/world-cup/1974/cup_ii.txt +0 -34
  129. data/test/data/world-cup/2014/cup.txt +0 -5
  130. data/test/data/world-cup/2014/cup.yml +0 -54
  131. data/test/data/world-cup/2014/squads/br-brazil.txt +0 -46
  132. data/test/data/world-cup/2014/squads/de-deutschland.txt +0 -8
  133. data/test/data/world-cup/2014/squads/jp-japan.txt +0 -30
  134. data/test/data/world-cup/2014/squads/uy-uruguay.txt +0 -32
  135. data/test/data/world-cup/leagues.txt +0 -5
  136. data/test/data/world-cup/seasons_1930.txt +0 -4
  137. data/test/data/world-cup/seasons_1954.txt +0 -4
  138. data/test/data/world-cup/seasons_1962.txt +0 -4
  139. data/test/data/world-cup/seasons_1974.txt +0 -5
  140. data/test/data/world-cup/teams_1930.txt +0 -26
  141. data/test/data/world-cup/teams_1954.txt +0 -30
  142. data/test/data/world-cup/teams_1962.txt +0 -29
  143. data/test/data/world-cup/teams_1974.txt +0 -29
  144. data/test/test_assoc_reader.rb +0 -199
  145. data/test/test_event_meta_reader.rb +0 -47
  146. data/test/test_event_reader.rb +0 -64
  147. data/test/test_event_table_reader.rb +0 -57
  148. data/test/test_goals.rb +0 -107
  149. data/test/test_indexer_team.rb +0 -34
  150. data/test/test_load.rb +0 -61
  151. data/test/test_pp.rb +0 -35
  152. data/test/test_reader.rb +0 -88
  153. data/test/test_reader_from_string.rb +0 -63
  154. data/test/test_round_auto.rb +0 -370
  155. data/test/test_round_def.rb +0 -109
  156. data/test/test_round_header.rb +0 -183
  157. data/test/test_rsssf_reader.rb +0 -76
  158. data/test/test_squad_club_reader.rb +0 -76
  159. data/test/test_squad_national_team_reader.rb +0 -116
  160. data/test/test_standings.rb +0 -279
  161. data/test/test_standings_ii.rb +0 -46
  162. data/test/test_utils.rb +0 -124
@@ -1,53 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- module SportDb
4
-
5
-
6
- class TeamReader
7
-
8
- include LogUtils::Logging
9
-
10
- ## make models available by default with namespace
11
- # e.g. lets you use Usage instead of Model::Usage
12
- include Models
13
-
14
- def self.from_zip( zip_file, entry_path, more_attribs={} )
15
- ## get text content from zip
16
- entry = zip_file.find_entry( entry_path )
17
-
18
- text = entry.get_input_stream().read()
19
- text = text.force_encoding( Encoding::UTF_8 )
20
-
21
- self.from_string( text, more_attribs )
22
- end
23
-
24
- def self.from_file( path, more_attribs={} )
25
- ## note: assume/enfore utf-8 encoding (with or without BOM - byte order mark)
26
- ## - see textutils/utils.rb
27
- text = File.read_utf8( path )
28
- self.from_string( text, more_attribs )
29
- end
30
-
31
- def self.from_string( text, more_attribs={} )
32
- TeamReader.new( text, more_attribs )
33
- end
34
-
35
- def initialize( text, more_attribs={} )
36
- ## todo/fix: how to add opts={} ???
37
- @text = text
38
- @more_attribs = more_attribs
39
- end
40
-
41
-
42
- def read
43
- reader = ValuesReader.from_string( @text, @more_attribs )
44
-
45
- reader.each_line do |new_attributes, values|
46
- Team.create_or_update_from_values( new_attributes, values )
47
- end # each lines
48
- end
49
-
50
-
51
-
52
- end # class TeamReader
53
- end # module SportDb
@@ -1,367 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- ##
4
- ## note: for now lets only support leagues with rounds (no cups/knockout rounds n groups)
5
- ## (re)add later when needed (e.g. for playoffs etc.)
6
-
7
-
8
- module SportDb
9
-
10
-
11
- class RsssfGameReader ### todo: rename to RsssfLeagueMatchReader ( or use league/cup option?) - why? why not??
12
-
13
- include LogUtils::Logging
14
-
15
- ## make models available by default with namespace
16
- # e.g. lets you use Usage instead of Model::Usage
17
- include Models
18
-
19
- ##
20
- ## todo: add from_file and from_zip too
21
-
22
- def self.from_string( event_or_event_key, text )
23
- self.new( event_or_event_key, text )
24
- end
25
-
26
- def initialize( event_or_event_key, text )
27
- ## todo/fix: how to add opts={} ???
28
- @event_or_event_key = event_or_event_key
29
- @text = text
30
- end
31
-
32
-
33
- def read
34
- ## note: assume active activerecord connection
35
-
36
- if @event_or_event_key.kind_of?( Event )
37
- @event= @event_or_event_key
38
- else ## assume string
39
- @event = Event.find_by!( key: @event_or_event_key )
40
- end
41
-
42
- logger.debug "Event #{@event.key} >#{@event.title}<"
43
-
44
- @mapper_teams = TeamMapper.new( @event.teams )
45
-
46
- ## reset cached values
47
- @patch_round_ids = []
48
-
49
- @last_round = nil
50
- @last_date = nil
51
-
52
- reader = LineReader.from_string( @text )
53
- parse_fixtures( reader )
54
- end # method load_fixtures
55
-
56
-
57
-
58
- RSSSF_FT_REGEX = /\b
59
- (?<score1>\d{1,2})
60
- -
61
- (?<score2>\d{1,2})
62
- \b/x
63
-
64
- def find_rsssf_scores!( line )
65
- # e.g. 1-1 or 0-2 or 3-3
66
-
67
- m = RSSSF_FT_REGEX.match( line )
68
- if m
69
- score1 = m[:score1].to_i
70
- score2 = m[:score2].to_i
71
-
72
- logger.debug " score: >#{score1}-#{score2}<"
73
-
74
- line.sub!( m[0], '[SCORE]' )
75
- else
76
- score1 = nil
77
- score2 = nil
78
- end
79
-
80
- scores = [score1, score2]
81
- scores
82
- end # method find_rsssf_scores!
83
-
84
-
85
- def find_rsssf_date!( line, opts={} )
86
- finder = RsssfDateFinder.new
87
- finder.find!( line, opts )
88
- end
89
-
90
-
91
- RSSSF_ROUND_REGEX = /\b
92
- (?<round>Round)
93
- \s
94
- (?<pos>\d{1,3})
95
- \b/x
96
-
97
- def is_rsssf_round?( line )
98
- RSSSF_ROUND_REGEX.match( line ).nil? == false ## match found if not nil
99
- end
100
-
101
- def find_rsssf_round!( line )
102
- ## todo: check if \b works for run on [Apr 13] too ??
103
- ## todo: allow multiple spaces after round ??
104
-
105
- m = RSSSF_ROUND_REGEX.match( line )
106
- if m
107
- title = m[0] ## note: title is complete match e.g. Round 1, Round 2, etc.
108
- pos = m[:pos].to_i
109
-
110
- logger.debug " title: >#{title}<, pos: >#{pos}<"
111
-
112
- line.sub!( m[0], '[ROUND]' )
113
- else
114
- ## fix: add logger.warn no round pos found in line
115
- title = nil
116
- pos = nil
117
- end
118
-
119
- [title,pos] ## return array; note: [nil,nil] if nothing found
120
- end # method find_rsssf_round!
121
-
122
-
123
- def parse_round_header( line )
124
-
125
- ## todo/fix:
126
- ## simplify - for now round number always required
127
- # e.g. no auto-calculation supported here
128
- # fail if round found w/o number/pos !!!
129
- #
130
- # also remove knockout flag for now (set to always false for now)
131
-
132
- logger.debug "parsing round header line: >#{line}<"
133
-
134
- ## check for date in header first e.g. Round 36 [Jul 20] !!
135
- ## avoid "conflict" with getting "wrong" round number from date etc.
136
- date = find_rsssf_date!( line, start_at: @event.start_at )
137
- if date
138
- @last_date = date
139
- end
140
-
141
- title, pos = find_rsssf_round!( line )
142
-
143
- ## check if pos available; if not auto-number/calculate
144
- if pos.nil?
145
- logger.error( " no round pos found in line >#{line}<; round pos required in rsssf; sorry" )
146
- fail( "round pos required in rsssf; sorry")
147
- end
148
-
149
- logger.debug " line: >#{line}<"
150
-
151
- ## Note: dummy/placeholder start_at, end_at date
152
- ## replace/patch after adding all games for round
153
-
154
- round_attribs = {
155
- title: title,
156
- title2: nil,
157
- knockout: false
158
- }
159
-
160
- round = Round.find_by( event_id: @event.id,
161
- pos: pos )
162
-
163
- if round.present?
164
- logger.debug "update round #{round.id}:"
165
- else
166
- logger.debug "create round:"
167
- round = Round.new
168
-
169
- round_attribs = round_attribs.merge( {
170
- event_id: @event.id,
171
- pos: pos,
172
- ## todo: add num e.g. num == pos for round 1, round 2, etc. - why? why not??
173
- start_at: Date.parse('1911-11-11'),
174
- end_at: Date.parse('1911-11-11')
175
- })
176
- end
177
-
178
- logger.debug round_attribs.to_json
179
-
180
- round.update_attributes!( round_attribs )
181
-
182
- ### store list of round ids for patching start_at/end_at at the end
183
- @patch_round_ids << round.id
184
- @last_round = round ## keep track of last seen round for matches that follow etc.
185
- end
186
-
187
-
188
- def try_parse_game( line )
189
- # note: clone line; for possible test do NOT modify in place for now
190
- # note: returns true if parsed, false if no match
191
- parse_game( line.dup )
192
- end
193
-
194
- def parse_game( line )
195
- logger.debug "parsing game (fixture) line: >#{line}<"
196
-
197
- @mapper_teams.map_teams!( line )
198
- team_keys = @mapper_teams.find_teams!( line )
199
- team1_key = team_keys[0]
200
- team2_key = team_keys[1]
201
-
202
- ## note: if we do NOT find two teams; return false - no match found
203
- if team1_key.nil? || team2_key.nil?
204
- logger.debug " no game match (two teams required) found for line: >#{line}<"
205
- return false
206
- end
207
-
208
- date = find_rsssf_date!( line, start_at: @event.start_at )
209
-
210
- ###
211
- # check if date found?
212
- # note: ruby falsey is nil & false only (not 0 or empty array etc.)
213
- if date
214
- @last_date = date # keep a reference for later use
215
- else
216
- date = @last_date # no date found; (re)use last seen date
217
- end
218
-
219
- scores = find_rsssf_scores!( line )
220
-
221
- logger.debug " line: >#{line}<"
222
-
223
-
224
- ### todo: cache team lookups in hash?
225
- team1 = Team.find_by!( key: team1_key )
226
- team2 = Team.find_by!( key: team2_key )
227
-
228
- round = @last_round
229
-
230
- ### check if games exists
231
- ## with this teams in this round if yes only update
232
- ##
233
- ## todo: add replay flag (true/false) !!!!!!!!
234
- ## allows same match fixture in round !!!!!!!!
235
- game = Game.find_by( round_id: round.id,
236
- team1_id: team1.id,
237
- team2_id: team2.id )
238
-
239
- game_attribs = {
240
- score1: scores[0],
241
- score2: scores[1],
242
- score1et: scores[2],
243
- score2et: scores[3],
244
- score1p: scores[4],
245
- score2p: scores[5],
246
- play_at: date,
247
- play_at_v2: nil,
248
- postponed: false,
249
- knockout: false, ## round.knockout, ## note: for now always use knockout flag from round - why? why not??
250
- ground_id: nil,
251
- group_id: nil
252
- }
253
-
254
- if game.present?
255
- logger.debug "update game #{game.id}:"
256
- else
257
- logger.debug "create game:"
258
- game = Game.new
259
-
260
- ## Note: use round.games.count for pos
261
- ## lets us add games out of order if later needed
262
- more_game_attribs = {
263
- round_id: round.id,
264
- team1_id: team1.id,
265
- team2_id: team2.id,
266
- pos: round.games.count+1
267
- }
268
- game_attribs = game_attribs.merge( more_game_attribs )
269
- end
270
-
271
- logger.debug game_attribs.to_json
272
- game.update_attributes!( game_attribs )
273
-
274
- return true # game match found
275
- end # method parse_game
276
-
277
-
278
- def try_parse_date_header( line )
279
- # note: clone line; for possible test do NOT modify in place for now
280
- # note: returns true if parsed, false if no match
281
- parse_date_header( line.dup )
282
- end
283
-
284
- def parse_date_header( line )
285
- # note: returns true if parsed, false if no match
286
-
287
- # line with NO teams plus include date e.g.
288
- # [Jun 17] etc.
289
-
290
- @mapper_teams.map_teams!( line )
291
- team_keys= @mapper_teams.find_teams!( line )
292
- team1_key = team_keys[0]
293
- team2_key = team_keys[1]
294
-
295
- date = find_rsssf_date!( line, start_at: @event.start_at )
296
-
297
- if date && team1_key.nil? && team2_key.nil?
298
- logger.debug( "date header line found: >#{line}<")
299
- logger.debug( " date: #{date}")
300
-
301
- @last_date = date # keep a reference for later use
302
- return true
303
- else
304
- return false
305
- end
306
- end
307
-
308
-
309
-
310
- def parse_fixtures( reader )
311
-
312
- reader.each_line do |line|
313
-
314
- if is_rsssf_round?( line )
315
- parse_round_header( line )
316
- elsif try_parse_game( line )
317
- # do nothing here
318
- elsif try_parse_date_header( line )
319
- # do nothing here
320
- else
321
- logger.info "skipping line (no match found): >#{line}<"
322
- end
323
- end # lines.each
324
-
325
- ###########################
326
- # backtrack and patch round dates (start_at/end_at)
327
-
328
- unless @patch_round_ids.empty?
329
- ###
330
- # note: use uniq - to allow multiple round headers (possible?)
331
-
332
- Round.find( @patch_round_ids.uniq ).each do |r|
333
- logger.debug "patch round start_at/end_at date for #{r.title}:"
334
-
335
- ## note:
336
- ## will add "scope" pos first e.g
337
- #
338
- ## SELECT "games".* FROM "games" WHERE "games"."round_id" = ?
339
- # ORDER BY pos, play_at asc [["round_id", 7]]
340
- # thus will NOT order by play_at but by pos first!!!
341
- # =>
342
- # need to unscope pos!!! or use unordered_games - games_by_play_at_date etc.??
343
- # thus use reorder()!!! - not just order('play_at asc')
344
-
345
- games = r.games.reorder( 'play_at asc' ).all
346
-
347
- ## skip rounds w/ no games
348
-
349
- ## todo/check/fix: what's the best way for checking assoc w/ 0 recs?
350
- next if games.size == 0
351
-
352
- # note: make sure start_at/end_at is date only (e.g. use play_at.to_date)
353
- # sqlite3 saves datetime in date field as datetime, for example (will break date compares later!)
354
-
355
- round_attribs = {
356
- start_at: games[0].play_at.to_date, # use games.first ?
357
- end_at: games[-1].play_at.to_date # use games.last ? why? why not?
358
- }
359
-
360
- logger.debug round_attribs.to_json
361
- r.update_attributes!( round_attribs )
362
- end
363
- end
364
- end # method parse_fixtures
365
-
366
- end # class RsssfGameReader
367
- end # module SportDb
@@ -1,178 +0,0 @@
1
- # encoding: utf-8
2
-
3
-
4
- ##############
5
- ##
6
- ## fix/todo:
7
- ## - reuse in footballcsv/build e.g. require sportdb and remove "old" code!!!!
8
-
9
- module SportDb
10
-
11
-
12
- class StandingsLine
13
- attr_accessor :rank, :team_name,
14
- :played, :won, :lost, :drawn, ## -- total
15
- :goals_for, :goals_against, :pts,
16
- :home_played, :home_won, :home_lost, :home_drawn, ## -- home
17
- :home_goals_for, :home_goals_against, :home_pts,
18
- :away_played, :away_won, :away_lost, :away_drawn, ## -- away
19
- :away_goals_for, :away_goals_against, :away_pts
20
-
21
- def initialize( team_name )
22
- @rank = nil # use 0? why? why not?
23
- @team_name = team_name
24
- @played = @home_played = @away_played = 0
25
- @won = @home_won = @away_won = 0
26
- @lost = @home_lost = @away_lost = 0
27
- @drawn = @home_drawn = @away_drawn = 0
28
- @goals_for = @home_goals_for = @away_goals_for = 0
29
- @goals_against = @home_goals_against = @away_goals_against = 0
30
- @pts = @home_pts = @away_pts = 0
31
-
32
- ### fix: add @recs too - to count number of records (e.g. appearances/seasons etc.)
33
- end
34
- end # class StandingsLine
35
-
36
-
37
- class Standings
38
-
39
- def initialize( opts={} )
40
- ## fix:
41
- # passing in e.g. pts for win (3? 2? etc.)
42
- # default to 3 for now
43
-
44
- ## lets you pass in 2 as an alterantive, for example
45
- @pts_won = opts[:pts_won] || 3
46
-
47
- @lines = {} # StandingsLines cached by team name/key
48
- end
49
-
50
-
51
- def update( match_or_matches )
52
- puts " [debug] update match_or_matches.class.name: #{match_or_matches.class.name}"
53
-
54
- ## convenience - update all matches at once
55
- if match_or_matches.is_a?( Array ) ||
56
- match_or_matches.is_a?( ActiveRecord::Associations::CollectionProxy )
57
- matches = match_or_matches
58
- matches.each_with_index do |match,i| # note: index(i) starts w/ zero (0)
59
- update_match( match )
60
- end
61
- else
62
- match = match_or_matches
63
- update_match( match )
64
- end
65
- self # note: return self to allow chaining
66
- end
67
-
68
- def to_a
69
- ## return lines; sort and add rank
70
- ## note: will update rank!!!! (side effect)
71
-
72
- #############################
73
- ### calc ranking position (rank)
74
- ## fix/allow same rank e.g. all 1 or more than one team 3rd etc.
75
-
76
- # build array from hash
77
- ary = []
78
- @lines.each do |k,v|
79
- ary << v
80
- end
81
-
82
- ary.sort! do |l,r|
83
- ## note: reverse order (thus, change l,r to r,l)
84
- value = r.pts <=> l.pts
85
- if value == 0 # same pts try goal diff
86
- value = (r.goals_for-r.goals_against) <=> (l.goals_for-l.goals_against)
87
- if value == 0 # same goal diff too; try assume more goals better for now
88
- value = r.goals_for <=> l.goals_for
89
- end
90
- end
91
- value
92
- end
93
-
94
- ## update rank using ordered array
95
- ary.each_with_index do |line,i|
96
- line.rank = i+1 ## add ranking (e.g. 1,2,3 etc.) - note: i starts w/ zero (0)
97
- end
98
-
99
- ary
100
- end # to_a
101
-
102
-
103
- private
104
- def update_match( m ) ## add a match
105
-
106
- ## puts " #{m.team1} - #{m.team2} #{m.score_str}"
107
- unless m.over?
108
- puts " !!!! skipping match - not yet over (play_at date in the future)"
109
- return
110
- end
111
-
112
- unless m.complete?
113
- puts "!!! [calc_standings] skipping match #{m.team1_name} - #{m.team2_name} - scores incomplete #{m.score_str}"
114
- return
115
- end
116
-
117
- ### fix/todo: use team1_name n team2_name ???
118
- ### fix/todo: - add extra time and penalty shootout !!!!
119
-
120
- line1 = @lines[ m.team1_name ] || StandingsLine.new( m.team1_name )
121
- line2 = @lines[ m.team2_name ] || StandingsLine.new( m.team2_name )
122
-
123
- line1.played += 1
124
- line1.home_played += 1
125
-
126
- line2.played += 1
127
- line2.away_played += 1
128
-
129
- if m.winner == 1
130
- line1.won += 1
131
- line1.home_won += 1
132
-
133
- line2.lost += 1
134
- line2.away_lost += 1
135
-
136
- line1.pts += @pts_won
137
- line1.home_pts += @pts_won
138
- elsif m.winner == 2
139
- line1.lost += 1
140
- line1.home_lost += 1
141
-
142
- line2.won += 1
143
- line2.away_won += 1
144
-
145
- line2.pts += @pts_won
146
- line2.away_pts += @pts_won
147
- else ## assume drawn/tie (that is, 0)
148
- line1.drawn += 1
149
- line1.home_drawn += 1
150
-
151
- line2.drawn += 1
152
- line2.away_drawn += 1
153
-
154
- line1.pts += 1
155
- line1.home_pts += 1
156
- line2.pts += 1
157
- line2.away_pts += 1
158
- end
159
-
160
- line1.goals_for += m.score1
161
- line1.home_goals_for += m.score1
162
- line1.goals_against += m.score2
163
- line1.home_goals_against += m.score2
164
-
165
- line2.goals_for += m.score2
166
- line2.away_goals_for += m.score2
167
- line2.goals_against += m.score1
168
- line2.away_goals_against += m.score1
169
-
170
- @lines[ m.team1_name ] = line1
171
- @lines[ m.team2_name ] = line2
172
- end # method update_match
173
-
174
- end # class Standings
175
-
176
-
177
-
178
- end # module SportDb