sportdb 1.8.26 → 1.8.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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