sportdb 1.8.7 → 1.8.8
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 +10 -0
- data/bin/sportdb +0 -0
- data/lib/sportdb.rb +13 -0
- data/lib/sportdb/reader.rb +35 -822
- data/lib/sportdb/readers/event.rb +197 -0
- data/lib/sportdb/readers/game.rb +336 -0
- data/lib/sportdb/readers/ground.rb +33 -0
- data/lib/sportdb/readers/league.rb +32 -0
- data/lib/sportdb/readers/race.rb +102 -0
- data/lib/sportdb/readers/record.rb +108 -0
- data/lib/sportdb/readers/roster.rb +98 -0
- data/lib/sportdb/readers/season.rb +64 -0
- data/lib/sportdb/readers/team.rb +34 -0
- data/lib/sportdb/readers/track.rb +34 -0
- data/lib/sportdb/schema.rb +3 -5
- data/lib/sportdb/updater.rb +5 -3
- data/lib/sportdb/version.rb +1 -1
- metadata +53 -73
- checksums.yaml +0 -7
data/Manifest.txt
CHANGED
|
@@ -47,6 +47,16 @@ lib/sportdb/models/world/continent.rb
|
|
|
47
47
|
lib/sportdb/models/world/country.rb
|
|
48
48
|
lib/sportdb/models/world/region.rb
|
|
49
49
|
lib/sportdb/reader.rb
|
|
50
|
+
lib/sportdb/readers/event.rb
|
|
51
|
+
lib/sportdb/readers/game.rb
|
|
52
|
+
lib/sportdb/readers/ground.rb
|
|
53
|
+
lib/sportdb/readers/league.rb
|
|
54
|
+
lib/sportdb/readers/race.rb
|
|
55
|
+
lib/sportdb/readers/record.rb
|
|
56
|
+
lib/sportdb/readers/roster.rb
|
|
57
|
+
lib/sportdb/readers/season.rb
|
|
58
|
+
lib/sportdb/readers/team.rb
|
|
59
|
+
lib/sportdb/readers/track.rb
|
|
50
60
|
lib/sportdb/schema.rb
|
|
51
61
|
lib/sportdb/service.rb
|
|
52
62
|
lib/sportdb/service/public/football/js/football/api.js
|
data/bin/sportdb
CHANGED
|
File without changes
|
data/lib/sportdb.rb
CHANGED
|
@@ -72,7 +72,20 @@ require 'sportdb/utils_round'
|
|
|
72
72
|
require 'sportdb/utils_scores'
|
|
73
73
|
require 'sportdb/utils_teams'
|
|
74
74
|
require 'sportdb/matcher'
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
require 'sportdb/readers/event'
|
|
78
|
+
require 'sportdb/readers/game'
|
|
79
|
+
require 'sportdb/readers/ground'
|
|
80
|
+
require 'sportdb/readers/league'
|
|
81
|
+
require 'sportdb/readers/race'
|
|
82
|
+
require 'sportdb/readers/record'
|
|
83
|
+
require 'sportdb/readers/roster'
|
|
84
|
+
require 'sportdb/readers/season'
|
|
85
|
+
require 'sportdb/readers/team'
|
|
86
|
+
require 'sportdb/readers/track'
|
|
75
87
|
require 'sportdb/reader'
|
|
88
|
+
|
|
76
89
|
require 'sportdb/lang'
|
|
77
90
|
|
|
78
91
|
require 'sportdb/updater'
|
data/lib/sportdb/reader.rb
CHANGED
|
@@ -43,17 +43,20 @@ class Reader
|
|
|
43
43
|
def load( name ) # convenience helper for all-in-one reader
|
|
44
44
|
|
|
45
45
|
logger.debug "enter load( name=>>#{name}<<, include_path=>>#{include_path}<<)"
|
|
46
|
-
|
|
46
|
+
|
|
47
47
|
if name =~ /^circuits/ # e.g. circuits.txt in formula1.db
|
|
48
|
-
|
|
48
|
+
reader = TrackReader.new( include_path )
|
|
49
|
+
reader.read( name )
|
|
49
50
|
elsif match_tracks_for_country( name ) do |country_key| # name =~ /^([a-z]{2})\/tracks/
|
|
50
51
|
# auto-add country code (from folder structure) for country-specific tracks
|
|
51
52
|
# e.g. at/tracks or at-austria/tracks
|
|
52
53
|
country = Country.find_by_key!( country_key )
|
|
53
|
-
|
|
54
|
+
reader = TrackReader.new( include_path )
|
|
55
|
+
reader.read( name, country_id: country.id )
|
|
54
56
|
end
|
|
55
57
|
elsif name =~ /^tracks/ # e.g. tracks.txt in ski.db
|
|
56
|
-
|
|
58
|
+
reader = TrackReader.new( include_path )
|
|
59
|
+
reader.read( name )
|
|
57
60
|
elsif name =~ /^drivers/ # e.g. drivers.txt in formula1.db
|
|
58
61
|
load_persons( name )
|
|
59
62
|
elsif match_skiers_for_country( name ) do |country_key| # name =~ /^([a-z]{2})\/skiers/
|
|
@@ -65,101 +68,80 @@ class Reader
|
|
|
65
68
|
elsif name =~ /^skiers/ # e.g. skiers.men.txt in ski.db
|
|
66
69
|
load_persons( name )
|
|
67
70
|
elsif name =~ /^teams/ # e.g. teams.txt in formula1.db
|
|
68
|
-
|
|
71
|
+
reader = TeamReader.new( include_path )
|
|
72
|
+
reader.read( name )
|
|
69
73
|
elsif name =~ /\/races/ # e.g. 2013/races.txt in formula1.db
|
|
70
|
-
|
|
74
|
+
reader = RaceReader.new( include_path )
|
|
75
|
+
reader.read( name )
|
|
71
76
|
elsif name =~ /\/squads/ || name =~ /\/rosters/ # e.g. 2013/squads.txt in formula1.db
|
|
72
|
-
|
|
77
|
+
reader = RosterReader.new( include_path )
|
|
78
|
+
reader.read( name )
|
|
73
79
|
elsif name =~ /\/([0-9]{2})-/
|
|
74
80
|
race_pos = $1.to_i
|
|
75
81
|
# NB: assume @event is set from previous load
|
|
76
82
|
race = Race.find_by_event_id_and_pos( @event.id, race_pos )
|
|
77
|
-
|
|
83
|
+
reader = RecordReader.new( include_path )
|
|
84
|
+
reader.read( name, race_id: race.id ) # e.g. 2013/04-gp-monaco.txt in formula1.db
|
|
78
85
|
elsif name =~ /(?:^|\/)seasons/ # NB: ^seasons or also possible at-austria!/seasons
|
|
79
|
-
|
|
86
|
+
reader = SeasonReader.new( include_path )
|
|
87
|
+
reader.read( name )
|
|
80
88
|
elsif match_stadiums_for_country( name ) do |country_key|
|
|
81
89
|
country = Country.find_by_key!( country_key )
|
|
82
|
-
|
|
90
|
+
reader = GroundReader.new( include_path )
|
|
91
|
+
reader.read( name, country_id: country.id )
|
|
83
92
|
end
|
|
84
93
|
elsif match_leagues_for_country( name ) do |country_key| # name =~ /^([a-z]{2})\/leagues/
|
|
85
94
|
# auto-add country code (from folder structure) for country-specific leagues
|
|
86
95
|
# e.g. at/leagues
|
|
87
96
|
country = Country.find_by_key!( country_key )
|
|
88
|
-
|
|
97
|
+
reader = LeagueReader.new( include_path )
|
|
98
|
+
reader.read( name, club: true, country_id: country.id )
|
|
89
99
|
end
|
|
90
100
|
elsif name =~ /(?:^|\/)leagues/ # NB: ^leagues or also possible world!/leagues - NB: make sure goes after leagues_for_country!!
|
|
91
101
|
if name =~ /-cup!?\// || # NB: -cup/ or -cup!/
|
|
92
102
|
name =~ /copa-america!?\// # NB: copa-america/ or copa-america!/
|
|
93
103
|
# e.g. national team tournaments/leagues (e.g. world-cup/ or euro-cup/)
|
|
94
|
-
|
|
104
|
+
reader = LeagueReader.new( include_path )
|
|
105
|
+
reader.read( name, club: false )
|
|
95
106
|
else
|
|
96
107
|
# e.g. leagues_club
|
|
97
|
-
|
|
108
|
+
reader = LeagueReader.new( include_path )
|
|
109
|
+
reader.read( name, club: true )
|
|
98
110
|
end
|
|
99
111
|
elsif match_teams_for_country( name ) do |country_key| # name =~ /^([a-z]{2})\/teams/
|
|
100
112
|
# auto-add country code (from folder structure) for country-specific teams
|
|
101
113
|
# e.g. at/teams at/teams.2 de/teams etc.
|
|
102
114
|
country = Country.find_by_key!( country_key )
|
|
103
|
-
|
|
115
|
+
reader = TeamReader.new( include_path )
|
|
116
|
+
reader.read( name, club: true, country_id: country.id )
|
|
104
117
|
end
|
|
105
118
|
elsif name =~ /(?:^|\/)teams/
|
|
106
119
|
if name =~ /-cup!?\// || # NB: -cup/ or -cup!/
|
|
107
120
|
name =~ /copa-america!?\// # NB: copa-america/ or copa-america!/
|
|
108
121
|
# assume national teams
|
|
109
122
|
# e.g. world-cup/teams amercia-cup/teams_northern
|
|
110
|
-
|
|
123
|
+
reader = TeamReader.new( include_path )
|
|
124
|
+
reader.read( name, club: false )
|
|
111
125
|
else
|
|
112
126
|
# club teams (many countries)
|
|
113
127
|
# e.g. club/europe/teams
|
|
114
|
-
|
|
128
|
+
reader = TeamReader.new( include_path )
|
|
129
|
+
reader.read( name, club: true )
|
|
115
130
|
end
|
|
116
131
|
elsif name =~ /\/(\d{4}|\d{4}_\d{2})\// || name =~ /\/(\d{4}|\d{4}_\d{2})$/
|
|
117
132
|
# e.g. must match /2012/ or /2012_13/
|
|
118
133
|
# or /2012 or /2012_13 e.g. brazil/2012 or brazil/2012_13
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
fixtures = fetch_event_fixtures( name )
|
|
122
|
-
fixtures.each do |fx|
|
|
123
|
-
load_fixtures( event.key, fx )
|
|
124
|
-
end
|
|
134
|
+
reader = GameReader.new( include_path )
|
|
135
|
+
reader.read( name )
|
|
125
136
|
else
|
|
126
137
|
logger.error "unknown sportdb fixture type >#{name}<"
|
|
127
138
|
# todo/fix: exit w/ error
|
|
128
139
|
end
|
|
129
140
|
end # method load
|
|
130
141
|
|
|
131
|
-
|
|
132
|
-
def load_stadiums( name, more_attribs={} )
|
|
133
|
-
reader = ValuesReaderV2.new( name, include_path, more_attribs )
|
|
134
|
-
|
|
135
|
-
reader.each_line do |new_attributes, values|
|
|
136
|
-
Ground.create_or_update_from_values( new_attributes, values )
|
|
137
|
-
end # each lines
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
def load_leagues( name, more_attribs={} )
|
|
142
|
-
|
|
143
|
-
reader = ValuesReaderV2.new( name, include_path, more_attribs )
|
|
144
|
-
|
|
145
|
-
reader.each_line do |new_attributes, values|
|
|
146
|
-
League.create_or_update_from_values( new_attributes, values )
|
|
147
|
-
end # each lines
|
|
148
|
-
|
|
149
|
-
end # load_leagues
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
def load_tracks( name, more_attribs={} )
|
|
153
|
-
|
|
154
|
-
reader = ValuesReaderV2.new( name, include_path, more_attribs )
|
|
155
|
-
|
|
156
|
-
reader.each_line do |new_attributes, values|
|
|
157
|
-
Track.create_or_update_from_values( new_attributes, values )
|
|
158
|
-
end # each lines
|
|
159
|
-
|
|
160
|
-
end # load_tracks
|
|
161
|
-
|
|
162
142
|
|
|
143
|
+
####
|
|
144
|
+
## fix: move to persondb for (re)use
|
|
163
145
|
|
|
164
146
|
def load_persons( name, more_attribs={} )
|
|
165
147
|
|
|
@@ -171,775 +153,6 @@ class Reader
|
|
|
171
153
|
|
|
172
154
|
end # load_persons
|
|
173
155
|
|
|
174
|
-
|
|
175
|
-
def load_seasons( name )
|
|
176
|
-
|
|
177
|
-
reader = LineReaderV2.new( name, include_path )
|
|
178
|
-
|
|
179
|
-
####
|
|
180
|
-
## fix!!!!!
|
|
181
|
-
## use Season.create_or_update_from_hash or similar
|
|
182
|
-
## use Season.create_or_update_from_hash_reader?? or similar
|
|
183
|
-
# move parsing code to model
|
|
184
|
-
|
|
185
|
-
reader.each_line do |line|
|
|
186
|
-
|
|
187
|
-
# for now assume single value
|
|
188
|
-
logger.debug ">#{line}<"
|
|
189
|
-
|
|
190
|
-
key = line
|
|
191
|
-
|
|
192
|
-
logger.debug " find season key: #{key}"
|
|
193
|
-
season = Season.find_by_key( key )
|
|
194
|
-
|
|
195
|
-
season_attribs = {}
|
|
196
|
-
|
|
197
|
-
## check if it exists
|
|
198
|
-
if season.present?
|
|
199
|
-
logger.debug "update season #{season.id}-#{season.key}:"
|
|
200
|
-
else
|
|
201
|
-
logger.debug "create season:"
|
|
202
|
-
season = Season.new
|
|
203
|
-
season_attribs[ :key ] = key
|
|
204
|
-
end
|
|
205
|
-
|
|
206
|
-
season_attribs[ :title ] = key # for now key n title are the same
|
|
207
|
-
|
|
208
|
-
logger.debug season_attribs.to_json
|
|
209
|
-
|
|
210
|
-
season.update_attributes!( season_attribs )
|
|
211
|
-
end # each line
|
|
212
|
-
|
|
213
|
-
end # load_seasons
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
def fetch_event_fixtures( name )
|
|
217
|
-
# todo: merge with fetch_event to make it single read op - why? why not??
|
|
218
|
-
reader = HashReaderV2.new( name, include_path )
|
|
219
|
-
|
|
220
|
-
fixtures = []
|
|
221
|
-
|
|
222
|
-
reader.each_typed do |key, value|
|
|
223
|
-
if key == 'fixtures' && value.kind_of?( Array )
|
|
224
|
-
logger.debug "fixtures:"
|
|
225
|
-
logger.debug value.to_json
|
|
226
|
-
## todo: make sure we get an array!!!!!
|
|
227
|
-
fixtures = value
|
|
228
|
-
else
|
|
229
|
-
# skip; do nothing
|
|
230
|
-
end
|
|
231
|
-
end # each key,value
|
|
232
|
-
|
|
233
|
-
if fixtures.empty?
|
|
234
|
-
## logger.warn "no fixtures found for event - >#{name}<; assume fixture name is the same as event"
|
|
235
|
-
fixtures = [name]
|
|
236
|
-
else
|
|
237
|
-
## add path to fixtures (use path from event e.g)
|
|
238
|
-
# - bl + at-austria!/2012_13/bl -> at-austria!/2012_13/bl
|
|
239
|
-
# - bl_ii + at-austria!/2012_13/bl -> at-austria!/2012_13/bl_ii
|
|
240
|
-
|
|
241
|
-
dir = File.dirname( name ) # use dir for fixtures
|
|
242
|
-
|
|
243
|
-
fixtures = fixtures.map do |fx|
|
|
244
|
-
fx_new = "#{dir}/#{fx}" # add path upfront
|
|
245
|
-
logger.debug "fx: #{fx_new} | >#{fx}< + >#{dir}<"
|
|
246
|
-
fx_new
|
|
247
|
-
end
|
|
248
|
-
end
|
|
249
|
-
|
|
250
|
-
fixtures
|
|
251
|
-
end
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
def fetch_event( name )
|
|
255
|
-
# get/fetch/find event from yml file
|
|
256
|
-
|
|
257
|
-
## todo/fix: use h = HashFile.load( path ) or similar instead of HashReader!!
|
|
258
|
-
|
|
259
|
-
## todo/fix: add option for not adding prop automatically?? w/ HashReaderV2
|
|
260
|
-
|
|
261
|
-
reader = HashReaderV2.new( name, include_path )
|
|
262
|
-
|
|
263
|
-
event_attribs = {}
|
|
264
|
-
|
|
265
|
-
reader.each_typed do |key, value|
|
|
266
|
-
|
|
267
|
-
## puts "processing event attrib >>#{key}<< >>#{value}<<..."
|
|
268
|
-
|
|
269
|
-
if key == 'league'
|
|
270
|
-
league = League.find_by_key!( value.to_s.strip )
|
|
271
|
-
event_attribs[ 'league_id' ] = league.id
|
|
272
|
-
elsif key == 'season'
|
|
273
|
-
season = Season.find_by_key!( value.to_s.strip )
|
|
274
|
-
event_attribs[ 'season_id' ] = season.id
|
|
275
|
-
else
|
|
276
|
-
# skip; do nothing
|
|
277
|
-
end
|
|
278
|
-
end # each key,value
|
|
279
|
-
|
|
280
|
-
league_id = event_attribs['league_id']
|
|
281
|
-
season_id = event_attribs['season_id']
|
|
282
|
-
|
|
283
|
-
event = Event.find_by_league_id_and_season_id!( league_id, season_id )
|
|
284
|
-
event
|
|
285
|
-
end
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
def load_event( name )
|
|
289
|
-
|
|
290
|
-
####
|
|
291
|
-
## fix!!!!!
|
|
292
|
-
## use Event.create_or_update_from_hash or similar
|
|
293
|
-
## use Event.create_or_update_from_hash_reader?? or similar
|
|
294
|
-
# move parsing code to model
|
|
295
|
-
|
|
296
|
-
reader = HashReaderV2.new( name, include_path )
|
|
297
|
-
|
|
298
|
-
event_attribs = {}
|
|
299
|
-
|
|
300
|
-
## set default sources to basename by convention
|
|
301
|
-
# e.g 2013_14/bl => bl
|
|
302
|
-
# etc.
|
|
303
|
-
# use fixtures/sources: to override default
|
|
304
|
-
|
|
305
|
-
event_attribs[ 'sources' ] = File.basename( name )
|
|
306
|
-
event_attribs[ 'config' ] = File.basename( name ) # name a of .yml file
|
|
307
|
-
|
|
308
|
-
reader.each_typed do |key, value|
|
|
309
|
-
|
|
310
|
-
## puts "processing event attrib >>#{key}<< >>#{value}<<..."
|
|
311
|
-
|
|
312
|
-
if key == 'league'
|
|
313
|
-
league = League.find_by_key( value.to_s.strip )
|
|
314
|
-
|
|
315
|
-
## check if it exists
|
|
316
|
-
if league.present?
|
|
317
|
-
event_attribs['league_id'] = league.id
|
|
318
|
-
else
|
|
319
|
-
logger.error "league with key >>#{value.to_s.strip}<< missing"
|
|
320
|
-
exit 1
|
|
321
|
-
end
|
|
322
|
-
|
|
323
|
-
elsif key == 'season'
|
|
324
|
-
season = Season.find_by_key( value.to_s.strip )
|
|
325
|
-
|
|
326
|
-
## check if it exists
|
|
327
|
-
if season.present?
|
|
328
|
-
event_attribs['season_id'] = season.id
|
|
329
|
-
else
|
|
330
|
-
logger.error "season with key >>#{value.to_s.strip}<< missing"
|
|
331
|
-
exit 1
|
|
332
|
-
end
|
|
333
|
-
|
|
334
|
-
elsif key == 'start_at' || key == 'begin_at'
|
|
335
|
-
|
|
336
|
-
if value.is_a?(DateTime) || value.is_a?(Date)
|
|
337
|
-
start_at = value
|
|
338
|
-
else # assume it's a string
|
|
339
|
-
start_at = DateTime.strptime( value.to_s.strip, '%Y-%m-%d' )
|
|
340
|
-
end
|
|
341
|
-
|
|
342
|
-
event_attribs['start_at'] = start_at
|
|
343
|
-
|
|
344
|
-
elsif key == 'end_at' || key == 'stop_at'
|
|
345
|
-
|
|
346
|
-
if value.is_a?(DateTime) || value.is_a?(Date)
|
|
347
|
-
end_at = value
|
|
348
|
-
else # assume it's a string
|
|
349
|
-
end_at = DateTime.strptime( value.to_s.strip, '%Y-%m-%d' )
|
|
350
|
-
end
|
|
351
|
-
|
|
352
|
-
event_attribs['end_at'] = end_at
|
|
353
|
-
|
|
354
|
-
elsif key == 'grounds' || key == 'stadiums' || key == 'venues'
|
|
355
|
-
## assume grounds value is an array
|
|
356
|
-
|
|
357
|
-
##
|
|
358
|
-
## note: for now we allow invalid ground keys
|
|
359
|
-
## will skip keys not found
|
|
360
|
-
|
|
361
|
-
ground_ids = []
|
|
362
|
-
value.each do |item|
|
|
363
|
-
ground_key = item.to_s.strip
|
|
364
|
-
ground = Ground.find_by_key( ground_key )
|
|
365
|
-
if ground.nil?
|
|
366
|
-
puts "[warn] ground/stadium w/ key >#{ground_key}< not found; skipping ground"
|
|
367
|
-
else
|
|
368
|
-
ground_ids << ground.id
|
|
369
|
-
end
|
|
370
|
-
end
|
|
371
|
-
|
|
372
|
-
event_attribs['ground_ids'] = ground_ids
|
|
373
|
-
elsif key == 'teams'
|
|
374
|
-
## assume teams value is an array
|
|
375
|
-
|
|
376
|
-
team_ids = []
|
|
377
|
-
value.each do |item|
|
|
378
|
-
team_key = item.to_s.strip
|
|
379
|
-
team = Team.find_by_key!( team_key )
|
|
380
|
-
team_ids << team.id
|
|
381
|
-
end
|
|
382
|
-
|
|
383
|
-
event_attribs['team_ids'] = team_ids
|
|
384
|
-
|
|
385
|
-
elsif key == 'team3'
|
|
386
|
-
## for now always assume false # todo: fix - use value and convert to boolean if not boolean
|
|
387
|
-
event_attribs['team3'] = false
|
|
388
|
-
elsif key == 'fixtures' || key == 'sources'
|
|
389
|
-
if value.kind_of?(Array)
|
|
390
|
-
event_attribs['sources'] = value.join(',')
|
|
391
|
-
else # assume plain (single fixture) string
|
|
392
|
-
event_attribs['sources'] = value.to_s
|
|
393
|
-
end
|
|
394
|
-
else
|
|
395
|
-
## todo: add a source location struct to_s or similar (file, line, col)
|
|
396
|
-
logger.error "unknown event attrib #{key}; skipping attrib"
|
|
397
|
-
end
|
|
398
|
-
|
|
399
|
-
end # each key,value
|
|
400
|
-
|
|
401
|
-
league_id = event_attribs['league_id']
|
|
402
|
-
season_id = event_attribs['season_id']
|
|
403
|
-
|
|
404
|
-
logger.debug "find event - league_id: #{league_id}, season_id: #{season_id}"
|
|
405
|
-
|
|
406
|
-
event = Event.find_by_league_id_and_season_id( league_id, season_id )
|
|
407
|
-
|
|
408
|
-
## check if it exists
|
|
409
|
-
if event.present?
|
|
410
|
-
logger.debug "*** update event #{event.id}-#{event.key}:"
|
|
411
|
-
else
|
|
412
|
-
logger.debug "*** create event:"
|
|
413
|
-
event = Event.new
|
|
414
|
-
end
|
|
415
|
-
|
|
416
|
-
logger.debug event_attribs.to_json
|
|
417
|
-
|
|
418
|
-
event.update_attributes!( event_attribs )
|
|
419
|
-
|
|
420
|
-
end # load_event
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
def load_fixtures_from_string( event_key, text ) # load from string (e.g. passed in via web form)
|
|
425
|
-
|
|
426
|
-
SportDb.lang.lang = SportDb.lang.classify( text )
|
|
427
|
-
|
|
428
|
-
## todo/fix: move code into LineReader e.g. use LineReader.fromString() - why? why not?
|
|
429
|
-
reader = StringLineReader.new( text )
|
|
430
|
-
|
|
431
|
-
load_fixtures_worker( event_key, reader )
|
|
432
|
-
|
|
433
|
-
## fix add prop
|
|
434
|
-
### Prop.create!( key: "db.#{fixture_name_to_prop_key(name)}.version", value: "file.txt.#{File.mtime(path).strftime('%Y.%m.%d')}" )
|
|
435
|
-
end
|
|
436
|
-
|
|
437
|
-
def load_fixtures( event_key, name ) # load from file system
|
|
438
|
-
|
|
439
|
-
## todo: move name_real_path code to LineReaderV2 ????
|
|
440
|
-
pos = name.index( '!/')
|
|
441
|
-
if pos.nil?
|
|
442
|
-
name_real_path = name # not found; real path is the same as name
|
|
443
|
-
else
|
|
444
|
-
# cut off everything until !/ e.g.
|
|
445
|
-
# at-austria!/w-wien/beers becomes
|
|
446
|
-
# w-wien/beers
|
|
447
|
-
name_real_path = name[ (pos+2)..-1 ]
|
|
448
|
-
end
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
path = "#{include_path}/#{name_real_path}.txt"
|
|
452
|
-
|
|
453
|
-
logger.info "parsing data '#{name}' (#{path})..."
|
|
454
|
-
|
|
455
|
-
SportDb.lang.lang = SportDb.lang.classify_file( path )
|
|
456
|
-
|
|
457
|
-
reader = LineReader.new( path )
|
|
458
|
-
|
|
459
|
-
load_fixtures_worker( event_key, reader )
|
|
460
|
-
|
|
461
|
-
Prop.create_from_fixture!( name, path )
|
|
462
|
-
end
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
def load_records( name, more_attribs={} )
|
|
467
|
-
path = "#{include_path}/#{name}.txt"
|
|
468
|
-
|
|
469
|
-
logger.info "parsing data '#{name}' (#{path})..."
|
|
470
|
-
|
|
471
|
-
### SportDb.lang.lang = LangChecker.new.analyze( name, include_path )
|
|
472
|
-
|
|
473
|
-
reader = LineReader.new( path )
|
|
474
|
-
|
|
475
|
-
## for now: use all tracks (later filter/scope by event)
|
|
476
|
-
# @known_tracks = Track.known_tracks_table
|
|
477
|
-
|
|
478
|
-
## fix: add @known_teams - for now; use teams (not scoped by event)
|
|
479
|
-
@known_teams = TextUtils.build_title_table_for( Team.all )
|
|
480
|
-
## and for now use all persons
|
|
481
|
-
@known_persons = TextUtils.build_title_table_for( Person.all )
|
|
482
|
-
|
|
483
|
-
load_records_worker( reader, more_attribs )
|
|
484
|
-
|
|
485
|
-
Prop.create_from_fixture!( name, path )
|
|
486
|
-
end
|
|
487
|
-
|
|
488
|
-
def load_records_worker( reader, more_attribs )
|
|
489
|
-
|
|
490
|
-
reader.each_line do |line|
|
|
491
|
-
logger.debug " line: >#{line}<"
|
|
492
|
-
|
|
493
|
-
cut_off_end_of_line_comment!( line )
|
|
494
|
-
|
|
495
|
-
state = find_record_leading_state!( line )
|
|
496
|
-
|
|
497
|
-
map_team!( line )
|
|
498
|
-
team_key = find_team!( line )
|
|
499
|
-
team = Team.find_by_key!( team_key )
|
|
500
|
-
|
|
501
|
-
map_person!( line )
|
|
502
|
-
person_key = find_person!( line )
|
|
503
|
-
person = Person.find_by_key!( person_key )
|
|
504
|
-
|
|
505
|
-
timeline = find_record_timeline!( line )
|
|
506
|
-
|
|
507
|
-
laps = find_record_laps!( line )
|
|
508
|
-
|
|
509
|
-
comment = find_record_comment!( line )
|
|
510
|
-
|
|
511
|
-
logger.debug " line2: >#{line}<"
|
|
512
|
-
|
|
513
|
-
record_attribs = {
|
|
514
|
-
state: state,
|
|
515
|
-
## team_id: team.id, ## NB: not needed for db
|
|
516
|
-
person_id: person.id,
|
|
517
|
-
timeline: timeline,
|
|
518
|
-
comment: comment,
|
|
519
|
-
laps: laps
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
record_attribs = record_attribs.merge( more_attribs )
|
|
523
|
-
|
|
524
|
-
### check if record exists
|
|
525
|
-
record = Record.find_by_race_id_and_person_id( record_attribs[ :race_id ],
|
|
526
|
-
record_attribs[ :person_id ])
|
|
527
|
-
|
|
528
|
-
if record.present?
|
|
529
|
-
logger.debug "update Record #{record.id}:"
|
|
530
|
-
else
|
|
531
|
-
logger.debug "create Record:"
|
|
532
|
-
record = Record.new
|
|
533
|
-
end
|
|
534
|
-
|
|
535
|
-
logger.debug record_attribs.to_json
|
|
536
|
-
|
|
537
|
-
record.update_attributes!( record_attribs )
|
|
538
|
-
|
|
539
|
-
end # lines.each
|
|
540
|
-
|
|
541
|
-
end # method load_record_worker
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
def load_rosters( name )
|
|
546
|
-
path = "#{include_path}/#{name}.txt"
|
|
547
|
-
|
|
548
|
-
logger.info "parsing data '#{name}' (#{path})..."
|
|
549
|
-
|
|
550
|
-
### SportDb.lang.lang = LangChecker.new.analyze( name, include_path )
|
|
551
|
-
|
|
552
|
-
reader = LineReader.new( path )
|
|
553
|
-
|
|
554
|
-
## for now: use all tracks (later filter/scope by event)
|
|
555
|
-
# @known_tracks = Track.known_tracks_table
|
|
556
|
-
|
|
557
|
-
## fix: add @known_teams - for now; use teams (not scoped by event)
|
|
558
|
-
## for now use all teams
|
|
559
|
-
@known_teams = TextUtils.build_title_table_for( Team.all )
|
|
560
|
-
## and for now use all persons
|
|
561
|
-
@known_persons = TextUtils.build_title_table_for( Person.all )
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
load_rosters_worker( reader )
|
|
565
|
-
|
|
566
|
-
Prop.create_from_fixture!( name, path )
|
|
567
|
-
end
|
|
568
|
-
|
|
569
|
-
def load_rosters_worker( reader )
|
|
570
|
-
|
|
571
|
-
reader.each_line do |line|
|
|
572
|
-
logger.debug " line: >#{line}<"
|
|
573
|
-
|
|
574
|
-
cut_off_end_of_line_comment!( line )
|
|
575
|
-
|
|
576
|
-
pos = find_leading_pos!( line )
|
|
577
|
-
|
|
578
|
-
map_team!( line )
|
|
579
|
-
team_key = find_team!( line )
|
|
580
|
-
team = Team.find_by_key!( team_key )
|
|
581
|
-
|
|
582
|
-
map_person!( line )
|
|
583
|
-
person_key = find_person!( line )
|
|
584
|
-
person = Person.find_by_key!( person_key )
|
|
585
|
-
|
|
586
|
-
logger.debug " line2: >#{line}<"
|
|
587
|
-
|
|
588
|
-
### check if roster record exists
|
|
589
|
-
roster = Roster.find_by_event_id_and_team_id_and_person_id( @event.id, team.id, person.id )
|
|
590
|
-
|
|
591
|
-
if roster.present?
|
|
592
|
-
logger.debug "update Roster #{roster.id}:"
|
|
593
|
-
else
|
|
594
|
-
logger.debug "create Roster:"
|
|
595
|
-
roster = Roster.new
|
|
596
|
-
end
|
|
597
|
-
|
|
598
|
-
roster_attribs = {
|
|
599
|
-
pos: pos,
|
|
600
|
-
team_id: team.id,
|
|
601
|
-
person_id: person.id,
|
|
602
|
-
event_id: @event.id # NB: reuse/fallthrough from races - make sure load_races goes first (to setup event)
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
logger.debug roster_attribs.to_json
|
|
606
|
-
|
|
607
|
-
roster.update_attributes!( roster_attribs )
|
|
608
|
-
end # lines.each
|
|
609
|
-
|
|
610
|
-
end # method load_rosters_worker
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
def load_races( name )
|
|
615
|
-
load_event( name ) # must have .yml file with same name for event definition
|
|
616
|
-
@event = fetch_event( name )
|
|
617
|
-
|
|
618
|
-
logger.info " event: #{@event.key} >>#{@event.full_title}<<"
|
|
619
|
-
|
|
620
|
-
path = "#{include_path}/#{name}.txt"
|
|
621
|
-
|
|
622
|
-
logger.info "parsing data '#{name}' (#{path})..."
|
|
623
|
-
|
|
624
|
-
### SportDb.lang.lang = LangChecker.new.analyze( name, include_path )
|
|
625
|
-
|
|
626
|
-
reader = LineReader.new( path )
|
|
627
|
-
|
|
628
|
-
## for now: use all tracks (later filter/scope by event)
|
|
629
|
-
@known_tracks = Track.known_tracks_table
|
|
630
|
-
|
|
631
|
-
load_races_worker( reader )
|
|
632
|
-
|
|
633
|
-
Prop.create_from_fixture!( name, path )
|
|
634
|
-
end
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
def load_races_worker( reader )
|
|
638
|
-
|
|
639
|
-
reader.each_line do |line|
|
|
640
|
-
logger.debug " line: >#{line}<"
|
|
641
|
-
|
|
642
|
-
cut_off_end_of_line_comment!( line )
|
|
643
|
-
|
|
644
|
-
pos = find_leading_pos!( line )
|
|
645
|
-
|
|
646
|
-
map_track!( line )
|
|
647
|
-
track_key = find_track!( line )
|
|
648
|
-
track = Track.find_by_key!( track_key )
|
|
649
|
-
|
|
650
|
-
date = find_date!( line )
|
|
651
|
-
|
|
652
|
-
logger.debug " line2: >#{line}<"
|
|
653
|
-
|
|
654
|
-
### check if games exists
|
|
655
|
-
race = Race.find_by_event_id_and_track_id( @event.id, track.id )
|
|
656
|
-
|
|
657
|
-
if race.present?
|
|
658
|
-
logger.debug "update race #{race.id}:"
|
|
659
|
-
else
|
|
660
|
-
logger.debug "create race:"
|
|
661
|
-
race = Race.new
|
|
662
|
-
end
|
|
663
|
-
|
|
664
|
-
race_attribs = {
|
|
665
|
-
pos: pos,
|
|
666
|
-
track_id: track.id,
|
|
667
|
-
start_at: date,
|
|
668
|
-
event_id: @event.id
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
logger.debug race_attribs.to_json
|
|
672
|
-
|
|
673
|
-
race.update_attributes!( race_attribs )
|
|
674
|
-
end # lines.each
|
|
675
|
-
|
|
676
|
-
end # method load_races_worker
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
def load_teams( name, more_attribs={} )
|
|
680
|
-
reader = ValuesReaderV2.new( name, include_path, more_attribs )
|
|
681
|
-
|
|
682
|
-
reader.each_line do |new_attributes, values|
|
|
683
|
-
Team.create_or_update_from_values( new_attributes, values )
|
|
684
|
-
end # each lines
|
|
685
|
-
end # load_teams
|
|
686
|
-
|
|
687
|
-
private
|
|
688
|
-
|
|
689
|
-
include SportDb::FixtureHelpers
|
|
690
|
-
|
|
691
|
-
def load_fixtures_worker( event_key, reader )
|
|
692
|
-
|
|
693
|
-
## assume active activerecord connection
|
|
694
|
-
##
|
|
695
|
-
|
|
696
|
-
## reset cached values
|
|
697
|
-
@patch_rounds = {}
|
|
698
|
-
@knockout_flag = false
|
|
699
|
-
@round = nil
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
@event = Event.find_by_key!( event_key )
|
|
703
|
-
|
|
704
|
-
logger.debug "Event #{@event.key} >#{@event.title}<"
|
|
705
|
-
|
|
706
|
-
### fix: use build_title_table_for ??? why? why not??
|
|
707
|
-
@known_teams = @event.known_teams_table
|
|
708
|
-
|
|
709
|
-
@known_grounds = TextUtils.build_title_table_for( @event.grounds )
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
parse_fixtures( reader )
|
|
713
|
-
|
|
714
|
-
end # method load_fixtures
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
def parse_group( line )
|
|
718
|
-
logger.debug "parsing group line: >#{line}<"
|
|
719
|
-
|
|
720
|
-
match_teams!( line )
|
|
721
|
-
team_keys = find_teams!( line )
|
|
722
|
-
|
|
723
|
-
title, pos = find_group_title_and_pos!( line )
|
|
724
|
-
|
|
725
|
-
logger.debug " line: >#{line}<"
|
|
726
|
-
|
|
727
|
-
group_attribs = {
|
|
728
|
-
title: title
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
@group = Group.find_by_event_id_and_pos( @event.id, pos )
|
|
732
|
-
if @group.present?
|
|
733
|
-
logger.debug "update group #{@group.id}:"
|
|
734
|
-
else
|
|
735
|
-
logger.debug "create group:"
|
|
736
|
-
@group = Group.new
|
|
737
|
-
group_attribs = group_attribs.merge( {
|
|
738
|
-
event_id: @event.id,
|
|
739
|
-
pos: pos
|
|
740
|
-
})
|
|
741
|
-
end
|
|
742
|
-
|
|
743
|
-
logger.debug group_attribs.to_json
|
|
744
|
-
|
|
745
|
-
@group.update_attributes!( group_attribs )
|
|
746
|
-
|
|
747
|
-
@group.teams.clear # remove old teams
|
|
748
|
-
## add new teams
|
|
749
|
-
team_keys.each do |team_key|
|
|
750
|
-
team = Team.find_by_key!( team_key )
|
|
751
|
-
logger.debug " adding team #{team.title} (#{team.code})"
|
|
752
|
-
@group.teams << team
|
|
753
|
-
end
|
|
754
|
-
end
|
|
755
|
-
|
|
756
|
-
def parse_round( line )
|
|
757
|
-
logger.debug "parsing round line: >#{line}<"
|
|
758
|
-
|
|
759
|
-
### todo/fix/check: move cut off optional comment in reader for all lines? why? why not?
|
|
760
|
-
cut_off_end_of_line_comment!( line ) # cut off optional comment starting w/ #
|
|
761
|
-
|
|
762
|
-
# NB: cut off optional title2 starting w/ // first
|
|
763
|
-
title2 = find_round_title2!( line )
|
|
764
|
-
|
|
765
|
-
group_title, group_pos = find_group_title_and_pos!( line )
|
|
766
|
-
|
|
767
|
-
pos = find_round_pos!( line )
|
|
768
|
-
|
|
769
|
-
title = find_round_title!( line )
|
|
770
|
-
|
|
771
|
-
## NB: use extracted round title for knockout check
|
|
772
|
-
@knockout_flag = is_knockout_round?( title )
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
if group_pos.present?
|
|
776
|
-
@group = Group.find_by_event_id_and_pos!( @event.id, group_pos )
|
|
777
|
-
else
|
|
778
|
-
@group = nil # reset group to no group
|
|
779
|
-
end
|
|
780
|
-
|
|
781
|
-
logger.debug " line: >#{line}<"
|
|
782
|
-
|
|
783
|
-
## NB: dummy/placeholder start_at, end_at date
|
|
784
|
-
## replace/patch after adding all games for round
|
|
785
|
-
|
|
786
|
-
round_attribs = {
|
|
787
|
-
title: title,
|
|
788
|
-
title2: title2,
|
|
789
|
-
knockout: @knockout_flag
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
@round = Round.find_by_event_id_and_pos( @event.id, pos )
|
|
794
|
-
if @round.present?
|
|
795
|
-
logger.debug "update round #{@round.id}:"
|
|
796
|
-
else
|
|
797
|
-
logger.debug "create round:"
|
|
798
|
-
@round = Round.new
|
|
799
|
-
|
|
800
|
-
round_attribs = round_attribs.merge( {
|
|
801
|
-
event_id: @event.id,
|
|
802
|
-
pos: pos,
|
|
803
|
-
start_at: Time.utc('1912-12-12'),
|
|
804
|
-
end_at: Time.utc('1912-12-12')
|
|
805
|
-
})
|
|
806
|
-
end
|
|
807
|
-
|
|
808
|
-
logger.debug round_attribs.to_json
|
|
809
|
-
|
|
810
|
-
@round.update_attributes!( round_attribs )
|
|
811
|
-
|
|
812
|
-
### store list of round is for patching start_at/end_at at the end
|
|
813
|
-
@patch_rounds[ @round.id ] = @round.id
|
|
814
|
-
end
|
|
815
|
-
|
|
816
|
-
def parse_game( line )
|
|
817
|
-
logger.debug "parsing game (fixture) line: >#{line}<"
|
|
818
|
-
|
|
819
|
-
pos = find_game_pos!( line )
|
|
820
|
-
|
|
821
|
-
match_teams!( line )
|
|
822
|
-
team1_key = find_team1!( line )
|
|
823
|
-
team2_key = find_team2!( line )
|
|
824
|
-
|
|
825
|
-
if is_postponed?( line )
|
|
826
|
-
postponed = true
|
|
827
|
-
date_v2 = find_date!( line, start_at: @event.start_at )
|
|
828
|
-
date = find_date!( line, start_at: @event.start_at )
|
|
829
|
-
else
|
|
830
|
-
postponed = false
|
|
831
|
-
date_v2 = nil
|
|
832
|
-
date = find_date!( line, start_at: @event.start_at )
|
|
833
|
-
end
|
|
834
|
-
|
|
835
|
-
scores = find_scores!( line )
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
map_ground!( line )
|
|
839
|
-
ground_key = find_ground!( line )
|
|
840
|
-
ground = ground_key.nil? ? nil : Ground.find_by_key!( ground_key )
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
logger.debug " line: >#{line}<"
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
### todo: cache team lookups in hash?
|
|
847
|
-
|
|
848
|
-
team1 = Team.find_by_key!( team1_key )
|
|
849
|
-
team2 = Team.find_by_key!( team2_key )
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
### check if games exists
|
|
853
|
-
## with this teams in this round if yes only update
|
|
854
|
-
game = Game.find_by_round_id_and_team1_id_and_team2_id(
|
|
855
|
-
@round.id, team1.id, team2.id
|
|
856
|
-
)
|
|
857
|
-
|
|
858
|
-
game_attribs = {
|
|
859
|
-
score1: scores[0],
|
|
860
|
-
score2: scores[1],
|
|
861
|
-
score1et: scores[2],
|
|
862
|
-
score2et: scores[3],
|
|
863
|
-
score1p: scores[4],
|
|
864
|
-
score2p: scores[5],
|
|
865
|
-
play_at: date,
|
|
866
|
-
play_at_v2: date_v2,
|
|
867
|
-
postponed: postponed,
|
|
868
|
-
knockout: @knockout_flag,
|
|
869
|
-
ground_id: ground.present? ? ground.id : nil,
|
|
870
|
-
group_id: @group.present? ? @group.id : nil
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
game_attribs[ :pos ] = pos if pos.present?
|
|
874
|
-
|
|
875
|
-
####
|
|
876
|
-
# note: only update if any changes (or create if new record)
|
|
877
|
-
if game.present? &&
|
|
878
|
-
game.check_for_changes( game_attribs ) == false
|
|
879
|
-
logger.debug " skip update game #{game.id}; no changes found"
|
|
880
|
-
else
|
|
881
|
-
if game.present?
|
|
882
|
-
logger.debug "update game #{game.id}:"
|
|
883
|
-
else
|
|
884
|
-
logger.debug "create game:"
|
|
885
|
-
game = Game.new
|
|
886
|
-
|
|
887
|
-
more_game_attribs = {
|
|
888
|
-
round_id: @round.id,
|
|
889
|
-
team1_id: team1.id,
|
|
890
|
-
team2_id: team2.id
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
## NB: use round.games.count for pos
|
|
894
|
-
## lets us add games out of order if later needed
|
|
895
|
-
more_game_attribs[ :pos ] = @round.games.count+1 if pos.nil?
|
|
896
|
-
|
|
897
|
-
game_attribs = game_attribs.merge( more_game_attribs )
|
|
898
|
-
end
|
|
899
|
-
|
|
900
|
-
logger.debug game_attribs.to_json
|
|
901
|
-
game.update_attributes!( game_attribs )
|
|
902
|
-
end
|
|
903
|
-
|
|
904
|
-
end # method parse_game
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
def parse_fixtures( reader )
|
|
908
|
-
|
|
909
|
-
reader.each_line do |line|
|
|
910
|
-
if is_round?( line )
|
|
911
|
-
parse_round( line )
|
|
912
|
-
elsif is_group?( line ) ## NB: group goes after round (round may contain group marker too)
|
|
913
|
-
parse_group( line )
|
|
914
|
-
else
|
|
915
|
-
parse_game( line )
|
|
916
|
-
end
|
|
917
|
-
end # lines.each
|
|
918
|
-
|
|
919
|
-
@patch_rounds.each do |k,v|
|
|
920
|
-
logger.debug "patch start_at/end_at date for round #{k}:"
|
|
921
|
-
round = Round.find( k )
|
|
922
|
-
games = round.games.order( 'play_at asc' ).all
|
|
923
|
-
|
|
924
|
-
## skip rounds w/ no games
|
|
925
|
-
|
|
926
|
-
## todo/fix: what's the best way for checking assoc w/ 0 recs?
|
|
927
|
-
next if games.size == 0
|
|
928
|
-
|
|
929
|
-
round_attribs = {}
|
|
930
|
-
|
|
931
|
-
## todo: check for no records
|
|
932
|
-
## e.g. if game[0].present? or just if game[0] ??
|
|
933
|
-
|
|
934
|
-
round_attribs[:start_at] = games[0].play_at
|
|
935
|
-
round_attribs[:end_at ] = games[-1].play_at
|
|
936
|
-
|
|
937
|
-
logger.debug round_attribs.to_json
|
|
938
|
-
round.update_attributes!( round_attribs )
|
|
939
|
-
end
|
|
940
|
-
|
|
941
|
-
end # method parse_fixtures
|
|
942
|
-
|
|
943
156
|
|
|
944
157
|
end # class Reader
|
|
945
158
|
end # module SportDb
|