sportdb 1.8.26 → 1.8.27

Sign up to get free protection for your applications and to get access to all the features.
data/Manifest.txt CHANGED
@@ -13,6 +13,7 @@ config/fixtures/ro.yml
13
13
  data/seasons.txt
14
14
  data/setups/all.txt
15
15
  lib/sportdb.rb
16
+ lib/sportdb/calc.rb
16
17
  lib/sportdb/cli/main.rb
17
18
  lib/sportdb/cli/opts.rb
18
19
  lib/sportdb/console.rb
@@ -41,6 +42,12 @@ lib/sportdb/models/roster.rb
41
42
  lib/sportdb/models/round.rb
42
43
  lib/sportdb/models/run.rb
43
44
  lib/sportdb/models/season.rb
45
+ lib/sportdb/models/stats/alltime_standing.rb
46
+ lib/sportdb/models/stats/alltime_standing_entry.rb
47
+ lib/sportdb/models/stats/event_standing.rb
48
+ lib/sportdb/models/stats/event_standing_entry.rb
49
+ lib/sportdb/models/stats/group_standing.rb
50
+ lib/sportdb/models/stats/group_standing_entry.rb
44
51
  lib/sportdb/models/team.rb
45
52
  lib/sportdb/models/track.rb
46
53
  lib/sportdb/models/utils.rb
@@ -148,5 +155,6 @@ test/test_round_auto.rb
148
155
  test/test_round_def.rb
149
156
  test/test_round_header.rb
150
157
  test/test_scores.rb
158
+ test/test_standings.rb
151
159
  test/test_utils.rb
152
160
  test/test_winner.rb
data/bin/sportdb CHANGED
File without changes
data/lib/sportdb.rb CHANGED
@@ -53,6 +53,13 @@ require 'sportdb/models/season'
53
53
  require 'sportdb/models/team'
54
54
  require 'sportdb/models/track'
55
55
 
56
+ require 'sportdb/models/stats/alltime_standing'
57
+ require 'sportdb/models/stats/alltime_standing_entry'
58
+ require 'sportdb/models/stats/event_standing'
59
+ require 'sportdb/models/stats/event_standing_entry'
60
+ require 'sportdb/models/stats/group_standing'
61
+ require 'sportdb/models/stats/group_standing_entry'
62
+
56
63
  require 'sportdb/models/utils' # e.g. GameCursor
57
64
 
58
65
  ## add backwards compatible n convenience namespace
@@ -76,6 +83,7 @@ require 'sportdb/utils_round'
76
83
  require 'sportdb/utils_scores'
77
84
  require 'sportdb/utils_teams'
78
85
  require 'sportdb/matcher'
86
+ require 'sportdb/calc'
79
87
 
80
88
 
81
89
  require 'sportdb/readers/event'
@@ -97,6 +105,7 @@ require 'sportdb/updater'
97
105
  require 'sportdb/deleter'
98
106
  require 'sportdb/stats'
99
107
 
108
+
100
109
  ###############
101
110
  # optional: for convenience add some finders etc. for known fixtures
102
111
  #
@@ -0,0 +1,177 @@
1
+ # encoding: utf-8
2
+
3
+ module SportDb
4
+
5
+
6
+ ##############################################
7
+ # helper/ builds standings table in memory
8
+ # - find a better module name for StandingsHelper ?? why? why not?
9
+
10
+
11
+ module StandingsHelper
12
+
13
+ ## todo:
14
+ ## add team_id to struct - why? why not? - saves a db lookup?
15
+ ## add appearances (event) count or similar - add to struct or use an extension?
16
+ ## == use recs for number of (stats) records?
17
+ Stats = Struct.new(
18
+ :pos,
19
+ :played,
20
+ :won,
21
+ :lost,
22
+ :drawn,
23
+ :goals_for,
24
+ :goals_against,
25
+ :pts )
26
+
27
+
28
+ def self.calc( games, opts={} )
29
+ recs = calc_stats( games, opts )
30
+
31
+ ## update pos (that is, ranking e.g. 1.,2., 3. etc.)
32
+ recs= update_ranking( recs )
33
+
34
+ pp recs
35
+ recs
36
+ end
37
+
38
+
39
+ def self.calc_for_events( events, opts={} )
40
+
41
+ ## todo:
42
+ ## - add tracker for appeareances (stats records counter)
43
+
44
+ alltime_recs = {} # stats recs indexed by team_key
45
+
46
+ events.each do |event|
47
+ puts " update standings for #{event.title}"
48
+ recs = calc_stats( event.games )
49
+
50
+ recs.each do |team_key, rec|
51
+ alltime_rec = alltime_recs[ team_key ] || Stats.new( 0, 0, 0, 0, 0, 0, 0, 0 )
52
+
53
+ ## add stats values
54
+ alltime_rec.played += rec.played
55
+ alltime_rec.won += rec.won
56
+ alltime_rec.lost += rec.lost
57
+ alltime_rec.drawn += rec.drawn
58
+ alltime_rec.goals_for += rec.goals_for
59
+ alltime_rec.goals_against += rec.goals_against
60
+ alltime_rec.pts += rec.pts
61
+
62
+ alltime_recs[ team_key ] = alltime_rec
63
+ end
64
+ end
65
+
66
+ ## update pos (that is, ranking e.g. 1.,2., 3. etc.)
67
+ alltime_recs= update_ranking( alltime_recs )
68
+
69
+ pp alltime_recs
70
+ alltime_recs
71
+ end
72
+
73
+
74
+
75
+ def self.calc_stats( games, opts={} )
76
+
77
+ ## fix:
78
+ # passing in e.g. pts for win (3? 2? etc.)
79
+ # default to 3 for now
80
+
81
+ recs = {}
82
+
83
+ games.each_with_index do |g,i| # note: index(i) starts w/ zero (0)
84
+ puts " [#{i+1}] #{g.team1.title} - #{g.team2.title} #{g.score_str}"
85
+ unless g.over?
86
+ puts " skipping match - not yet over (play_at date in the future)"
87
+ next
88
+ end
89
+ unless g.complete?
90
+ puts " skipping match - scores incomplete"
91
+ next
92
+ end
93
+
94
+ rec1 = recs[ g.team1.key ] || Stats.new( 0, 0, 0, 0, 0, 0, 0, 0 )
95
+ rec2 = recs[ g.team2.key ] || Stats.new( 0, 0, 0, 0, 0, 0, 0, 0 )
96
+
97
+ rec1.played += 1
98
+ rec2.played += 1
99
+
100
+ if g.winner == 1
101
+ rec1.won += 1
102
+ rec2.lost += 1
103
+ rec1.pts += 3 # 3pts for win (hardcoded for now; change - use event setting?)
104
+ elsif g.winner == 2
105
+ rec1.lost += 1
106
+ rec2.won += 1
107
+ rec2.pts += 3 # 3pts for win (hardcoded for now; change - use event setting?)
108
+ else ## assume == 0 (drawn)
109
+ rec1.drawn += 1
110
+ rec2.drawn += 1
111
+ rec1.pts += 1
112
+ rec2.pts += 1
113
+ end
114
+
115
+ rec1.goals_for += g.score1
116
+ rec1.goals_against += g.score2
117
+
118
+ rec2.goals_for += g.score2
119
+ rec2.goals_against += g.score1
120
+
121
+ ## add overtime and penalty??
122
+ ## - for now add only overtime if present
123
+ rec1.goals_for += (g.score1et-g.score1) if g.score1et.present?
124
+ rec1.goals_against += (g.score2et-g.score2) if g.score2et.present?
125
+
126
+ rec2.goals_for += (g.score2et-g.score2) if g.score2et.present?
127
+ rec2.goals_against += (g.score1et-g.score1) if g.score1et.present?
128
+
129
+
130
+ recs[ g.team1.key ] = rec1
131
+ recs[ g.team2.key ] = rec2
132
+ end # each game
133
+
134
+ recs # return records; hash indexed by team key
135
+ end # method calc
136
+
137
+
138
+ def self.update_ranking( recs )
139
+ #############################
140
+ ### calc ranking / pos
141
+ ##
142
+ ## fix/allow sampe pos e.g. all 1 or more than one team 3rd etc.
143
+ ## see sportbook for an example
144
+
145
+ # build array from hash
146
+ ary = []
147
+ recs.each do |k,v|
148
+ ary << [k,v]
149
+ end
150
+
151
+ ary.sort! do |l,r|
152
+ ## note: reverse order (thus, change l,r to r,l)
153
+ value = r[1].pts <=> l[1].pts
154
+ if value == 0 # same pts try goal diff
155
+ value = (r[1].goals_for-r[1].goals_against) <=> (l[1].goals_for-l[1].goals_against)
156
+ if value == 0 # same goal diff too; try assume more goals better for now
157
+ value = r[1].goals_for <=> l[1].goals_for
158
+ end
159
+ end
160
+ value
161
+ end
162
+
163
+ ## update pos using ordered array
164
+ ary.each_with_index do |rec,i|
165
+ k = rec[0]
166
+ v = rec[1]
167
+ v.pos = i+1 ## add ranking (e.g. 1,2,3 etc.) - note: i starts w/ zero (0)
168
+ recs[ k ] = v ## update recs
169
+ end
170
+
171
+ recs
172
+ end # method update_ranking
173
+
174
+
175
+ end # module StandingsHelper
176
+
177
+ end # module SportDb
@@ -10,6 +10,13 @@ module SportDb
10
10
  def run
11
11
  # for now delete all tables
12
12
 
13
+ ## stats
14
+ AlltimeStandingEntry.delete_all
15
+ AlltimeStanding.delete_all
16
+ GroupStandingEntry.delete_all
17
+ GroupStanding.delete_all
18
+
19
+
13
20
  Goal.delete_all
14
21
  Record.delete_all
15
22
 
@@ -0,0 +1,42 @@
1
+ # encoding: utf-8
2
+
3
+ module SportDb
4
+ module Model
5
+
6
+
7
+ class AlltimeStanding < ActiveRecord::Base
8
+
9
+ self.table_name = 'alltime_standings'
10
+
11
+ has_many :entries, class_name: 'SportDb::Model::AlltimeStandingEntry', foreign_key: 'alltime_standing_id', :dependent => :delete_all
12
+
13
+
14
+ def recalc_for_league!( league )
15
+
16
+ recs = StandingsHelper.calc_for_events( league.events )
17
+
18
+ ## - remove (if exit) old entries and add new entries
19
+ entries.delete_all # note: assoc dependent set to :delete_all (defaults to :nullify)
20
+
21
+ recs.each do |team_key,rec|
22
+
23
+ team = Team.find_by_key!( team_key )
24
+ entries.create!(
25
+ team_id: team.id,
26
+ pos: rec.pos,
27
+ played: rec.played,
28
+ won: rec.won,
29
+ drawn: rec.drawn,
30
+ lost: rec.lost,
31
+ goals_for: rec.goals_for,
32
+ goals_against: rec.goals_against,
33
+ pts: rec.pts )
34
+ end
35
+ end # method recalc_for_league!
36
+
37
+
38
+ end # class AlltimeStanding
39
+
40
+
41
+ end # module Model
42
+ end # module SportDb
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ module SportDb
4
+ module Model
5
+
6
+
7
+ class AlltimeStandingEntry < ActiveRecord::Base
8
+
9
+ self.table_name = 'alltime_standing_entries'
10
+
11
+ belongs_to :standing, class_name: 'SportDb::Model::AlltimeStanding', foreign_key: 'alltime_standing_id'
12
+ belongs_to :team
13
+
14
+ ## note:
15
+ ## map standing_id to alltime_standing_id - convenience alias
16
+ def standing_id=(value) write_attribute(:alltime_standing_id, value); end
17
+
18
+
19
+ end # class AlltimeStandingEntry
20
+
21
+
22
+ end # module Model
23
+ end # module SportDb
@@ -0,0 +1,55 @@
1
+ # encoding: utf-8
2
+
3
+ module SportDb
4
+ module Model
5
+
6
+
7
+ class EventStanding < ActiveRecord::Base
8
+
9
+ self.table_name = 'event_standings'
10
+
11
+ has_many :entries, class_name: 'SportDb::Model::EventStandingEntry', foreign_key: 'event_standing_id', :dependent => :delete_all
12
+ belongs_to :event
13
+
14
+ ## convenience helper; recalcs all records
15
+ def self.recalc!() self.order(:id).each { |rec| rec.recalc! }; end
16
+
17
+
18
+ def recalc!
19
+ ## will calculate event standing e.g.
20
+
21
+ ## calc points (pts) - loop over all group games/matches
22
+ # group.games.each do |game|
23
+ # end
24
+
25
+ # todo/fix!!!!!!!!!!:
26
+ # skip knockout rounds - why? why not?
27
+ # make it configure-able?
28
+
29
+ recs = StandingsHelper.calc( event.games )
30
+
31
+ ## - remove (if exit) old entries and add new entries
32
+ entries.delete_all # note: assoc dependent set to :delete_all (defaults to :nullify)
33
+
34
+ ## add empty entries
35
+ event.teams.each do |team|
36
+ puts " adding entry for team #{team.title} (#{team.code})"
37
+ rec = recs[ team.key ] # find (in-memory) stats records
38
+ entries.create!(
39
+ team_id: team.id,
40
+ pos: rec.pos,
41
+ played: rec.played,
42
+ won: rec.won,
43
+ drawn: rec.drawn,
44
+ lost: rec.lost,
45
+ goals_for: rec.goals_for,
46
+ goals_against: rec.goals_against,
47
+ pts: rec.pts )
48
+ end
49
+ end # method recalc!
50
+
51
+
52
+ end # class EventStanding
53
+ end # module Model
54
+
55
+ end # module SportDb
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+
3
+ module SportDb
4
+ module Model
5
+
6
+ class EventStandingEntry < ActiveRecord::Base
7
+
8
+ self.table_name = 'event_standing_entries'
9
+
10
+ belongs_to :standing, class_name: 'SportDb::Model::EventStanding', foreign_key: 'event_standing_id'
11
+ belongs_to :team
12
+
13
+ ## note:
14
+ ## map standing_id to group_standing_id - convenience alias
15
+ def standing_id=(value) write_attribute(:event_standing_id, value); end
16
+
17
+ end # class EventStandingEntry
18
+
19
+
20
+ end # module Model
21
+ end # module SportDb
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+
3
+ module SportDb
4
+ module Model
5
+
6
+
7
+ class GroupStanding < ActiveRecord::Base
8
+
9
+ self.table_name = 'group_standings'
10
+
11
+ has_many :entries, class_name: 'SportDb::Model::GroupStandingEntry', foreign_key: 'group_standing_id', :dependent => :delete_all
12
+ belongs_to :group
13
+
14
+ ## convenience helper; recalcs all records
15
+ def self.recalc!() self.order(:id).each { |rec| rec.recalc! }; end
16
+
17
+
18
+ def recalc!
19
+ ## will calculate group standing e.g.
20
+
21
+ ## calc points (pts) - loop over all group games/matches
22
+ # group.games.each do |game|
23
+ # end
24
+ recs = StandingsHelper.calc( group.games )
25
+
26
+ ## - remove (if exit) old entries and add new entries
27
+ entries.delete_all # note: assoc dependent set to :delete_all (defaults to :nullify)
28
+
29
+ ## add empty entries
30
+ group.teams.each do |team|
31
+ puts " adding entry for team #{team.title} (#{team.code})"
32
+ rec = recs[ team.key ] # find (in-memory) stats records
33
+ entries.create!(
34
+ team_id: team.id,
35
+ pos: rec.pos,
36
+ played: rec.played,
37
+ won: rec.won,
38
+ drawn: rec.drawn,
39
+ lost: rec.lost,
40
+ goals_for: rec.goals_for,
41
+ goals_against: rec.goals_against,
42
+ pts: rec.pts )
43
+ end
44
+ end # method recalc!
45
+
46
+
47
+ end # class GroupStanding
48
+ end # module Model
49
+
50
+ end # module SportDb
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+
3
+ module SportDb
4
+ module Model
5
+
6
+
7
+ class GroupStandingEntry < ActiveRecord::Base
8
+
9
+ self.table_name = 'group_standing_entries'
10
+
11
+ belongs_to :standing, class_name: 'SportDb::Model::GroupStanding', foreign_key: 'group_standing_id'
12
+ belongs_to :team
13
+
14
+ ## note:
15
+ ## map standing_id to group_standing_id - convenience alias
16
+ def standing_id=(value) write_attribute(:group_standing_id, value); end
17
+
18
+ end # class GroupStandingEntry
19
+
20
+
21
+ end # module Model
22
+ end # module SportDb
@@ -297,6 +297,80 @@ create_table :badges do |t|
297
297
  t.timestamps
298
298
  end
299
299
 
300
+
301
+ ############################################
302
+ # stats tables
303
+
304
+ # use tables for standings e.g group_tables? - why? why not?
305
+ #
306
+ # todo: add group_standings per round with pos diffs e.g +1,+2, -3 etc.
307
+
308
+ create_table :group_standings do |t|
309
+ t.references :group, null: false
310
+ t.timestamps
311
+ end
312
+
313
+ create_table :group_standing_entries do |t|
314
+ t.references :group_standing, null: false
315
+ t.references :team, null: false
316
+ t.integer :pos
317
+ t.integer :played
318
+ t.integer :won
319
+ t.integer :lost
320
+ t.integer :drawn
321
+ t.integer :goals_for # todo: find a short name - gf? why? why not?
322
+ t.integer :goals_against # todo: find a shorter name - ga? why? why not?
323
+ t.integer :pts
324
+ t.string :comments
325
+ t.timestamps
326
+ end
327
+
328
+
329
+ create_table :event_standings do |t|
330
+ t.references :event, null: false
331
+ t.timestamps
332
+ end
333
+
334
+ create_table :event_standing_entries do |t|
335
+ t.references :event_standing, null: false
336
+ t.references :team, null: false
337
+ t.integer :pos
338
+ t.integer :played
339
+ t.integer :won
340
+ t.integer :lost
341
+ t.integer :drawn
342
+ t.integer :goals_for # todo: find a short name - gf? or for? why? why not?
343
+ t.integer :goals_against # todo: find a shorter name - ga? or against? why? why not?
344
+ t.integer :pts
345
+ t.string :comments
346
+ t.timestamps
347
+ end
348
+
349
+
350
+ ## flex (free-style/form) standings table - lets you add as many events as you like (not bound to single event/season/etc.)
351
+ ## -use (find a better) a different name? why? why not?
352
+ create_table :alltime_standings do |t|
353
+ t.string :key, null: false
354
+ t.string :title, null: false
355
+ t.timestamps
356
+ end
357
+
358
+ create_table :alltime_standing_entries do |t|
359
+ t.references :alltime_standing, null: false
360
+ t.references :team, null: false
361
+ t.integer :pos
362
+ t.integer :played # todo: use a different name - why? why not?
363
+ t.integer :won
364
+ t.integer :lost
365
+ t.integer :drawn
366
+ t.integer :goals_for # todo: find a short name - gf? why? why not?
367
+ t.integer :goals_against # todo: find a shorter name - ga? why? why not?
368
+ t.integer :pts
369
+ t.string :comments
370
+ t.timestamps
371
+ end
372
+
373
+
300
374
  end # Schema.define
301
375
  end # method up
302
376
 
@@ -1,6 +1,6 @@
1
1
 
2
2
  module SportDb
3
- VERSION = '1.8.26'
3
+ VERSION = '1.8.27'
4
4
  end
5
5
 
6
6
 
data/test/helper.rb CHANGED
@@ -26,10 +26,20 @@ Team = SportDb::Model::Team
26
26
  Roster = SportDb::Model::Roster
27
27
 
28
28
  Round = SportDb::Model::Round
29
+ Group = SportDb::Model::Group
29
30
  Game = SportDb::Model::Game
30
31
  GameCursor = SportDb::Model::GameCursor
31
32
 
32
33
 
34
+ EventStanding = SportDb::Model::EventStanding
35
+ EventStandingEntry = SportDb::Model::EventStandingEntry
36
+ GroupStanding = SportDb::Model::GroupStanding
37
+ GroupStandingEntry = SportDb::Model::GroupStandingEntry
38
+ AlltimeStanding = SportDb::Model::AlltimeStanding
39
+ AlltimeStandingEntry = SportDb::Model::AlltimeStandingEntry
40
+
41
+
42
+
33
43
  ####################
34
44
  # Reader shortcuts
35
45
 
@@ -0,0 +1,250 @@
1
+ # encoding: utf-8
2
+
3
+ ###
4
+ # to run use
5
+ # ruby -I ./lib -I ./test test/test_standings.rb
6
+ # or better
7
+ # rake -I ./lib test
8
+
9
+
10
+ require 'helper'
11
+
12
+
13
+
14
+ class TestStandings < MiniTest::Unit::TestCase
15
+
16
+ def setup
17
+ WorldDb.delete!
18
+ SportDb.delete!
19
+ ## SportDb.read_builtin
20
+
21
+ add_countries
22
+ add_world_cup_1974
23
+ end
24
+
25
+ def add_countries
26
+ countries = [
27
+ ['cd', 'Congo DR', 'COD' ],
28
+ ['kr', 'South Korea', 'KOR' ],
29
+ ['au', 'Australia', 'AUS' ],
30
+
31
+ ['ar', 'Argentina', 'ARG' ],
32
+ ['br', 'Brazil', 'BRA' ],
33
+ ['bo', 'Bolivia', 'BOL' ],
34
+ ['cl', 'Chile', 'CHI' ],
35
+ ['co', 'Colombia', 'COL' ],
36
+ ['uy', 'Uruguay', 'URU' ],
37
+ ['pe', 'Peru', 'PER' ],
38
+ ['py', 'Paraguay', 'PAR' ],
39
+
40
+ ['mx', 'Mexico', 'MEX' ],
41
+ ['us', 'United States', 'USA' ],
42
+ ['ht', 'Haiti', 'HAI' ],
43
+
44
+ ['at', 'Austria', 'AUT' ],
45
+ ['be', 'Belgium', 'BEL' ],
46
+ ['fr', 'France', 'FRA' ],
47
+ ['rs', 'Serbia', 'SRB' ],
48
+ ['ro', 'Romania', 'ROU' ],
49
+ ['bg', 'Bulgaria', 'BUL' ],
50
+ ['cz', 'Czech Republic', 'CZE' ],
51
+ ['en', 'England', 'ENG' ],
52
+ ['de', 'Germany', 'GER' ],
53
+ ['hu', 'Hungary', 'HUN' ],
54
+ ['it', 'Italy', 'ITA' ],
55
+ ['ru', 'Russia', 'RUS' ],
56
+ ['es', 'Spain', 'ESP' ],
57
+ ['ch', 'Switzerland', 'SUI' ],
58
+ ['sc', 'Scotland', 'SCO' ],
59
+ ['tr', 'Turkey', 'TUR' ],
60
+ ['nl', 'Netherlands', 'NED' ],
61
+ ['pl', 'Poland', 'POL' ],
62
+ ['se', 'Sweden', 'SWE' ],
63
+ ]
64
+
65
+ countries.each do |country|
66
+ key = country[0]
67
+ name = country[1]
68
+ code = country[2]
69
+ Country.create!( key: key, name: name, code: code, pop: 1, area: 1)
70
+ end
71
+ end
72
+
73
+
74
+ def add_world_cup_1974
75
+ teamreader = TeamReader.new( SportDb.test_data_path )
76
+ teamreader.read( 'world-cup/teams_1974' )
77
+
78
+ seasonreader = SeasonReader.new( SportDb.test_data_path )
79
+ seasonreader.read( 'world-cup/seasons_1974')
80
+
81
+ leaguereader = LeagueReader.new( SportDb.test_data_path )
82
+ leaguereader.read( 'world-cup/leagues' )
83
+
84
+ gamereader = GameReader.new( SportDb.test_data_path )
85
+ gamereader.read( 'world-cup/1974/cup' )
86
+
87
+ ev = Event.find_by_key!( 'world.1974' )
88
+
89
+ assert_equal 16, ev.teams.count
90
+ assert_equal 38, ev.games.count
91
+ assert_equal 12, ev.rounds.count
92
+ end # method add_world_cup_1974
93
+
94
+
95
+ def test_alltime_standings
96
+ st = AlltimeStanding.create!( key: 'worldcup', title: 'All Time World Cup' )
97
+
98
+ assert_equal 1, AlltimeStanding.count
99
+ assert_equal 0, st.entries.count
100
+
101
+ ## add some team entries
102
+
103
+ arg = Team.find_by_key!( 'arg' )
104
+ bra = Team.find_by_key!( 'bra' )
105
+ ita = Team.find_by_key!( 'ita' )
106
+
107
+ AlltimeStandingEntry.create!( standing_id: st.id, team_id: arg.id )
108
+ AlltimeStandingEntry.create!( standing_id: st.id, team_id: bra.id )
109
+ AlltimeStandingEntry.create!( standing_id: st.id, team_id: ita.id )
110
+
111
+ assert_equal 3, st.entries.count
112
+ assert_equal 3, AlltimeStandingEntry.count
113
+
114
+ st2 = AlltimeStandingEntry.first.standing # check back/parent ref w/ standing belongs_to assoc
115
+ assert_equal 'worldcup', st2.key
116
+ assert_equal 'All Time World Cup', st2.title
117
+
118
+ end # test_alltime_standings
119
+
120
+
121
+ def test_alltime_standings_recalc
122
+ st = AlltimeStanding.create!( key: 'worldcup', title: 'All Time World Cup' )
123
+
124
+ assert_equal 1, AlltimeStanding.count
125
+ assert_equal 0, st.entries.count
126
+
127
+ league = League.find_by_key!( 'world' )
128
+
129
+ st.recalc_for_league!( league )
130
+ assert_equal 16, st.entries.count
131
+ assert_equal 16, AlltimeStandingEntry.count
132
+
133
+ st.recalc_for_league!( league )
134
+ assert_equal 16, st.entries.count
135
+ assert_equal 16, AlltimeStandingEntry.count
136
+ end # test_alltime_standings_recalc
137
+
138
+
139
+ def test_event_standings_recalc
140
+ ev = Event.find_by_key!( 'world.1974' )
141
+
142
+ assert_equal 16, ev.teams.count
143
+
144
+ st = EventStanding.create!( event_id: ev.id )
145
+
146
+ assert_equal 1, EventStanding.count
147
+ assert_equal 0, st.entries.count
148
+
149
+ st.recalc!
150
+ assert_equal 16, st.entries.count
151
+
152
+ st.recalc! ## try again (check update)
153
+ assert_equal 16, st.entries.count
154
+
155
+ ## try global recalc
156
+ EventStandingEntry.delete_all
157
+ assert_equal 1, EventStanding.count
158
+ assert_equal 0, EventStandingEntry.count
159
+
160
+ EventStanding.recalc!
161
+ assert_equal 1, EventStanding.count
162
+ assert_equal 16, EventStandingEntry.count
163
+
164
+ end # test_event_standings_recalc
165
+
166
+
167
+ def test_group_standings_recalc
168
+ g2 = Group.find_by_pos!( 2 ) ## Group 2 | Yugoslavia Brazil Scotland Zaire
169
+
170
+ assert_equal 4, g2.teams.count
171
+
172
+ st2 = GroupStanding.create!( group_id: g2.id )
173
+
174
+ assert_equal 1, GroupStanding.count
175
+ assert_equal 0, st2.entries.count
176
+
177
+ st2.recalc!
178
+ assert_equal 4, st2.entries.count
179
+
180
+ st2.recalc! ## try again (check update)
181
+ assert_equal 4, st2.entries.count
182
+
183
+ ## try global recalc
184
+ GroupStandingEntry.delete_all
185
+ assert_equal 1, GroupStanding.count
186
+ assert_equal 0, GroupStandingEntry.count
187
+
188
+ GroupStanding.recalc!
189
+ assert_equal 1, GroupStanding.count
190
+ assert_equal 4, GroupStandingEntry.count
191
+
192
+ end # test_group_standings_recalc
193
+
194
+
195
+ def test_group_standings
196
+ ## Group 1 | East Germany West Germany Chile Australia
197
+ ## Group 2 | Yugoslavia Brazil Scotland Zaire
198
+ ## Group 3 | Netherlands Sweden Bulgaria Uruguay
199
+ ## Group 4 | Poland Argentina Italy Haiti
200
+
201
+ g2 = Group.find_by_pos!( 2 )
202
+ g4 = Group.find_by_pos!( 4 )
203
+
204
+ assert_equal 4, g2.teams.count
205
+ assert_equal 4, g4.teams.count
206
+
207
+ st2 = GroupStanding.create!( group_id: g2.id )
208
+ st4 = GroupStanding.create!( group_id: g4.id )
209
+
210
+ assert_equal 2, GroupStanding.count
211
+ assert_equal 0, st2.entries.count
212
+ assert_equal 0, st4.entries.count
213
+
214
+ ## add some team entries
215
+ bra = Team.find_by_key!( 'bra' )
216
+ arg = Team.find_by_key!( 'arg' )
217
+ ita = Team.find_by_key!( 'ita' )
218
+
219
+ GroupStandingEntry.create!( standing_id: st2.id, team_id: bra.id )
220
+ GroupStandingEntry.create!( standing_id: st4.id, team_id: arg.id )
221
+ GroupStandingEntry.create!( standing_id: st4.id, team_id: ita.id )
222
+
223
+ assert_equal 1, st2.entries.count
224
+ assert_equal 2, st4.entries.count
225
+ assert_equal 3, GroupStandingEntry.count
226
+
227
+ st2ii = st2.entries.first.standing # check back/parent ref w/ standing belongs_to assoc
228
+ assert_equal g2.title, st2ii.group.title
229
+
230
+
231
+ ## Group I | Netherlands Brazil East Germany Argentina
232
+ ## Group J | West Germany Poland Sweden Yugoslavia
233
+
234
+ gi = Group.find_by_pos!( 9 ) # note: I maps to 9
235
+ gj = Group.find_by_pos!( 10 ) # note: J maps to 10
236
+
237
+ assert_equal 4, gi.teams.count
238
+ assert_equal 4, gj.teams.count
239
+
240
+ sti = GroupStanding.create!( group_id: gi.id )
241
+ stj = GroupStanding.create!( group_id: gj.id )
242
+
243
+ assert_equal 4, GroupStanding.count
244
+ assert_equal 0, sti.entries.count
245
+ assert_equal 0, stj.entries.count
246
+
247
+ end # test_group_standings
248
+
249
+
250
+ end # class TestStandings
metadata CHANGED
@@ -1,183 +1,148 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sportdb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.26
4
+ version: 1.8.27
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
8
  - Gerald Bauer
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2014-05-24 00:00:00.000000000 Z
12
+ date: 2014-05-29 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: props
15
- requirement: !ruby/object:Gem::Requirement
16
+ requirement: &86161750 !ruby/object:Gem::Requirement
17
+ none: false
16
18
  requirements:
17
19
  - - ! '>='
18
20
  - !ruby/object:Gem::Version
19
21
  version: '0'
20
22
  type: :runtime
21
23
  prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ! '>='
25
- - !ruby/object:Gem::Version
26
- version: '0'
24
+ version_requirements: *86161750
27
25
  - !ruby/object:Gem::Dependency
28
26
  name: logutils
29
- requirement: !ruby/object:Gem::Requirement
27
+ requirement: &86161430 !ruby/object:Gem::Requirement
28
+ none: false
30
29
  requirements:
31
30
  - - ! '>='
32
31
  - !ruby/object:Gem::Version
33
32
  version: '0'
34
33
  type: :runtime
35
34
  prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ! '>='
39
- - !ruby/object:Gem::Version
40
- version: '0'
35
+ version_requirements: *86161430
41
36
  - !ruby/object:Gem::Dependency
42
37
  name: textutils
43
- requirement: !ruby/object:Gem::Requirement
38
+ requirement: &86204100 !ruby/object:Gem::Requirement
39
+ none: false
44
40
  requirements:
45
41
  - - ! '>='
46
42
  - !ruby/object:Gem::Version
47
43
  version: '0'
48
44
  type: :runtime
49
45
  prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ! '>='
53
- - !ruby/object:Gem::Version
54
- version: '0'
46
+ version_requirements: *86204100
55
47
  - !ruby/object:Gem::Dependency
56
48
  name: worlddb
57
- requirement: !ruby/object:Gem::Requirement
49
+ requirement: &86203610 !ruby/object:Gem::Requirement
50
+ none: false
58
51
  requirements:
59
52
  - - ! '>='
60
53
  - !ruby/object:Gem::Version
61
54
  version: 2.0.2
62
55
  type: :runtime
63
56
  prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ! '>='
67
- - !ruby/object:Gem::Version
68
- version: 2.0.2
57
+ version_requirements: *86203610
69
58
  - !ruby/object:Gem::Dependency
70
59
  name: tagutils
71
- requirement: !ruby/object:Gem::Requirement
60
+ requirement: &86203300 !ruby/object:Gem::Requirement
61
+ none: false
72
62
  requirements:
73
63
  - - ! '>='
74
64
  - !ruby/object:Gem::Version
75
65
  version: '0'
76
66
  type: :runtime
77
67
  prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ! '>='
81
- - !ruby/object:Gem::Version
82
- version: '0'
68
+ version_requirements: *86203300
83
69
  - !ruby/object:Gem::Dependency
84
70
  name: persondb
85
- requirement: !ruby/object:Gem::Requirement
71
+ requirement: &86202890 !ruby/object:Gem::Requirement
72
+ none: false
86
73
  requirements:
87
74
  - - ! '>='
88
75
  - !ruby/object:Gem::Version
89
76
  version: '0'
90
77
  type: :runtime
91
78
  prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ! '>='
95
- - !ruby/object:Gem::Version
96
- version: '0'
79
+ version_requirements: *86202890
97
80
  - !ruby/object:Gem::Dependency
98
81
  name: activerecord-utils
99
- requirement: !ruby/object:Gem::Requirement
82
+ requirement: &86202550 !ruby/object:Gem::Requirement
83
+ none: false
100
84
  requirements:
101
85
  - - ! '>='
102
86
  - !ruby/object:Gem::Version
103
87
  version: '0'
104
88
  type: :runtime
105
89
  prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ! '>='
109
- - !ruby/object:Gem::Version
110
- version: '0'
90
+ version_requirements: *86202550
111
91
  - !ruby/object:Gem::Dependency
112
92
  name: fetcher
113
- requirement: !ruby/object:Gem::Requirement
93
+ requirement: &86202050 !ruby/object:Gem::Requirement
94
+ none: false
114
95
  requirements:
115
96
  - - ! '>='
116
97
  - !ruby/object:Gem::Version
117
98
  version: '0.3'
118
99
  type: :runtime
119
100
  prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - ! '>='
123
- - !ruby/object:Gem::Version
124
- version: '0.3'
101
+ version_requirements: *86202050
125
102
  - !ruby/object:Gem::Dependency
126
103
  name: gli
127
- requirement: !ruby/object:Gem::Requirement
104
+ requirement: &86201700 !ruby/object:Gem::Requirement
105
+ none: false
128
106
  requirements:
129
107
  - - ! '>='
130
108
  - !ruby/object:Gem::Version
131
109
  version: 2.5.6
132
110
  type: :runtime
133
111
  prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - ! '>='
137
- - !ruby/object:Gem::Version
138
- version: 2.5.6
112
+ version_requirements: *86201700
139
113
  - !ruby/object:Gem::Dependency
140
114
  name: activerecord
141
- requirement: !ruby/object:Gem::Requirement
115
+ requirement: &86201380 !ruby/object:Gem::Requirement
116
+ none: false
142
117
  requirements:
143
118
  - - ! '>='
144
119
  - !ruby/object:Gem::Version
145
120
  version: '0'
146
121
  type: :runtime
147
122
  prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - ! '>='
151
- - !ruby/object:Gem::Version
152
- version: '0'
123
+ version_requirements: *86201380
153
124
  - !ruby/object:Gem::Dependency
154
125
  name: rdoc
155
- requirement: !ruby/object:Gem::Requirement
126
+ requirement: &86200880 !ruby/object:Gem::Requirement
127
+ none: false
156
128
  requirements:
157
129
  - - ~>
158
130
  - !ruby/object:Gem::Version
159
131
  version: '4.0'
160
132
  type: :development
161
133
  prerelease: false
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - ~>
165
- - !ruby/object:Gem::Version
166
- version: '4.0'
134
+ version_requirements: *86200880
167
135
  - !ruby/object:Gem::Dependency
168
136
  name: hoe
169
- requirement: !ruby/object:Gem::Requirement
137
+ requirement: &86200580 !ruby/object:Gem::Requirement
138
+ none: false
170
139
  requirements:
171
140
  - - ~>
172
141
  - !ruby/object:Gem::Version
173
- version: '3.10'
142
+ version: '3.11'
174
143
  type: :development
175
144
  prerelease: false
176
- version_requirements: !ruby/object:Gem::Requirement
177
- requirements:
178
- - - ~>
179
- - !ruby/object:Gem::Version
180
- version: '3.10'
145
+ version_requirements: *86200580
181
146
  description: sportdb - sport.db command line tool
182
147
  email: opensport@googlegroups.com
183
148
  executables:
@@ -203,6 +168,7 @@ files:
203
168
  - data/seasons.txt
204
169
  - data/setups/all.txt
205
170
  - lib/sportdb.rb
171
+ - lib/sportdb/calc.rb
206
172
  - lib/sportdb/cli/main.rb
207
173
  - lib/sportdb/cli/opts.rb
208
174
  - lib/sportdb/console.rb
@@ -231,6 +197,12 @@ files:
231
197
  - lib/sportdb/models/round.rb
232
198
  - lib/sportdb/models/run.rb
233
199
  - lib/sportdb/models/season.rb
200
+ - lib/sportdb/models/stats/alltime_standing.rb
201
+ - lib/sportdb/models/stats/alltime_standing_entry.rb
202
+ - lib/sportdb/models/stats/event_standing.rb
203
+ - lib/sportdb/models/stats/event_standing_entry.rb
204
+ - lib/sportdb/models/stats/group_standing.rb
205
+ - lib/sportdb/models/stats/group_standing_entry.rb
234
206
  - lib/sportdb/models/team.rb
235
207
  - lib/sportdb/models/track.rb
236
208
  - lib/sportdb/models/utils.rb
@@ -338,13 +310,13 @@ files:
338
310
  - test/test_round_def.rb
339
311
  - test/test_round_header.rb
340
312
  - test/test_scores.rb
313
+ - test/test_standings.rb
341
314
  - test/test_utils.rb
342
315
  - test/test_winner.rb
343
316
  - .gemtest
344
317
  homepage: https://github.com/geraldb/sport.db.ruby
345
318
  licenses:
346
319
  - Public Domain
347
- metadata: {}
348
320
  post_install_message: ! '******************************************************************************
349
321
 
350
322
 
@@ -362,32 +334,35 @@ rdoc_options:
362
334
  require_paths:
363
335
  - lib
364
336
  required_ruby_version: !ruby/object:Gem::Requirement
337
+ none: false
365
338
  requirements:
366
339
  - - ! '>='
367
340
  - !ruby/object:Gem::Version
368
341
  version: 1.9.2
369
342
  required_rubygems_version: !ruby/object:Gem::Requirement
343
+ none: false
370
344
  requirements:
371
345
  - - ! '>='
372
346
  - !ruby/object:Gem::Version
373
347
  version: '0'
374
348
  requirements: []
375
349
  rubyforge_project:
376
- rubygems_version: 2.1.10
350
+ rubygems_version: 1.8.17
377
351
  signing_key:
378
- specification_version: 4
352
+ specification_version: 3
379
353
  summary: sportdb - sport.db command line tool
380
354
  test_files:
381
- - test/test_changes.rb
382
- - test/test_cursor.rb
383
355
  - test/test_date.rb
384
356
  - test/test_lang.rb
385
357
  - test/test_load.rb
386
- - test/test_national_team_reader.rb
387
- - test/test_reader.rb
388
- - test/test_round_auto.rb
389
- - test/test_round_def.rb
390
- - test/test_round_header.rb
358
+ - test/test_cursor.rb
359
+ - test/test_standings.rb
391
360
  - test/test_scores.rb
392
- - test/test_utils.rb
393
361
  - test/test_winner.rb
362
+ - test/test_round_def.rb
363
+ - test/test_utils.rb
364
+ - test/test_round_header.rb
365
+ - test/test_round_auto.rb
366
+ - test/test_national_team_reader.rb
367
+ - test/test_reader.rb
368
+ - test/test_changes.rb
checksums.yaml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- SHA1:
3
- metadata.gz: 60505f010e0ff11e3eedb1593fb94f0ae4bb8174
4
- data.tar.gz: 4e299e94a2d5811f79f8029b4f541ba5ae150775
5
- SHA512:
6
- metadata.gz: 11e59f6662a2a51c98af2f0300c6d78cb4ab86c0c1fa09f71cc9a43603c903c3a3d4ac9876ebb80f42b1266cbb05668de1d6b073ffe7ad6cd5ebf25223a5ace4
7
- data.tar.gz: fae8ee08187bd216298366aef6ae904abfa7f8f05e2cd93e44183879257048c621b220ead087ab9b8cc4ec709ee0ffbc05133f888bfb8907a91885bc0ddb2f1f