sportdb-exporters 0.0.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 192a963be138b0e03063615abbb95e84d2e2f492
4
+ data.tar.gz: a881a0a6845e6265b81c20411eaba1fe3a35fa31
5
+ SHA512:
6
+ metadata.gz: a947f48d8d2b14b360934c7dd2c8cf11b8a086a4dcc57aa7516ddf3e82192fc77dda3c36f28e46bba475e598ffada9abf826779142e30d1e10d25daa34315931
7
+ data.tar.gz: b22a856f3a193a9817c4b3f5d1def27d513a1c2ac3c93c10851693032308e27027cfcc96bd42069c762d4413b4b26c3ee87281c02ab350e9cee6f37edec6ac08
@@ -0,0 +1,4 @@
1
+ ### 0.0.1 / 2020-09-21
2
+
3
+ * Everything is new. First release.
4
+
@@ -0,0 +1,8 @@
1
+ CHANGELOG.md
2
+ Manifest.txt
3
+ README.md
4
+ Rakefile
5
+ lib/sportdb/exporters.rb
6
+ lib/sportdb/exporters/json_exporter.rb
7
+ lib/sportdb/exporters/json_exporter_more.rb
8
+ lib/sportdb/exporters/version.rb
@@ -0,0 +1,28 @@
1
+ # sportdb-exporters - export helpers for sport.db data in various formats incl. json, csv, and friends
2
+
3
+
4
+ * home :: [github.com/sportdb/sport.db](https://github.com/sportdb/sport.db)
5
+ * bugs :: [github.com/sportdb/sport.db/issues](https://github.com/sportdb/sport.db/issues)
6
+ * gem :: [rubygems.org/gems/sportdb-exporters](https://rubygems.org/gems/sportdb-exporters)
7
+ * rdoc :: [rubydoc.info/gems/sportdb-exporters](http://rubydoc.info/gems/sportdb-exporters)
8
+ * forum :: [groups.google.com/group/opensport](https://groups.google.com/group/opensport)
9
+
10
+
11
+ ## Usage
12
+
13
+ TBD
14
+
15
+
16
+ ## License
17
+
18
+ ![](https://publicdomainworks.github.io/buttons/zero88x31.png)
19
+
20
+ The `sportdb-exporters` scripts are dedicated to the public domain.
21
+ Use it as you please with no restrictions whatsoever.
22
+
23
+
24
+ ## Questions? Comments?
25
+
26
+ Send them along to the
27
+ [Open Sports & Friends Forum/Mailing List](http://groups.google.com/group/opensport).
28
+ Thanks!
@@ -0,0 +1,26 @@
1
+ require 'hoe'
2
+ require './lib/sportdb/exporters/version.rb'
3
+
4
+ Hoe.spec 'sportdb-exporters' do
5
+
6
+ self.version = SportDb::Module::Exporters::VERSION
7
+
8
+ self.summary = 'sportdb-exporters - export helpers for sport.db data in various formats incl. json, csv, and friends'
9
+ self.description = summary
10
+
11
+ self.urls = { home: 'https://github.com/sportdb/sport.db' }
12
+
13
+ self.author = 'Gerald Bauer'
14
+ self.email = 'opensport@googlegroups.com'
15
+
16
+ # switch extension to .markdown for gihub formatting
17
+ self.readme_file = 'README.md'
18
+ self.history_file = 'CHANGELOG.md'
19
+
20
+ self.licenses = ['Public Domain']
21
+
22
+ self.spec_extras = {
23
+ required_ruby_version: '>= 2.2.2'
24
+ }
25
+
26
+ end
@@ -0,0 +1,14 @@
1
+ require 'sportdb/catalogs'
2
+ require 'sportdb/models'
3
+
4
+
5
+ ###
6
+ # our own code
7
+ require 'sportdb/exporters/version'
8
+ require 'sportdb/exporters/json_exporter'
9
+ require 'sportdb/exporters/json_exporter_more'
10
+
11
+
12
+
13
+ SportDb::Module::Exporters.banner # say hello
14
+
@@ -0,0 +1,237 @@
1
+ module SportDb
2
+ class JsonExporter
3
+
4
+
5
+ LEAGUE_TO_BASENAME = {
6
+ 'eng.1' => 'en.1',
7
+ 'eng.2' => 'en.2',
8
+ 'eng.3' => 'en.3',
9
+ 'eng.4' => 'en.4',
10
+
11
+ 'world' => 'worldcup',
12
+ ## 'cl' => 'cl', ## keep cl as is :-)
13
+ 'uefa.cl' => 'cl',
14
+ 'uefa.cl.quali' => 'cl.quali'
15
+ }
16
+
17
+
18
+ def self.export( league_key, out_root: )
19
+
20
+ puts "find league >#{league_key}<"
21
+ league = Model::League.find_by( key: league_key )
22
+
23
+ if league.nil?
24
+ puts "!! WARN: no league found for >#{league_key}<; skipping export json"
25
+ return
26
+ end
27
+
28
+
29
+ league.events.each do |event|
30
+ puts "** event:"
31
+ pp event.name
32
+ pp event.season
33
+ pp event.league
34
+ puts "teams.count: #{event.teams.count}"
35
+ puts "rounds.count: #{event.rounds.count}"
36
+ puts "groups.count: #{event.groups.count}"
37
+ puts "matches.count: #{event.matches.count}"
38
+
39
+
40
+ ## build path e.g.
41
+ ## 2014-15/at.1.clubs.json
42
+
43
+ ## -- check for remapping (e.g. add .1); if not found use league key as is
44
+ league_basename = LEAGUE_TO_BASENAME[ event.league.key ] || event.league.key
45
+
46
+ season_basename = event.season.name.sub('/', '-') ## e.g. change 2014/15 to 2014-15
47
+
48
+
49
+ out_dir = "#{out_root}/#{season_basename}"
50
+ ## make sure folders exist
51
+ FileUtils.mkdir_p( out_dir ) unless Dir.exists?( out_dir )
52
+
53
+ ### note:
54
+ ## skip teams for now if no teams on "top-level"
55
+ ## - what to do? use all unique teams from matches? yes, yes!!
56
+ ## - maybe add stages array to team - why? why not?
57
+ ## - or use teams by stage?
58
+
59
+ ## if empty - try regular season stage
60
+ ## or apertura stage?
61
+
62
+
63
+ unless event.teams.empty?
64
+ data_clubs = build_clubs( event )
65
+ ## pp data_clubs
66
+ File.open( "#{out_dir}/#{league_basename}.clubs.json", 'w:utf-8' ) do |f|
67
+ f.write JSON.pretty_generate( data_clubs )
68
+ end
69
+ end
70
+
71
+ # note: make groups export optional for now - why? why not?
72
+ unless event.groups.empty?
73
+ data_groups = build_groups( event )
74
+ ## pp data_groups
75
+ File.open( "#{out_dir}/#{league_basename}.groups.json", 'w' ) do |f|
76
+ f.write JSON.pretty_generate( data_groups )
77
+ end
78
+ end
79
+
80
+ data_matches = build_matches( event )
81
+ ## pp data_matches
82
+ File.open( "#{out_dir}/#{league_basename}.json", 'w:utf-8' ) do |f|
83
+ f.write JSON.pretty_generate( data_matches )
84
+ end
85
+ end
86
+ end
87
+
88
+
89
+ ###############
90
+ ## helpers
91
+
92
+ def self.build_clubs( event )
93
+ clubs = []
94
+ event.teams.each do |team|
95
+ clubs << { name: team.name,
96
+ code: team.code,
97
+ country: team.country.name, }
98
+ end
99
+
100
+ data = {
101
+ name: event.name,
102
+ clubs: clubs
103
+ }
104
+
105
+ data
106
+ end
107
+
108
+
109
+ def self.build_groups( event )
110
+ groups = []
111
+ event.groups.each do |group|
112
+ teams = []
113
+
114
+ if group.teams.empty?
115
+ puts "!! WARN - group #{group.name} has no teams/is empty"
116
+ end
117
+
118
+ group.teams.each do |team|
119
+ teams << team.name
120
+ end
121
+ groups << { name: group.name, teams: teams }
122
+ end
123
+
124
+ data = {
125
+ name: event.name,
126
+ groups: groups
127
+ }
128
+
129
+ data
130
+ end
131
+
132
+
133
+ def self.build_matches( event )
134
+ ## note: no longer list by rounds
135
+ ## now list by dates and add round as a "regular" field
136
+ ## note: make round optional too!!!
137
+
138
+ matches = []
139
+ event.matches.order( 'date ASC' ).each do |match|
140
+ h = {}
141
+
142
+ ## let stage and/or group go first if present/available
143
+ h[ :stage ] = match.stage.name if match.stage
144
+ h[ :round ] = match.round.name if match.round
145
+ h[ :group ] = match.group.name if match.group
146
+
147
+
148
+ h[ :date ] = match.date.strftime( '%Y-%m-%d')
149
+ h[ :team1 ] = match.team1.name
150
+ h[ :team2 ] = match.team2.name
151
+
152
+
153
+ score = {}
154
+ if match.score1 && match.score2
155
+ score[:ft] = [match.score1, match.score2]
156
+ end
157
+
158
+ if match.score1et && match.score2et
159
+ score[:et] = [match.score1et, match.score2et]
160
+ end
161
+
162
+ if match.score1p && match.score2p
163
+ score[:p] = [match.score1p, match.score2p]
164
+ end
165
+
166
+ h[ :score ] = score unless score.empty? ## note: only add if has some data
167
+
168
+
169
+ unless match.goals.empty?
170
+ goals1, goals2 = build_goals( match )
171
+ h[ :goals1 ] = goals1
172
+ h[ :goals2 ] = goals2
173
+ end
174
+
175
+
176
+ if match.status
177
+ case match.status
178
+ when Status::CANCELLED
179
+ h[ :status ] = 'CANCELLED'
180
+ when Status::AWARDED
181
+ h[ :status ] = 'AWARDED'
182
+ when Status::ABANDONED
183
+ h[ :status ] = 'ABANDONED'
184
+ when Status::REPLAY
185
+ h[ :status ] = 'REPLAY'
186
+ when Status::POSTPONED
187
+ ## note: add NOTHING for postponed for now
188
+ else
189
+ puts "!! WARN - unknown match status >#{match.status}<:"
190
+ pp match
191
+ h[ :status ] = match.status.downcase ## print "literal" downcased for now
192
+ end
193
+ end
194
+
195
+ matches << h
196
+ end
197
+
198
+ data = {
199
+ name: event.name,
200
+ matches: matches
201
+ }
202
+
203
+ data
204
+ end
205
+
206
+
207
+
208
+ def self.build_goals( match )
209
+ goals1 = []
210
+ goals2 = []
211
+
212
+ match.goals.each do |goal|
213
+ if goal.team_id == match.team1_id
214
+ goals = goals1
215
+ elsif goal.team_id == match.team2_id
216
+ goals = goals2
217
+ else
218
+ puts "*** team id NOT matching for goal; must be team1 or team2 id"
219
+ exit 1 ## exit - why? why not?
220
+ end
221
+
222
+ g = { name: goal.person.name,
223
+ minute: goal.minute,
224
+ }
225
+ g[:offset] = goal.offset if goal.offset != 0
226
+ g[:score1] = goal.score1
227
+ g[:score2] = goal.score2
228
+ g[:penalty] = goal.penalty if goal.penalty
229
+ g[:owngoal] = goal.owngoal if goal.owngoal
230
+ goals << g
231
+ end
232
+ [goals1, goals2]
233
+ end
234
+
235
+
236
+ end # class Json Exporter
237
+ end # module SportDb
@@ -0,0 +1,250 @@
1
+ module SportDb
2
+ class JsonExporter
3
+
4
+ ## hack: for timezone (add timezone to city - fix/fix/fix)
5
+
6
+ CITY_TO_TIMEZONE = {
7
+ ## brazil 2014
8
+ 'Rio de Janeiro' => 'UTC-3',
9
+ 'Brasília' => 'UTC-3',
10
+ 'São Paulo' => 'UTC-3',
11
+ 'Fortaleza' => 'UTC-3',
12
+ 'Belo Horizonte' => 'UTC-3',
13
+ 'Salvador' => 'UTC-3',
14
+ 'Natal' => 'UTC-3',
15
+ 'Porto Alegre' => 'UTC-3',
16
+ 'Recife' => 'UTC-3',
17
+ 'Curitiba' => 'UTC-3',
18
+ 'Cuiabá' => 'UTC-4',
19
+ 'Manaus' => 'UTC-4',
20
+ ## russia 2018
21
+ 'Kaliningrad' => 'UTC+2',
22
+ 'Nizhny Novgorod' => 'UTC+3',
23
+ 'Volgograd' => 'UTC+3',
24
+ 'Saransk' => 'UTC+3',
25
+ 'Rostov-on-Don' => 'UTC+3',
26
+ 'Kazan' => 'UTC+3',
27
+ 'Sochi' => 'UTC+3',
28
+ 'Saint Petersburg' => 'UTC+3',
29
+ 'Moscow' => 'UTC+3',
30
+ 'Samara' => 'UTC+4',
31
+ 'Ekaterinburg' => 'UTC+5',
32
+ }
33
+
34
+ def self.city_to_timezone( city )
35
+ CITY_TO_TIMEZONE[ city ] || '?'
36
+ end
37
+
38
+
39
+ def self.export_worldcup( league_key, out_root: )
40
+
41
+ league = Model::League.find_by_key!( league_key )
42
+
43
+ league.events.each do |event|
44
+ puts "** event:"
45
+ pp event.title
46
+ pp event.season
47
+ pp event.league
48
+ puts "teams.count: #{event.teams.count}"
49
+ puts "rounds.count: #{event.rounds.count}"
50
+ puts "groups.count: #{event.groups.count}"
51
+ puts "grounds.count: #{event.grounds.count}"
52
+
53
+
54
+ grounds = []
55
+ event.grounds.each do |ground|
56
+ grounds << { key: ground.key,
57
+ name: ground.title,
58
+ capacity: ground.capacity,
59
+ city: ground.city.name,
60
+ timezone: city_to_timezone( ground.city.name ) }
61
+ end
62
+
63
+ hash_grounds = {
64
+ name: event.title,
65
+ stadiums: grounds
66
+ }
67
+
68
+ pp hash_grounds
69
+
70
+
71
+ teams = []
72
+ event.teams.each do |team|
73
+ if team.country.assoc
74
+ continental = {}
75
+ team.country.assoc.parent_assocs.each do |parent|
76
+ ## next if parent.key == 'fifa' ## skip fifa
77
+ ## todo/fix: only include / use (single) continental (parent) org/assoc
78
+ ## find/use continental parent only for now
79
+ if ['caf', 'afc', 'concacaf', 'uefa', 'conmebol', 'ofc'].include? parent.key
80
+ continental = { name: parent.title,
81
+ code: parent.key.upcase }
82
+ end
83
+ end
84
+ assoc = { key: team.country.assoc.key,
85
+ name: team.country.assoc.title,
86
+ }
87
+ assoc[ :continental ] = continental unless continental.empty?
88
+ else
89
+ assoc = {}
90
+ end
91
+ t = { name: team.title,
92
+ code: team.code,
93
+ continent: team.country.continent.name }
94
+ t[ :assoc ] = assoc unless assoc.empty?
95
+ teams << t
96
+ end
97
+
98
+ hash_teams = {
99
+ name: event.title,
100
+ teams: teams
101
+ }
102
+
103
+ pp hash_teams
104
+
105
+
106
+ standings = []
107
+ event.groups.each do |group|
108
+ entries = []
109
+ group_standing = Model::GroupStanding.find_by( group_id: group.id )
110
+ if group_standing
111
+ group_standing.entries.each do |entry|
112
+ entries << { team: { name: entry.team.name, code: entry.team.code },
113
+ pos: entry.pos,
114
+ played: entry.played,
115
+ won: entry.won,
116
+ drawn: entry.drawn,
117
+ lost: entry.lost,
118
+ goals_for: entry.goals_for,
119
+ goals_against: entry.goals_against,
120
+ pts: entry.pts
121
+ }
122
+ end
123
+ end
124
+ standings << { name: group.title, standings: entries }
125
+ end
126
+
127
+ hash_standings = {
128
+ name: event.title,
129
+ groups: standings
130
+ }
131
+
132
+ pp hash_standings
133
+
134
+
135
+ groups = []
136
+ event.groups.each do |group|
137
+ teams = []
138
+ group.teams.each do |team|
139
+ teams << { name: team.title,
140
+ code: team.code
141
+ }
142
+ end
143
+ groups << { name: group.title, teams: teams }
144
+ end
145
+
146
+ hash_groups = {
147
+ name: event.title,
148
+ groups: groups
149
+ }
150
+
151
+ pp hash_groups
152
+
153
+
154
+ rounds = []
155
+ event.rounds.each do |round|
156
+ matches = []
157
+ round.games.each do |game|
158
+ m = { num: game.pos, ## use id - why? why not?
159
+ date: game.play_at.strftime( '%Y-%m-%d'),
160
+ time: game.play_at.strftime( '%H:%M'),
161
+ team1: {
162
+ name: game.team1.title,
163
+ code: game.team1.code
164
+ },
165
+ team2: {
166
+ name: game.team2.title,
167
+ code: game.team2.code
168
+ },
169
+ score1: game.score1,
170
+ score2: game.score2,
171
+ score1i: game.score1i, # half time / first third (opt)
172
+ score2i: game.score2i, # half time - team 2
173
+ }
174
+
175
+ if game.knockout
176
+ m[ :score1et ] = game.score1et # extratime - team 1 (opt)
177
+ m[ :score2et ] = game.score2et # extratime - team 2 (opt)
178
+ m[ :score1p ] = game.score1p # penalty - team 1 (opt)
179
+ m[ :score2p ] = game.score2p # penalty - team 2 (opt) elfmeter (opt)
180
+ m[ :knockout ] = game.knockout
181
+ end
182
+
183
+ unless game.goals.empty?
184
+ goals1, goals2 = build_goals( game )
185
+ m[ :goals1 ] = goals1
186
+ m[ :goals2 ] = goals2
187
+ end
188
+
189
+ if game.group
190
+ m[ :group ] = game.group.title
191
+ end
192
+
193
+ if game.ground
194
+ m[ :stadium ] = { key: game.ground.key, name: game.ground.title }
195
+ m[ :city ] = game.ground.city.name
196
+ m[ :timezone ] = city_to_timezone( game.ground.city.name )
197
+ end
198
+
199
+ matches << m
200
+ end
201
+
202
+ rounds << { name: round.title, matches: matches }
203
+ end
204
+
205
+ hash_matches = {
206
+ name: event.title,
207
+ rounds: rounds
208
+ }
209
+
210
+ pp hash_matches
211
+
212
+
213
+ ## build path e.g.
214
+ ## 2014-15/at.1.clubs.json
215
+ ## 2018/worldcup.teams.json
216
+
217
+ ## -- check for remapping (e.g. add .1); if not found use league key as is
218
+ league_basename = LEAGUE_TO_BASENAME[ event.league.key ] || event.league.key
219
+
220
+ season_basename = event.season.title.sub('/', '-') ## e.g. change 2014/15 to 2014-15
221
+
222
+
223
+ out_dir = "#{out_root}/#{season_basename}"
224
+ ## make sure folders exist
225
+ FileUtils.mkdir_p( out_dir ) unless Dir.exists?( out_dir )
226
+
227
+ File.open( "#{out_dir}/#{league_basename}.stadiums.json", 'w' ) do |f|
228
+ f.write JSON.pretty_generate( hash_grounds )
229
+ end
230
+
231
+ File.open( "#{out_dir}/#{league_basename}.teams.json", 'w' ) do |f|
232
+ f.write JSON.pretty_generate( hash_teams )
233
+ end
234
+
235
+ File.open( "#{out_dir}/#{league_basename}.groups.json", 'w' ) do |f|
236
+ f.write JSON.pretty_generate( hash_groups )
237
+ end
238
+
239
+ File.open( "#{out_dir}/#{league_basename}.standings.json", 'w' ) do |f|
240
+ f.write JSON.pretty_generate( hash_standings )
241
+ end
242
+
243
+ File.open( "#{out_dir}/#{league_basename}.json", 'w' ) do |f|
244
+ f.write JSON.pretty_generate( hash_matches )
245
+ end
246
+ end
247
+ end
248
+
249
+ end # class Json Exporter
250
+ end # module SportDb
@@ -0,0 +1,25 @@
1
+
2
+ module SportDb
3
+ module Module
4
+ module Exporters
5
+
6
+ MAJOR = 0 ## todo: namespace inside version or something - why? why not??
7
+ MINOR = 0
8
+ PATCH = 1
9
+ VERSION = [MAJOR,MINOR,PATCH].join('.')
10
+
11
+ def self.version
12
+ VERSION
13
+ end
14
+
15
+ def self.banner
16
+ "sportdb-exporters/#{VERSION} on Ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
17
+ end
18
+
19
+ def self.root
20
+ File.expand_path( File.dirname(File.dirname(File.dirname(File.dirname(__FILE__)))) )
21
+ end
22
+
23
+ end # module Exporters
24
+ end # module Module
25
+ end # module SportDb
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sportdb-exporters
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Gerald Bauer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-09-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rdoc
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: hoe
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.16'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.16'
41
+ description: sportdb-exporters - export helpers for sport.db data in various formats
42
+ incl. json, csv, and friends
43
+ email: opensport@googlegroups.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files:
47
+ - CHANGELOG.md
48
+ - Manifest.txt
49
+ - README.md
50
+ files:
51
+ - CHANGELOG.md
52
+ - Manifest.txt
53
+ - README.md
54
+ - Rakefile
55
+ - lib/sportdb/exporters.rb
56
+ - lib/sportdb/exporters/json_exporter.rb
57
+ - lib/sportdb/exporters/json_exporter_more.rb
58
+ - lib/sportdb/exporters/version.rb
59
+ homepage: https://github.com/sportdb/sport.db
60
+ licenses:
61
+ - Public Domain
62
+ metadata: {}
63
+ post_install_message:
64
+ rdoc_options:
65
+ - "--main"
66
+ - README.md
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: 2.2.2
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ requirements: []
80
+ rubyforge_project:
81
+ rubygems_version: 2.5.2
82
+ signing_key:
83
+ specification_version: 4
84
+ summary: sportdb-exporters - export helpers for sport.db data in various formats incl.
85
+ json, csv, and friends
86
+ test_files: []