sportdb-structs 0.1.2 → 0.1.3

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