sportdb 0.9.1 → 0.9.2

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.
@@ -23,8 +23,8 @@ Season = SportDB::Models::Season
23
23
  League = SportDB::Models::League
24
24
  Badge = SportDB::Models::Badge
25
25
 
26
- # Tag = WorldDB::Models::Tag
27
- # Tagging = WorldDB::Models::Tagging
26
+ Tag = WorldDB::Models::Tag
27
+ Tagging = WorldDB::Models::Tagging
28
28
  Country = WorldDB::Models::Country
29
29
  Region = WorldDB::Models::Region
30
30
  City = WorldDB::Models::City
@@ -49,6 +49,44 @@ puts " #{'%5d' % Game.count} games"
49
49
  puts " #{'%5d' % City.count} cities"
50
50
  puts "Ready."
51
51
 
52
+ ## add some predefined shortcuts
53
+
54
+ ##### some countries
55
+
56
+ AT = Country.find_by_key( 'at' )
57
+ DE = Country.find_by_key( 'de' )
58
+ EN = Country.find_by_key( 'en' )
59
+
60
+ US = Country.find_by_key( 'us' )
61
+ CA = Country.find_by_key( 'ca' )
62
+ MX = Country.find_by_key( 'mx' )
63
+
64
+ #### some events
65
+
66
+ EURO2008 = Event.find_by_key( 'euro.2008' )
67
+ EURO2012 = Event.find_by_key( 'euro.2012' )
68
+ EURO = EURO2012 # add alias
69
+
70
+ BL = Event.find_by_key( 'de.2012/13' )
71
+ PL = Event.find_by_key( 'en.2012/13' )
72
+
73
+ ### some club teams
74
+
75
+ BARCA = Team.find_by_key( 'barcelona' )
76
+ MANU = Team.find_by_key( 'manunited' )
77
+ MUN = MANUNITED = MANU # add alias
78
+ BAYERN = Team.find_by_key( 'bayern' )
79
+ AUSTRIA = Team.find_by_key( 'austria' )
80
+
81
+ ### some national teams (three letter fifa codes)
82
+
83
+ ESP = Team.find_by_key( 'esp' )
84
+ GER = Team.find_by_key( 'ger' )
85
+ AUT = Team.find_by_key( 'aut' )
86
+
87
+ MEX = Team.find_by_key( 'mex' )
88
+ ARG = Team.find_by_key( 'arg' )
89
+
52
90
  ## turn on activerecord logging to console
53
91
 
54
92
  ActiveRecord::Base.logger = Logger.new( STDOUT )
@@ -65,22 +65,6 @@ class Loader
65
65
 
66
66
  private
67
67
 
68
- ##
69
- # fix/todo: share helper w/ other readers
70
-
71
- # helper
72
- # change at/2012_13/bl to at.2012/13.bl
73
- # or quali_2012_13_europe_c to quali.2012/13.europe.c
74
-
75
- def fixture_name_to_prop_key( name )
76
- prop_key = name.gsub( '/', '.' )
77
- prop_key = prop_key.gsub( /(\d{4})_(\d{2})/, '\1/\2' ) # 2012_13 => 2012/13
78
- prop_key = prop_key.gsub( '_', '.' )
79
- prop_key
80
- end
81
-
82
-
83
-
84
68
 
85
69
  def load_fixtures_worker( code )
86
70
 
@@ -40,56 +40,6 @@ class Event < ActiveRecord::Base
40
40
  #####################
41
41
  ## convenience helper for text parser/reader
42
42
 
43
- ############
44
- ### fix/todo: share helper for all text readers/parsers- where to put it?
45
- ###
46
-
47
- def title_esc_regex( title_unescaped )
48
-
49
- ## escape regex special chars e.g. . to \. and ( to \( etc.
50
- # e.g. Benfica Lis.
51
- # e.g. Club Atlético Colón (Santa Fe)
52
-
53
- ## NB: cannot use Regexp.escape! will escape space '' to '\ '
54
- ## title = Regexp.escape( title_unescaped )
55
- title = title_unescaped.gsub( '.', '\.' )
56
- title = title.gsub( '(', '\(' )
57
- title = title.gsub( ')', '\)' )
58
-
59
- ## match accented char with or without accents
60
- ## add (ü|ue) etc.
61
- ## also make - optional change to (-| ) e.g. Blau-Weiss == Blau Weiss
62
-
63
- ## todo: add some more
64
- ## see http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references for more
65
- ##
66
- ## reuse for all readers!
67
-
68
- alternatives = [
69
- ['-', '(-| )'],
70
- ['ß', '(ß|ss)'],
71
- ['æ', '(æ|ae)'],
72
- ['á', '(á|a)'], ## e.g. Bogotá
73
- ['ã', '(ã|a)'], ## e.g São Paulo
74
- ['ä', '(ä|ae)'], ## add a ?
75
- ['Ö', '(Ö|Oe)'], ## e.g. Österreich
76
- ['ö', '(ö|oe)'], ## add o ?
77
- ['ó', '(ó|o)'], ## e.g. Colón
78
- ['ü', '(ü|ue)'], ## add u ?
79
- ['é', '(é|e)'], ## e.g. Vélez
80
- ['ê', '(ê|e)'], ## e.g. Grêmio
81
- ['ñ', '(ñ|n)'], ## e.g. Porteño
82
- ['ú', '(ú|u)'] ## e.g. Fútbol
83
- ]
84
-
85
- alternatives.each do |alt|
86
- title = title.gsub( alt[0], alt[1] )
87
- end
88
-
89
- title
90
- end
91
-
92
-
93
43
  def known_teams_table
94
44
 
95
45
  ## build known teams table w/ synonyms e.g.
@@ -40,11 +40,9 @@ class Reader
40
40
 
41
41
  puts "*** parsing data '#{name}' (#{path})..."
42
42
 
43
- ## nb: assume/enfore utf-8 encoding (with or without BOM - byte order mark)
44
- ## - see sportdb/utils.rb
45
- code = File.read_utf8( path )
43
+ reader = LineReader.new( logger, path )
46
44
 
47
- load_fixtures_worker( event_key, code )
45
+ load_fixtures_worker( event_key, reader )
48
46
 
49
47
  Prop.create!( key: "db.#{fixture_name_to_prop_key(name)}.version", value: "file.txt.#{File.mtime(path).strftime('%Y.%m.%d')}" )
50
48
  end
@@ -54,31 +52,69 @@ class Reader
54
52
 
55
53
  puts "*** parsing data '#{name}' (#{path})..."
56
54
 
57
- code = File.read_utf8( path )
58
-
59
- load_fixtures_worker( event_key, code )
55
+ reader = LineReader.new( logger, path )
56
+
57
+ load_fixtures_worker( event_key, reader )
60
58
 
61
59
  Prop.create!( key: "db.#{fixture_name_to_prop_key(name)}.version", value: "sport.txt.#{SportDB::VERSION}" )
62
60
  end
63
61
 
64
62
 
65
- private
63
+ def load_teams_builtin( name, more_values={} )
64
+ path = "#{SportDB.root}/db/#{name}.txt"
66
65
 
67
- ##
68
- # fix/todo: share helper w/ other readers
69
-
70
- # helper
71
- # change at/2012_13/bl to at.2012/13.bl
72
- # or quali_2012_13_europe_c to quali.2012/13.europe.c
73
-
74
- def fixture_name_to_prop_key( name )
75
- prop_key = name.gsub( '/', '.' )
76
- prop_key = prop_key.gsub( /(\d{4})_(\d{2})/, '\1/\2' ) # 2012_13 => 2012/13
77
- prop_key = prop_key.gsub( '_', '.' )
78
- prop_key
66
+ puts "*** parsing data '#{name}' (#{path})..."
67
+
68
+ reader = ValuesReader.new( logger, path, more_values )
69
+
70
+ load_teams_worker( reader )
71
+
72
+ Prop.create!( key: "db.#{fixture_name_to_prop_key(name)}.version", value: "sport.txt.#{SportDB::VERSION}" )
79
73
  end
80
74
 
81
- def load_fixtures_worker( event_key, data )
75
+
76
+ private
77
+
78
+ include SportDB::FixtureHelpers
79
+
80
+ def load_teams_worker( reader )
81
+
82
+ reader.each_line do |attribs, values|
83
+
84
+ ## check optional values
85
+ values.each_with_index do |value, index|
86
+ if value =~ /^city:/ ## city:
87
+ value_city_key = value[5..-1] ## cut off city: prefix
88
+ value_city = City.find_by_key!( value_city_key )
89
+ attribs[ :city_id ] = value_city.id
90
+ elsif value =~ /^[A-Z]{3}$/ ## assume three-letter code e.g. FCB, RBS, etc.
91
+ attribs[ :code ] = value
92
+ elsif value =~ /^[a-z]{2}$/ ## assume two-letter country key e.g. at,de,mx,etc.
93
+ value_country = Country.find_by_key!( value )
94
+ attribs[ :country_id ] = value_country.id
95
+ else
96
+ ## todo: assume title2 ??
97
+ # issue warning: unknown type for value
98
+ puts "*** warning: unknown type for value >#{value}<"
99
+ end
100
+ end
101
+
102
+ rec = Team.find_by_key( attribs[ :key ] )
103
+ if rec.present?
104
+ puts "*** update Team #{rec.id}-#{rec.key}:"
105
+ else
106
+ puts "*** create Team:"
107
+ rec = Team.new
108
+ end
109
+
110
+ puts attribs.to_json
111
+
112
+ rec.update_attributes!( attribs )
113
+
114
+ end # each lines
115
+ end # method load_teams_worker
116
+
117
+ def load_fixtures_worker( event_key, reader )
82
118
 
83
119
  ## assume active activerecord connection
84
120
  ##
@@ -95,258 +131,11 @@ private
95
131
 
96
132
  @known_teams = @event.known_teams_table
97
133
 
98
- parse_fixtures( data )
134
+ parse_fixtures( reader )
99
135
 
100
136
  end # method load_fixtures
101
137
 
102
138
 
103
- def is_round?( line )
104
- line =~ /Spieltag|Runde|Achtelfinale|Viertelfinale|Halbfinale|Finale/
105
- end
106
-
107
- def is_group?( line )
108
- # NB: check after is_round? (round may contain group reference!)
109
- line =~ /Gruppe|Group/
110
- end
111
-
112
- ### todo: rename to is_knockout_round?
113
- ##
114
- def find_knockout_flag( line )
115
- if line =~ /Achtelfinale|Viertelfinale|Halbfinale|Spiel um Platz 3|Finale|K\.O\.|Knockout/
116
- puts " setting knockout flag to true"
117
- true
118
- else
119
- false
120
- end
121
- end
122
-
123
- def find_group_title_and_pos!( line )
124
- ## group pos - for now support single digit e.g 1,2,3 or letter e.g. A,B,C
125
- ## nb: (?:) = is for non-capturing group(ing)
126
- regex = /(?:Group|Gruppe)\s+((?:\d{1}|[A-Z]{1}))\b/
127
-
128
- match = regex.match( line )
129
- unless match.nil?
130
- if match[1] == 'A'
131
- pos = 1
132
- elsif match[1] == 'B'
133
- pos = 2
134
- elsif match[1] == 'C'
135
- pos = 3
136
- elsif match[1] == 'D'
137
- pos = 4
138
- elsif match[1] == 'E'
139
- pos = 5
140
- elsif match[1] == 'F'
141
- pos = 6
142
- elsif match[1] == 'G'
143
- pos = 7
144
- elsif match[1] == 'H'
145
- pos = 8
146
- elsif match[1] == 'I'
147
- pos = 9
148
- elsif match[1] == 'J'
149
- pos = 10
150
- else
151
- pos = match[1].to_i
152
- end
153
-
154
- title = match[0]
155
-
156
- puts " title: >#{title}<"
157
- puts " pos: >#{pos}<"
158
-
159
- line.sub!( regex, '[GROUP|TITLE+POS]' )
160
-
161
- return [title,pos]
162
- else
163
- return [nil,nil]
164
- end
165
- end
166
-
167
- def find_round_pos!( line )
168
- ## fix/todo:
169
- ## if no round found assume last_pos+1 ??? why? why not?
170
-
171
- regex = /\b(\d+)\b/
172
-
173
- if line =~ regex
174
- value = $1.to_i
175
- puts " pos: >#{value}<"
176
-
177
- line.sub!( regex, '[ROUND|POS]' )
178
-
179
- return value
180
- else
181
- return nil
182
- end
183
- end
184
-
185
- def find_date!( line )
186
- # extract date from line
187
- # and return it
188
- # NB: side effect - removes date from line string
189
-
190
- # e.g. 2012-09-14 20:30 => YYYY-MM-DD HH:MM
191
- regex_db = /\b(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2})\b/
192
-
193
- # e.g. 14.09. 20:30 => DD.MM. HH:MM
194
- regex_de = /\b(\d{2})\.(\d{2})\.\s+(\d{2}):(\d{2})\b/
195
-
196
- if line =~ regex_db
197
- value = "#{$1}-#{$2}-#{$3} #{$4}:#{$5}"
198
- puts " date: >#{value}<"
199
-
200
- ## todo: lets you configure year
201
- ## and time zone (e.g. cet, eet, utc, etc.)
202
-
203
- line.sub!( regex_db, '[DATE.DB]' )
204
-
205
- return DateTime.strptime( value, '%Y-%m-%d %H:%M' )
206
- elsif line =~ regex_de
207
- value = "2012-#{$2}-#{$1} #{$3}:#{$4}"
208
- puts " date: >#{value}<"
209
-
210
- ## todo: lets you configure year
211
- ## and time zone (e.g. cet, eet, utc, etc.)
212
-
213
- line.sub!( regex_de, '[DATE.DE]' )
214
-
215
- return DateTime.strptime( value, '%Y-%m-%d %H:%M' )
216
- else
217
- return nil
218
- end
219
- end
220
-
221
-
222
- def find_game_pos!( line )
223
- # extract optional game pos from line
224
- # and return it
225
- # NB: side effect - removes pos from line string
226
-
227
- # e.g. (1) - must start line
228
- regex = /^[ \t]*\((\d{1,3})\)[ \t]+/
229
- if line =~ regex
230
- puts " pos: >#{$1}<"
231
-
232
- line.sub!( regex, '[POS] ' )
233
- return $1.to_i
234
- else
235
- return nil
236
- end
237
-
238
- end
239
-
240
- def find_scores!( line )
241
- # extract score from line
242
- # and return it
243
- # NB: side effect - removes date from line string
244
-
245
- # e.g. 1:2 or 0:2 or 3:3
246
- regex = /\b(\d):(\d)\b/
247
-
248
- # e.g. 1:2nV => overtime
249
- regex_ot = /\b(\d):(\d)[ \t]?[nN][vV]\b/
250
-
251
- # e.g. 5:4iE => penalty
252
- regex_p = /\b(\d):(\d)[ \t]?[iI][eE]\b/
253
-
254
- scores = []
255
-
256
- if line =~ regex
257
- puts " score: >#{$1}-#{$2}<"
258
-
259
- line.sub!( regex, '[SCORE]' )
260
-
261
- scores << $1.to_i
262
- scores << $2.to_i
263
-
264
- if line =~ regex_ot
265
- puts " score.ot: >#{$1}-#{$2}<"
266
-
267
- line.sub!( regex_ot, '[SCORE.OT]' )
268
-
269
- scores << $1.to_i
270
- scores << $2.to_i
271
-
272
- if line =~ regex_p
273
- puts " score.p: >#{$1}-#{$2}<"
274
-
275
- line.sub!( regex_p, '[SCORE.P]' )
276
-
277
- scores << $1.to_i
278
- scores << $2.to_i
279
- end
280
- end
281
- end
282
- scores
283
- end # methdod find_scores!
284
-
285
-
286
- def find_team_worker!( line, index )
287
- regex = /@@oo([^@]+?)oo@@/ # e.g. everything in @@ .... @@ (use non-greedy +? plus all chars but not @, that is [^@])
288
-
289
- if line =~ regex
290
- value = "#{$1}"
291
- puts " team#{index}: >#{value}<"
292
-
293
- line.sub!( regex, "[TEAM#{index}]" )
294
-
295
- return $1
296
- else
297
- return nil
298
- end
299
- end
300
-
301
- def find_teams!( line )
302
- counter = 1
303
- teams = []
304
-
305
- team = find_team_worker!( line, counter )
306
- while team.present?
307
- teams << team
308
- counter += 1
309
- team = find_team_worker!( line, counter )
310
- end
311
-
312
- teams
313
- end
314
-
315
- def find_team1!( line )
316
- find_team_worker!( line, 1 )
317
- end
318
-
319
- def find_team2!( line )
320
- find_team_worker!( line, 2 )
321
- end
322
-
323
-
324
- def match_team_worker!( line, key, values )
325
- values.each do |value|
326
- ## nb: \b does NOT include space or newline for word boundry (only alphanums e.g. a-z0-9)
327
- ## (thus add it, allows match for Benfica Lis. for example - note . at the end)
328
-
329
- ## check add $ e.g. (\b| |\t|$) does this work? - check w/ Benfica Lis.$
330
- regex = /\b#{value}(\b| |\t|$)/ # wrap with world boundry (e.g. match only whole words e.g. not wac in wacker)
331
- if line =~ regex
332
- puts " match for team >#{key}< >#{value}<"
333
- # make sure @@oo{key}oo@@ doesn't match itself with other key e.g. wacker, wac, etc.
334
- line.sub!( regex, "@@oo#{key}oo@@ " ) # NB: add one space char at end
335
- return true # break out after first match (do NOT continue)
336
- end
337
- end
338
- return false
339
- end
340
-
341
- def match_teams!( line )
342
- @known_teams.each do |rec|
343
- key = rec[0]
344
- values = rec[1]
345
- match_team_worker!( line, key, values )
346
- end # each known_teams
347
- end # method translate_teams!
348
-
349
-
350
139
  def parse_group( line )
351
140
  puts "parsing group line: >#{line}<"
352
141
 
@@ -357,9 +146,6 @@ private
357
146
 
358
147
  puts " line: >#{line}<"
359
148
 
360
- ## world2 = Group.create!( event: world, pos: 2, title: 'Gruppe 2' )
361
- ## world2.add_teams_from_ary!( team_keys_world2 )
362
-
363
149
  group_attribs = {
364
150
  title: title
365
151
  }
@@ -393,7 +179,7 @@ private
393
179
  puts "parsing round line: >#{line}<"
394
180
  pos = find_round_pos!( line )
395
181
 
396
- @knockout_flag = find_knockout_flag( line )
182
+ @knockout_flag = is_knockout_round?( line )
397
183
 
398
184
  group_title, group_pos = find_group_title_and_pos!( line )
399
185
 
@@ -501,25 +287,9 @@ private
501
287
  end
502
288
 
503
289
 
504
- def parse_fixtures( data )
290
+ def parse_fixtures( reader )
505
291
 
506
- data.each_line do |line|
507
-
508
- if line =~ /^\s*#/
509
- # skip komments and do NOT copy to result (keep comments secret!)
510
- logger.debug 'skipping comment line'
511
- next
512
- end
513
-
514
- if line =~ /^\s*$/
515
- # kommentar oder leerzeile überspringen
516
- logger.debug 'skipping blank line'
517
- next
518
- end
519
-
520
- # remove leading and trailing whitespace
521
- line = line.strip
522
-
292
+ reader.each_line do |line|
523
293
  if is_round?( line )
524
294
  parse_round( line )
525
295
  elsif is_group?( line ) ## NB: group goes after round (round may contain group marker too)