sports 0.0.1 → 0.1.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9ff86ce7425d973d8bb3adc8235bc0889c050fbd
4
- data.tar.gz: 82decba8bbf6f6964612ca0913086224abfdeb1f
3
+ metadata.gz: 831dacee645acf5dea757570924ad7c9e1e2212f
4
+ data.tar.gz: 676b1114696241c5113854fc523821da2a8155ad
5
5
  SHA512:
6
- metadata.gz: '039b38b1e98a51a30390b88dbda7d35035134938af42767f96c7cf0ecf043c70a6ec2c58a99f59e9f0fe98a636755bbff8310def3431ada51a4a142dd668e956'
7
- data.tar.gz: fe78d06e9c4aa9a44ef1bcc26859da1884fa191b1ea4a28d3bd059c2198f91c875a4182b3a65aa569591ef47e0db92123cc96f5ec331e9fe832fb2a7226bf321
6
+ metadata.gz: 61ad3469162b1c9269166ec3e4ed8fa739be3e181e7e0fa74bd3440ef631f046a293fe63752c4c28d9f5c4a856ddc83e6f15b94b347c3c50b773adb2b4b98768
7
+ data.tar.gz: 3cde3acf5f4a7756f0b68d5c4686f374f6cf45f967f4070c8b952e7747e0bf51ebb32d464a4e71b9e887dcac40b7b9ac12e1f6cf3aa1cdb8c270982d2ba73d75
@@ -4,6 +4,7 @@ README.md
4
4
  Rakefile
5
5
  lib/sports.rb
6
6
  lib/sports/config.rb
7
+ lib/sports/goal_parser_csv.rb
7
8
  lib/sports/match_parser_csv.rb
8
9
  lib/sports/match_status_parser.rb
9
10
  lib/sports/name_helper.rb
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # sports - sport data structures for matches, scores, leagues, seasons, rounds, groups, teams, clubs and more"
1
+ # sports - sport data structures for matches, scores, leagues, seasons, rounds, groups, teams, clubs and more
2
2
 
3
3
 
4
4
  * home :: [github.com/sportdb/sport.db](https://github.com/sportdb/sport.db)
@@ -11,7 +11,285 @@
11
11
 
12
12
  ## Usage
13
13
 
14
- To be done
14
+
15
+ ### Working with CSV Datafiles
16
+
17
+ Let's build the standings table for the English Premier League (EPL) for the 2019/20 season from all matches
18
+ in the comma-separated values (.csv) format.
19
+ Example:
20
+
21
+ ```
22
+ - Home - - Away - - Total -
23
+ Pld W D L F:A W D L F:A F:A +/- Pts
24
+ 1. Liverpool FC 38 18 1 0 52:16 14 2 3 33:17 85:33 +52 99
25
+ 2. Manchester City FC 38 15 2 2 57:13 11 1 7 45:22 102:35 +67 81
26
+ 3. Manchester United FC 38 10 7 2 40:17 8 5 6 26:19 66:36 +30 66
27
+ 4. Chelsea FC 38 11 3 5 30:16 9 3 7 39:38 69:54 +15 66
28
+ 5. Leicester City FC 38 11 4 4 35:17 7 4 8 32:24 67:41 +26 62
29
+ 6. Tottenham Hotspur FC 38 12 3 4 36:17 4 8 7 25:30 61:47 +14 59
30
+ 7. Wolverhampton Wanderers FC 38 8 7 4 27:19 7 7 5 24:21 51:40 +11 59
31
+ 8. Arsenal FC 38 10 6 3 36:24 4 8 7 20:24 56:48 +8 56
32
+ 9. Sheffield United FC 38 10 3 6 24:15 4 9 6 15:24 39:39 54
33
+ 10. Burnley FC 38 8 4 7 24:23 7 5 7 19:27 43:50 -7 54
34
+ 11. Southampton FC 38 6 3 10 21:35 9 4 6 30:25 51:60 -9 52
35
+ 12. Everton FC 38 8 7 4 24:21 5 3 11 20:35 44:56 -12 49
36
+ 13. Newcastle United FC 38 6 8 5 20:21 5 3 11 18:37 38:58 -20 44
37
+ 14. Crystal Palace FC 38 6 5 8 15:20 5 5 9 16:30 31:50 -19 43
38
+ 15. Brighton & Hove Albion FC 38 5 7 7 20:27 4 7 8 19:27 39:54 -15 41
39
+ 16. West Ham United FC 38 6 4 9 30:33 4 5 10 19:29 49:62 -13 39
40
+ 17. Aston Villa FC 38 7 3 9 22:30 2 5 12 19:37 41:67 -26 35
41
+ 18. AFC Bournemouth 38 5 6 8 22:30 4 1 14 18:35 40:65 -25 34
42
+ 19. Watford FC 38 6 6 7 22:27 2 4 13 14:37 36:64 -28 34
43
+ 20. Norwich City FC 38 4 3 12 19:37 1 3 15 7:38 26:75 -49 21
44
+ ```
45
+
46
+
47
+ Step 0: Download the free public domain [`/england`](https://github.com/footballcsv/england) dataset package / archive from the [football.csv org](https://footballcsv.github.io).
48
+
49
+ What's the comma-separated values (.csv) format?
50
+ It's the world's most popular tabular data interchange format in text.
51
+ Values are separated - surprise, surprise - by commas (that is, `,`).
52
+ One line is one record, that is, one match :-).
53
+ Example:
54
+
55
+ ```
56
+ Team 1, FT, HT, Team 2
57
+ Liverpool FC, 4-1, 4-0, Norwich City FC
58
+ West Ham United FC, 0-5, 0-1, Manchester City FC
59
+ AFC Bournemouth, 1-1, 0-0, Sheffield United FC
60
+ Burnley FC, 3-0, 0-0, Southampton FC
61
+ Crystal Palace FC, 0-0, 0-0, Everton FC
62
+ Watford FC, 0-3, 0-1, Brighton & Hove Albion FC
63
+ Tottenham Hotspur FC, 3-1, 0-1, Aston Villa FC
64
+ Leicester City FC, 0-0, 0-0, Wolverhampton Wanderers FC
65
+ Newcastle United FC, 0-1, 0-0, Arsenal FC
66
+ Manchester United FC, 4-0, 1-0, Chelsea FC
67
+ ...
68
+ ```
69
+
70
+ Let's use the [`eng.1.csv`](https://github.com/footballcsv/england/blob/master/2010s/2019-20/eng.1.csv), that is, the English Premier League datafile in the `/2010s/2019-20` folder.
71
+ Read in all matches with the `Match.read_csv` method from the sports library / gem:
72
+
73
+
74
+ ``` ruby
75
+ require 'sports'
76
+
77
+ include Sports ## include Match, Team, Standings, etc. data classes
78
+
79
+
80
+ matches = Match.read_csv( 'england/2010s/2019-20/eng.1.csv' )
81
+ pp matches.size #=> 380
82
+ pp matches
83
+ ```
84
+
85
+ will pretty print (pp):
86
+
87
+ ```
88
+ [#<Sports::Match
89
+ @date = "2019-08-09",
90
+ @score1 = 4,
91
+ @score1i = 4,
92
+ @score2 = 1,
93
+ @score2i = 0,
94
+ @team1 = "Liverpool FC",
95
+ @team2 = "Norwich City FC">,
96
+ #<Sports::Match
97
+ @date = "2019-08-10",
98
+ @score1 = 0,
99
+ @score1i = 0,
100
+ @score2 = 5,
101
+ @score2i = 1,
102
+ @team1 = "West Ham United FC",
103
+ @team2 = "Manchester City FC">,
104
+ ...]
105
+ ```
106
+
107
+ Now tally up all matches for the standings table with the standings helper class:
108
+
109
+ ``` ruby
110
+ standings = Standings.new( matches )
111
+ pp standings
112
+ ```
113
+
114
+ will pretty print (pp):
115
+
116
+ ```
117
+ #<Sports::Standings @lines=[
118
+ #<Sports::StandingsLine
119
+ @away_drawn = 0,
120
+ @away_goals_against = 1,
121
+ @away_goals_for = 5,
122
+ @away_lost = 0,
123
+ @away_played = 2,
124
+ @away_pts = 6,
125
+ @away_won = 2,
126
+ @drawn = 0,
127
+ @goals_against = 3,
128
+ @goals_for = 12,
129
+ @home_drawn = 0,
130
+ @home_goals_against = 2,
131
+ @home_goals_for = 7,
132
+ @home_lost = 0,
133
+ @home_played = 2,
134
+ @home_pts = 6,
135
+ @home_won = 2,
136
+ @lost = 0,
137
+ @played = 4,
138
+ @pts = 12,
139
+ @rank = 1,
140
+ @team = "Liverpool FC",
141
+ @won = 4>,
142
+ #<Sports::StandingsLine
143
+ @away_drawn = 0,
144
+ @away_goals_against = 6,
145
+ @away_goals_for = 1,
146
+ @away_lost = 2,
147
+ @away_played = 2,
148
+ @away_pts = 0,
149
+ @away_won = 0,
150
+ @drawn = 0,
151
+ @goals_against = 10,
152
+ @goals_for = 6,
153
+ @home_drawn = 0,
154
+ @home_goals_against = 4,
155
+ @home_goals_for = 5,
156
+ @home_lost = 1,
157
+ @home_played = 2,
158
+ @home_pts = 3,
159
+ @home_won = 1,
160
+ @lost = 3,
161
+ @played = 4,
162
+ @pts = 3,
163
+ @rank = 19,
164
+ @team = "Norwich City FC",
165
+ @won = 1>,
166
+ ... ]>
167
+ ```
168
+
169
+ Now let's format the standings for humans :-) in the classic more compact table format.
170
+ Let's start with
171
+ showing only totals - no home/away break outs yet -
172
+ in the first simple version:
173
+
174
+ ``` ruby
175
+ standings.each do |l|
176
+ print '%2d. ' % l.rank
177
+ print '%-28s ' % l.team
178
+ print '%2d ' % l.played
179
+ print '%3d ' % l.won
180
+ print '%3d ' % l.drawn
181
+ print '%3d ' % l.lost
182
+ print '%3d:%-3d ' % [l.goals_for,l.goals_against]
183
+ print '%3d' % l.pts
184
+ print "\n"
185
+ end
186
+ ```
187
+
188
+ resulting in:
189
+
190
+ ```
191
+ 1. Liverpool FC 38 32 3 3 85:33 99
192
+ 2. Manchester City FC 38 26 3 9 102:35 81
193
+ 3. Manchester United FC 38 18 12 8 66:36 66
194
+ 4. Chelsea FC 38 20 6 12 69:54 66
195
+ 5. Leicester City FC 38 18 8 12 67:41 62
196
+ 6. Tottenham Hotspur FC 38 16 11 11 61:47 59
197
+ 7. Wolverhampton Wanderers FC 38 15 14 9 51:40 59
198
+ 8. Arsenal FC 38 14 14 10 56:48 56
199
+ 9. Sheffield United FC 38 14 12 12 39:39 54
200
+ 10. Burnley FC 38 15 9 14 43:50 54
201
+ 11. Southampton FC 38 15 7 16 51:60 52
202
+ 12. Everton FC 38 13 10 15 44:56 49
203
+ 13. Newcastle United FC 38 11 11 16 38:58 44
204
+ 14. Crystal Palace FC 38 11 10 17 31:50 43
205
+ 15. Brighton & Hove Albion FC 38 9 14 15 39:54 41
206
+ 16. West Ham United FC 38 10 9 19 49:62 39
207
+ 17. Aston Villa FC 38 9 8 21 41:67 35
208
+ 18. AFC Bournemouth 38 9 7 22 40:65 34
209
+ 19. Watford FC 38 8 10 20 36:64 34
210
+ 20. Norwich City FC 38 5 6 27 26:75 21
211
+ ```
212
+
213
+ To wrap up let's break out the standings for home and away matches for a deluxe version:
214
+
215
+ ``` ruby
216
+ print " - Home - - Away - - Total -\n"
217
+ print " Pld W D L F:A W D L F:A F:A +/- Pts\n"
218
+
219
+ standings.each do |l|
220
+ print '%2d. ' % l.rank
221
+ print '%-28s ' % l.team
222
+ print '%2d ' % l.played
223
+
224
+ print '%2d ' % l.home_won
225
+ print '%2d ' % l.home_drawn
226
+ print '%2d ' % l.home_lost
227
+ print '%3d:%-3d ' % [l.home_goals_for,l.home_goals_against]
228
+
229
+ print '%2d ' % l.away_won
230
+ print '%2d ' % l.away_drawn
231
+ print '%2d ' % l.away_lost
232
+ print '%3d:%-3d ' % [l.away_goals_for,l.away_goals_against]
233
+
234
+ print '%3d:%-3d ' % [l.goals_for,l.goals_against]
235
+
236
+ goals_diff = l.goals_for-l.goals_against
237
+ if goals_diff > 0
238
+ print '%3s ' % "+#{goals_diff}"
239
+ elsif goals_diff < 0
240
+ print '%3s ' % "#{goals_diff}"
241
+ else ## assume 0
242
+ print ' '
243
+ end
244
+
245
+ print '%3d' % l.pts
246
+ print "\n"
247
+ end
248
+ ```
249
+
250
+ resulting in:
251
+
252
+ ```
253
+ - Home - - Away - - Total -
254
+ Pld W D L F:A W D L F:A F:A +/- Pts
255
+ 1. Liverpool FC 38 18 1 0 52:16 14 2 3 33:17 85:33 +52 99
256
+ 2. Manchester City FC 38 15 2 2 57:13 11 1 7 45:22 102:35 +67 81
257
+ 3. Manchester United FC 38 10 7 2 40:17 8 5 6 26:19 66:36 +30 66
258
+ 4. Chelsea FC 38 11 3 5 30:16 9 3 7 39:38 69:54 +15 66
259
+ 5. Leicester City FC 38 11 4 4 35:17 7 4 8 32:24 67:41 +26 62
260
+ 6. Tottenham Hotspur FC 38 12 3 4 36:17 4 8 7 25:30 61:47 +14 59
261
+ 7. Wolverhampton Wanderers FC 38 8 7 4 27:19 7 7 5 24:21 51:40 +11 59
262
+ 8. Arsenal FC 38 10 6 3 36:24 4 8 7 20:24 56:48 +8 56
263
+ 9. Sheffield United FC 38 10 3 6 24:15 4 9 6 15:24 39:39 54
264
+ 10. Burnley FC 38 8 4 7 24:23 7 5 7 19:27 43:50 -7 54
265
+ 11. Southampton FC 38 6 3 10 21:35 9 4 6 30:25 51:60 -9 52
266
+ 12. Everton FC 38 8 7 4 24:21 5 3 11 20:35 44:56 -12 49
267
+ 13. Newcastle United FC 38 6 8 5 20:21 5 3 11 18:37 38:58 -20 44
268
+ 14. Crystal Palace FC 38 6 5 8 15:20 5 5 9 16:30 31:50 -19 43
269
+ 15. Brighton & Hove Albion FC 38 5 7 7 20:27 4 7 8 19:27 39:54 -15 41
270
+ 16. West Ham United FC 38 6 4 9 30:33 4 5 10 19:29 49:62 -13 39
271
+ 17. Aston Villa FC 38 7 3 9 22:30 2 5 12 19:37 41:67 -26 35
272
+ 18. AFC Bournemouth 38 5 6 8 22:30 4 1 14 18:35 40:65 -25 34
273
+ 19. Watford FC 38 6 6 7 22:27 2 4 13 14:37 36:64 -28 34
274
+ 20. Norwich City FC 38 4 3 12 19:37 1 3 15 7:38 26:75 -49 21
275
+ ```
276
+
277
+
278
+ That's it.
279
+ Bonus: Why not build a standings table for the Bundesliga, La Liga, Ligue 1, Seria A, or your very own league? Yes, you can.
280
+
281
+
282
+
283
+ ## Installation
284
+
285
+ Use
286
+
287
+ gem install sports
288
+
289
+ or add the gem to your Gemfile
290
+
291
+ gem 'sports'
292
+
15
293
 
16
294
  ## License
17
295
 
data/Rakefile CHANGED
@@ -3,7 +3,7 @@ require './lib/sports/version.rb'
3
3
 
4
4
  Hoe.spec 'sports' do
5
5
 
6
- self.version = Sports::VERSION
6
+ self.version = SportDb::Module::Sports::VERSION
7
7
 
8
8
  self.summary = "sports - sport data structures for matches, scores, leagues, seasons, rounds, groups, teams, clubs and more"
9
9
  self.description = summary
@@ -22,7 +22,7 @@ Hoe.spec 'sports' do
22
22
  self.extra_deps = [
23
23
  ['alphabets', '>= 1.0.0'],
24
24
  ['date-formats', '>= 1.0.1'],
25
- ['score-formats', '>= 0.0.1'],
25
+ ['score-formats', '>= 0.1.0'],
26
26
  ['csvreader', '>= 1.2.4'],
27
27
  ]
28
28
 
@@ -46,10 +46,37 @@ require 'sports/structs/team_usage'
46
46
 
47
47
  require 'sports/match_status_parser'
48
48
  require 'sports/match_parser_csv'
49
-
50
-
51
-
52
-
53
- puts Sports.banner # say hello
49
+ require 'sports/goal_parser_csv'
50
+
51
+
52
+ ### add convenience shortcut helpers
53
+ module Sports
54
+ class Match
55
+ def self.read_csv( path, headers: nil, filters: nil, converters: nil, sep: nil )
56
+ SportDb::CsvMatchParser.read( path,
57
+ headers: headers,
58
+ filters: filters,
59
+ converters: converters,
60
+ sep: sep )
61
+ end
62
+
63
+ def self.parse_csv( txt, headers: nil, filters: nil, converters: nil, sep: nil )
64
+ SportDb::CsvMatchParser.parse( txt,
65
+ headers: headers,
66
+ filters: filters,
67
+ converters: converters,
68
+ sep: sep )
69
+ end
70
+ end # class Match
71
+ end # module Sports
72
+
73
+
74
+ #####
75
+ # note: add Sport and Football convenience alias - why? why not?
76
+
77
+ Sport = Sports
78
+ Football = Sports
79
+
80
+ puts SportDb::Module::Sports.banner # say hello
54
81
 
55
82
 
@@ -1,25 +1,40 @@
1
1
 
2
- module Sports
3
-
4
- class Configuration
5
-
6
- attr_reader :lang
7
- def lang=(value)
8
- ## check/todo: always use to_sym - why? needed?
9
- DateFormats.lang = value
10
- ScoreFormats.lang = value
2
+ module SportDb
3
+ module Import
4
+ class Configuration
5
+
6
+ attr_reader :lang
7
+ def lang=(value)
8
+ ## check/todo: always use to_sym - why? needed?
9
+ DateFormats.lang = value
10
+ ScoreFormats.lang = value
11
+ end
12
+
13
+ ## lets you use
14
+ ## SportDb.configure do |config|
15
+ ## config.lang = 'it'
16
+ ## end
17
+
18
+ def self.configure() yield( config ); end
19
+
20
+ end # class Configuration
21
+ def self.config() @config ||= Configuration.new; end
11
22
  end
23
+ end
12
24
 
13
- end # class Configuration
14
25
 
15
26
 
27
+ module Sports
28
+
16
29
  ## lets you use
17
30
  ## Sports.configure do |config|
18
31
  ## config.lang = 'it'
19
32
  ## end
20
33
 
34
+ ## note: just forward to SportDb::Import configuration!!!!!
35
+ ## keep Sports module / namespace "clean"
36
+ ## that is, only include data structures (e.g. Match,League,etc) for now - why? why not?
21
37
  def self.configure() yield( config ); end
22
-
23
- def self.config() @config ||= Configuration.new; end
38
+ def self.config() SportDb::Import.config; end
24
39
 
25
40
  end # module Sports
@@ -0,0 +1,28 @@
1
+
2
+ module SportDb
3
+ class CsvGoalParser
4
+
5
+
6
+ def self.read( path )
7
+ txt = File.open( path, 'r:utf-8' ) {|f| f.read } ## note: make sure to use (assume) utf-8
8
+ parse( txt )
9
+ end
10
+
11
+ def self.parse( txt )
12
+ new( txt ).parse
13
+ end
14
+
15
+
16
+ def initialize( txt )
17
+ @txt = txt
18
+ end
19
+
20
+ def parse
21
+ rows = parse_csv( @txt )
22
+ recs = rows.map { |row| Sports::GoalEvent.build( row ) }
23
+ ## pp recs[0]
24
+ recs
25
+ end
26
+
27
+ end # class CsvGoalParser
28
+ end # module Sports
@@ -1,5 +1,5 @@
1
1
 
2
- module Sports
2
+ module SportDb
3
3
  class CsvMatchParser
4
4
 
5
5
  #############
@@ -88,6 +88,7 @@ module Sports
88
88
  headers_mapping[:team1] = find_header( headers, ['Team 1'] )
89
89
  headers_mapping[:team2] = find_header( headers, ['Team 2'] )
90
90
  headers_mapping[:date] = find_header( headers, ['Date'] )
91
+ headers_mapping[:time] = find_header( headers, ['Time'] )
91
92
 
92
93
  ## check for all-in-one full time (ft) and half time (ht9 scores?
93
94
  headers_mapping[:score] = find_header( headers, ['FT'] )
@@ -120,6 +121,7 @@ module Sports
120
121
  headers_mapping[:team1] = find_header( headers, ['HomeTeam', 'HT', 'Home'] )
121
122
  headers_mapping[:team2] = find_header( headers, ['AwayTeam', 'AT', 'Away'] )
122
123
  headers_mapping[:date] = find_header( headers, ['Date'] )
124
+ headers_mapping[:time] = find_header( headers, ['Time'] )
123
125
 
124
126
  ## note: FT = Full Time, HG = Home Goal, AG = Away Goal
125
127
  headers_mapping[:score1] = find_header( headers, ['FTHG', 'HG'] )
@@ -197,6 +199,37 @@ module Sports
197
199
 
198
200
 
199
201
 
202
+ col = row[ headers_mapping[ :time ]]
203
+
204
+ if col.nil?
205
+ time = nil
206
+ else
207
+ col = col.strip # make sure not leading or trailing spaces left over
208
+
209
+ if col.empty?
210
+ col =~ /^-{1,}$/ || # e.g. - or ---
211
+ col =~ /^\?{1,}$/ # e.g. ? or ???
212
+ ## note: allow missing / unknown date for match
213
+ time = nil
214
+ else
215
+ if col =~ /^\d{1,2}:\d{2}$/
216
+ time_fmt = '%H:%M' # e.g. 17:00 or 3:00
217
+ elsif col =~ /^\d{1,2}.\d{2}$/
218
+ time_fmt = '%H.%M' # e.g. 17:00 or 3:00
219
+ else
220
+ puts "*** !!! wrong (unknown) time format >>#{col}<<; cannot continue; fix it; sorry"
221
+ ## todo/fix: add to errors/warns list - why? why not?
222
+ exit 1
223
+ end
224
+
225
+ ## todo/check: use date object (keep string?) - why? why not?
226
+ ## todo/fix: yes!! use date object!!!! do NOT use string
227
+ time = Time.strptime( col, time_fmt ).strftime( '%H:%M' )
228
+ end
229
+ end
230
+
231
+
232
+
200
233
  col = row[ headers_mapping[ :date ]]
201
234
  col = col.strip # make sure not leading or trailing spaces left over
202
235
 
@@ -387,6 +420,7 @@ module Sports
387
420
  ## puts 'match attributes:'
388
421
  attributes = {
389
422
  date: date,
423
+ time: time,
390
424
  team1: team1, team2: team2,
391
425
  score1: score1, score2: score2,
392
426
  score1i: score1i, score2i: score2i,
@@ -400,7 +434,7 @@ module Sports
400
434
  }
401
435
  ## pp attributes
402
436
 
403
- match = Match.new( **attributes )
437
+ match = Sports::Match.new( **attributes )
404
438
  matches << match
405
439
  end
406
440
 
@@ -451,6 +485,6 @@ end # method parse_score
451
485
 
452
486
 
453
487
 
454
- end # class CsvMatchParser
488
+ end # class CsvMatchParser
455
489
  end # module Sports
456
490
 
@@ -7,7 +7,10 @@
7
7
  # etc.
8
8
 
9
9
 
10
- module Sports
10
+ module SportDb
11
+
12
+
13
+ ### todo/fix: move Status inside Match struct - why? why not?
11
14
 
12
15
  class Status
13
16
  # note: use a class as an "enum"-like namespace for now - why? why not?
@@ -81,7 +84,7 @@ module Sports
81
84
 
82
85
  status
83
86
  end # method find!
84
- end # class StatusParser
87
+ end # class StatusParser
85
88
 
86
- end # module Sports
89
+ end # module SportDb
87
90
 
@@ -1,5 +1,5 @@
1
1
 
2
- module Sports
2
+ module SportDb
3
3
  module NameHelper
4
4
 
5
5
 
@@ -85,7 +85,7 @@ class Season
85
85
  :end_year
86
86
 
87
87
  def initialize( *args ) ## change args to years - why? why not?
88
- if args.size == 1 && args[0].is_a?( Integer )
88
+ if args.size == 1 && args[0].is_a?( Integer )
89
89
  @start_year = args[0]
90
90
  @end_year = args[0]
91
91
  elsif args.size == 2 && args[0].is_a?( Integer ) &&
@@ -47,8 +47,8 @@ class GoalEvent
47
47
  )?
48
48
  ['.]
49
49
  $}x.match( row['Minute'])
50
- minute = $1.to_i
51
- offset = $2 ? $2.to_i : nil
50
+ minute = m[1].to_i
51
+ offset = m[2] ? m[2].to_i : nil
52
52
  else
53
53
  puts "!! ERROR - unsupported minute (goal) format >#{row['Minute']}<"
54
54
  exit 1
@@ -174,8 +174,8 @@ class Goal ### nested (non-freestanding) inside match (match is parent)
174
174
  minute: event.minute,
175
175
  offset: event.offset,
176
176
  player: event.player,
177
- owngoal: event.owngoal?,
178
- penalty: event.penalty?,
177
+ owngoal: event.owngoal,
178
+ penalty: event.penalty,
179
179
  notes: event.notes
180
180
  }
181
181
 
@@ -5,6 +5,7 @@ module Sports
5
5
  class Match
6
6
 
7
7
  attr_reader :date,
8
+ :time,
8
9
  :team1, :team2, ## todo/fix: use team1_name, team2_name or similar - for compat with db activerecord version? why? why not?
9
10
  :score1, :score2, ## full time
10
11
  :score1i, :score2i, ## half time (first (i) part)
@@ -26,12 +27,20 @@ class Match
26
27
  attr_accessor :goals ## todo/fix: make goals like all other attribs!!
27
28
 
28
29
  def initialize( **kwargs )
30
+ @score1 = @score2 = nil ## full time
31
+ @score1i = @score2i = nil ## half time (first (i) part)
32
+ @score1et = @score2et = nil ## extra time
33
+ @score1p = @score2p = nil ## penalty
34
+ @score1agg = @score2agg = nil ## full time (all legs) aggregated
35
+
36
+
29
37
  update( kwargs ) unless kwargs.empty?
30
38
  end
31
39
 
32
40
  def update( **kwargs )
33
41
  ## note: check with has_key? because value might be nil!!!
34
42
  @date = kwargs[:date] if kwargs.has_key? :date
43
+ @time = kwargs[:time] if kwargs.has_key? :time
35
44
 
36
45
  ## todo/fix: use team1_name, team2_name or similar - for compat with db activerecord version? why? why not?
37
46
  @team1 = kwargs[:team1] if kwargs.has_key? :team1
@@ -114,15 +123,17 @@ class Match
114
123
  ##
115
124
 
116
125
  ## for now score1 and score2 must be present
117
- if @score1.nil? || @score2.nil?
118
- puts "** WARN: missing scores for match:"
119
- pp kwargs
120
- ## exit 1
121
- end
126
+ ## if @score1.nil? || @score2.nil?
127
+ ## puts "** WARN: missing scores for match:"
128
+ ## pp kwargs
129
+ ## ## exit 1
130
+ ## end
122
131
 
123
132
  ## todo/fix: auto-calculate winner
124
133
  # return 1,2,0 1 => team1, 2 => team2, 0 => draw/tie
125
134
  ### calculate winner - use 1,2,0
135
+ ##
136
+ ## move winner calc to score class - why? why not?
126
137
  if @score1 && @score2
127
138
  if @score1 > @score2
128
139
  @winner = 1
@@ -145,13 +156,23 @@ class Match
145
156
  def complete?() true; end ## for now all scores are complete - in the future check scores; might be missing - not yet entered
146
157
 
147
158
 
148
- def score_str # pretty print (full time) scores; convenience method
149
- "#{@score1}-#{@score2}"
159
+ def score
160
+ Score.new( @score1i, @score2i, ## half time (first (i) part)
161
+ @score1, @score2, ## full time
162
+ @score1et, @score2et, ## extra time
163
+ @score1p, @score2p ) ## penalty
150
164
  end
151
165
 
152
- def scorei_str # pretty print (half time) scores; convenience method
153
- "#{@score1i}-#{@score2i}"
154
- end
166
+
167
+ ####
168
+ ## deprecated - use score.to_s and friends - why? why not?
169
+ # def score_str # pretty print (full time) scores; convenience method
170
+ # "#{@score1}-#{@score2}"
171
+ # end
172
+
173
+ # def scorei_str # pretty print (half time) scores; convenience method
174
+ # "#{@score1i}-#{@score2i}"
175
+ # end
155
176
  end # class Match
156
177
 
157
178
  end # module Sports
@@ -82,13 +82,13 @@ private
82
82
 
83
83
  def has_dates?() @start_date && @end_date; end
84
84
  def dates_str
85
- ## note: start_date/end_date might be optional/missing
86
- if has_dates?
87
- "#{start_date.strftime( '%a %d %b %Y' )} - #{end_date.strftime( '%a %d %b %Y' )}"
88
- else
89
- "??? - ???"
90
- end
91
- end
85
+ ## note: start_date/end_date might be optional/missing
86
+ if has_dates?
87
+ "#{start_date.strftime( '%a %d %b %Y' )} - #{end_date.strftime( '%a %d %b %Y' )}"
88
+ else
89
+ "??? - ???"
90
+ end
91
+ end
92
92
 
93
93
  def days() end_date.jd - start_date.jd; end
94
94
 
@@ -1,6 +1,6 @@
1
1
  module Sports
2
2
 
3
- class Round
3
+ class Round
4
4
  attr_reader :name, :start_date, :end_date, :knockout
5
5
  attr_accessor :num # note: make read & writable - why? why not?
6
6
 
@@ -17,7 +17,7 @@ module Sports
17
17
  @knockout = knockout
18
18
  @auto = auto # auto-created (inline reference/header without proper definition before)
19
19
  end
20
- end # class Round
20
+ end # class Round
21
21
 
22
22
  end # module Sports
23
23
 
@@ -37,7 +37,7 @@ class Standings
37
37
  end # (nested) class StandingsLine
38
38
 
39
39
 
40
- def initialize( opts={} )
40
+ def initialize( match_or_matches=nil, opts={} )
41
41
  ## fix:
42
42
  # passing in e.g. pts for win (3? 2? etc.)
43
43
  # default to 3 for now
@@ -46,6 +46,9 @@ class Standings
46
46
  @pts_won = opts[:pts_won] || 3
47
47
 
48
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
49
52
  end
50
53
 
51
54
 
@@ -65,6 +68,10 @@ class Standings
65
68
  end
66
69
 
67
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
+
68
75
  def to_a
69
76
  ## return lines; sort and add rank
70
77
  ## note: will update rank!!!! (side effect)
@@ -184,7 +191,7 @@ private
184
191
  team1 = m.team1.is_a?( String ) ? m.team1 : m.team1.name
185
192
  team2 = m.team2.is_a?( String ) ? m.team2 : m.team2.name
186
193
 
187
- score = m.score_str
194
+ score = m.score.to_s
188
195
 
189
196
  ## puts " #{team1} - #{team2} #{score}"
190
197
 
@@ -66,7 +66,7 @@ class Team
66
66
  ##############################
67
67
  ## helper methods for import only??
68
68
  ## check for duplicates
69
- include NameHelper
69
+ include SportDb::NameHelper
70
70
 
71
71
  def duplicates?
72
72
  names = [name] + alt_names + alt_names_auto
@@ -1,8 +1,10 @@
1
1
 
2
- module Sports
2
+ module SportDb
3
+ module Module
4
+ module Sports
3
5
  MAJOR = 0 ## todo: namespace inside version or something - why? why not??
4
- MINOR = 0
5
- PATCH = 1
6
+ MINOR = 1
7
+ PATCH = 0
6
8
  VERSION = [MAJOR,MINOR,PATCH].join('.')
7
9
 
8
10
  def self.version
@@ -16,4 +18,7 @@ module Sports
16
18
  def self.root
17
19
  File.expand_path( File.dirname(File.dirname(__FILE__)) )
18
20
  end
19
- end # module Sports
21
+
22
+ end # module Sports
23
+ end
24
+ end
@@ -8,8 +8,8 @@ require 'helper'
8
8
 
9
9
  class TestMatchStatusParser < MiniTest::Test
10
10
 
11
- Status = Sports::Status
12
- StatusParser = Sports::StatusParser
11
+ Status = SportDb::Status
12
+ StatusParser = SportDb::StatusParser
13
13
 
14
14
  def test_find
15
15
  [['awarded [cancelled] canceled [ddd]', Status::CANCELLED],
@@ -24,7 +24,11 @@ class TestMatchStatusParser < MiniTest::Test
24
24
  puts "line (after): >#{line}<"
25
25
  puts
26
26
 
27
- assert_equal status_exp, status
27
+ if status_exp.nil?
28
+ assert_nil status
29
+ else
30
+ assert_equal status_exp, status
31
+ end
28
32
  end
29
33
  end # method test_find
30
34
 
@@ -38,7 +42,13 @@ class TestMatchStatusParser < MiniTest::Test
38
42
  ].each do |rec|
39
43
  str = rec[0]
40
44
  status_exp = rec[1]
41
- assert_equal status_exp, StatusParser.parse( str )
45
+ status = StatusParser.parse( str )
46
+
47
+ if status_exp.nil? ## for "silencing" minitest warning - Use assert_nil if expecting nil
48
+ assert_nil status
49
+ else
50
+ assert_equal status_exp, status
51
+ end
42
52
  end
43
53
  end
44
54
 
@@ -8,7 +8,7 @@ require 'helper'
8
8
 
9
9
  class TestNameHelper < MiniTest::Test
10
10
 
11
- include Sports::NameHelper
11
+ include SportDb::NameHelper
12
12
 
13
13
 
14
14
  def test_strip_norm ## strip (remove) non-norm characters e.g. ()'- etc.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sports
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerald Bauer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-17 00:00:00.000000000 Z
11
+ date: 2020-08-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: alphabets
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: 0.0.1
47
+ version: 0.1.0
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: 0.0.1
54
+ version: 0.1.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: csvreader
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -110,6 +110,7 @@ files:
110
110
  - Rakefile
111
111
  - lib/sports.rb
112
112
  - lib/sports/config.rb
113
+ - lib/sports/goal_parser_csv.rb
113
114
  - lib/sports/match_parser_csv.rb
114
115
  - lib/sports/match_status_parser.rb
115
116
  - lib/sports/name_helper.rb