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.
@@ -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
File without changes
@@ -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'
@@ -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
- load_tracks( name )
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
- load_tracks( name, country_id: country.id )
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
- load_tracks( name )
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
- load_teams( name )
71
+ reader = TeamReader.new( include_path )
72
+ reader.read( name )
69
73
  elsif name =~ /\/races/ # e.g. 2013/races.txt in formula1.db
70
- load_races( name )
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
- load_rosters( name )
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
- load_records( name, race_id: race.id ) # e.g. 2013/04-gp-monaco.txt in formula1.db
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
- load_seasons( name )
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
- load_stadiums( name, country_id: country.id )
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
- load_leagues( name, club: true, country_id: country.id )
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
- load_leagues( name, club: false )
104
+ reader = LeagueReader.new( include_path )
105
+ reader.read( name, club: false )
95
106
  else
96
107
  # e.g. leagues_club
97
- load_leagues( name, club: true )
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
- load_teams( name, club: true, country_id: country.id )
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
- load_teams( name, club: false )
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
- load_teams( name, club: true )
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
- load_event( name )
120
- event = fetch_event( name )
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