sportdb-models 1.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. checksums.yaml +7 -0
  2. data/.gemtest +0 -0
  3. data/HISTORY.md +21 -0
  4. data/Manifest.txt +142 -0
  5. data/README.md +28 -0
  6. data/Rakefile +59 -0
  7. data/config/fixtures/de.yml +46 -0
  8. data/config/fixtures/en.yml +54 -0
  9. data/config/fixtures/es.yml +48 -0
  10. data/config/fixtures/fr.yml +53 -0
  11. data/config/fixtures/it.yml +55 -0
  12. data/config/fixtures/pt.yml +46 -0
  13. data/config/fixtures/ro.yml +55 -0
  14. data/data/seasons.txt +74 -0
  15. data/data/setups/all.txt +5 -0
  16. data/lib/sportdb/calc.rb +279 -0
  17. data/lib/sportdb/deleter.rb +52 -0
  18. data/lib/sportdb/finders/date.rb +374 -0
  19. data/lib/sportdb/finders/goals.rb +260 -0
  20. data/lib/sportdb/finders/scores.rb +122 -0
  21. data/lib/sportdb/lang.rb +216 -0
  22. data/lib/sportdb/matcher.rb +31 -0
  23. data/lib/sportdb/models.rb +259 -0
  24. data/lib/sportdb/models/assoc.rb +106 -0
  25. data/lib/sportdb/models/assoc_assoc.rb +15 -0
  26. data/lib/sportdb/models/badge.rb +14 -0
  27. data/lib/sportdb/models/event.rb +65 -0
  28. data/lib/sportdb/models/event_ground.rb +15 -0
  29. data/lib/sportdb/models/event_team.rb +16 -0
  30. data/lib/sportdb/models/forward.rb +55 -0
  31. data/lib/sportdb/models/game.rb +244 -0
  32. data/lib/sportdb/models/goal.rb +15 -0
  33. data/lib/sportdb/models/ground.rb +100 -0
  34. data/lib/sportdb/models/group.rb +23 -0
  35. data/lib/sportdb/models/group_team.rb +14 -0
  36. data/lib/sportdb/models/league.rb +83 -0
  37. data/lib/sportdb/models/person.rb +21 -0
  38. data/lib/sportdb/models/roster.rb +18 -0
  39. data/lib/sportdb/models/round.rb +22 -0
  40. data/lib/sportdb/models/season.rb +14 -0
  41. data/lib/sportdb/models/stats/alltime_standing.rb +44 -0
  42. data/lib/sportdb/models/stats/alltime_standing_entry.rb +23 -0
  43. data/lib/sportdb/models/stats/event_standing.rb +55 -0
  44. data/lib/sportdb/models/stats/event_standing_entry.rb +21 -0
  45. data/lib/sportdb/models/stats/group_standing.rb +50 -0
  46. data/lib/sportdb/models/stats/group_standing_entry.rb +22 -0
  47. data/lib/sportdb/models/team.rb +119 -0
  48. data/lib/sportdb/models/team_comp.rb +64 -0
  49. data/lib/sportdb/models/utils.rb +78 -0
  50. data/lib/sportdb/models/world/city.rb +21 -0
  51. data/lib/sportdb/models/world/continent.rb +20 -0
  52. data/lib/sportdb/models/world/country.rb +19 -0
  53. data/lib/sportdb/models/world/region.rb +19 -0
  54. data/lib/sportdb/patterns.rb +38 -0
  55. data/lib/sportdb/reader.rb +130 -0
  56. data/lib/sportdb/reader_file.rb +123 -0
  57. data/lib/sportdb/reader_zip.rb +165 -0
  58. data/lib/sportdb/readers/assoc.rb +54 -0
  59. data/lib/sportdb/readers/event.rb +200 -0
  60. data/lib/sportdb/readers/game.rb +877 -0
  61. data/lib/sportdb/readers/ground.rb +53 -0
  62. data/lib/sportdb/readers/league.rb +54 -0
  63. data/lib/sportdb/readers/season.rb +83 -0
  64. data/lib/sportdb/readers/squad_club.rb +201 -0
  65. data/lib/sportdb/readers/squad_national_team.rb +173 -0
  66. data/lib/sportdb/readers/team.rb +53 -0
  67. data/lib/sportdb/schema.rb +373 -0
  68. data/lib/sportdb/standings.rb +178 -0
  69. data/lib/sportdb/stats.rb +27 -0
  70. data/lib/sportdb/utils.rb +89 -0
  71. data/lib/sportdb/utils_date.rb +26 -0
  72. data/lib/sportdb/utils_goals.rb +20 -0
  73. data/lib/sportdb/utils_group.rb +63 -0
  74. data/lib/sportdb/utils_map.rb +44 -0
  75. data/lib/sportdb/utils_round.rb +165 -0
  76. data/lib/sportdb/utils_scores.rb +17 -0
  77. data/lib/sportdb/utils_teams.rb +43 -0
  78. data/lib/sportdb/version.rb +23 -0
  79. data/test/data/at-austria/2013_14/bl.txt +227 -0
  80. data/test/data/at-austria/2013_14/bl.yml +30 -0
  81. data/test/data/at-austria/2013_14/bl_ii.txt +154 -0
  82. data/test/data/at-austria/2013_14/el.txt +4 -0
  83. data/test/data/at-austria/2013_14/el.yml +25 -0
  84. data/test/data/at-austria/2013_14/squads/austria.txt +40 -0
  85. data/test/data/at-austria/2013_14/squads/salzburg.txt +35 -0
  86. data/test/data/at-austria/leagues.txt +11 -0
  87. data/test/data/at-austria/teams.txt +75 -0
  88. data/test/data/at-austria/teams_2.txt +34 -0
  89. data/test/data/national-teams/assocs.txt +231 -0
  90. data/test/data/national-teams/europe/assocs.txt +13 -0
  91. data/test/data/national-teams/europe/teams.txt +13 -0
  92. data/test/data/national-teams/north-america/assocs.txt +10 -0
  93. data/test/data/national-teams/north-america/teams.txt +7 -0
  94. data/test/data/national-teams/teams.txt +19 -0
  95. data/test/data/players/europe/at-austria/players.txt +45 -0
  96. data/test/data/players/europe/de-deutschland/players.txt +41 -0
  97. data/test/data/players/south-america/br-brazil/players.txt +51 -0
  98. data/test/data/world-cup/1930/cup.txt +71 -0
  99. data/test/data/world-cup/1930/cup.yml +23 -0
  100. data/test/data/world-cup/1930/cup_goals.txt +47 -0
  101. data/test/data/world-cup/1930/cup_goals.yml +23 -0
  102. data/test/data/world-cup/1954/cup.txt +90 -0
  103. data/test/data/world-cup/1954/cup.yml +30 -0
  104. data/test/data/world-cup/1962/cup.txt +86 -0
  105. data/test/data/world-cup/1962/cup.yml +32 -0
  106. data/test/data/world-cup/1974/cup.yml +35 -0
  107. data/test/data/world-cup/1974/cup_finals.txt +14 -0
  108. data/test/data/world-cup/1974/cup_i.txt +55 -0
  109. data/test/data/world-cup/1974/cup_ii.txt +34 -0
  110. data/test/data/world-cup/2014/cup.txt +5 -0
  111. data/test/data/world-cup/2014/cup.yml +54 -0
  112. data/test/data/world-cup/2014/squads/br-brazil.txt +46 -0
  113. data/test/data/world-cup/2014/squads/de-deutschland.txt +8 -0
  114. data/test/data/world-cup/2014/squads/jp-japan.txt +30 -0
  115. data/test/data/world-cup/2014/squads/uy-uruguay.txt +32 -0
  116. data/test/data/world-cup/leagues.txt +5 -0
  117. data/test/data/world-cup/seasons_1930.txt +4 -0
  118. data/test/data/world-cup/seasons_1954.txt +4 -0
  119. data/test/data/world-cup/seasons_1962.txt +4 -0
  120. data/test/data/world-cup/seasons_1974.txt +5 -0
  121. data/test/data/world-cup/teams_1930.txt +26 -0
  122. data/test/data/world-cup/teams_1954.txt +30 -0
  123. data/test/data/world-cup/teams_1962.txt +29 -0
  124. data/test/data/world-cup/teams_1974.txt +29 -0
  125. data/test/helper.rb +120 -0
  126. data/test/test_assoc_reader.rb +201 -0
  127. data/test/test_changes.rb +74 -0
  128. data/test/test_cursor.rb +50 -0
  129. data/test/test_date.rb +100 -0
  130. data/test/test_goals.rb +109 -0
  131. data/test/test_lang.rb +130 -0
  132. data/test/test_load.rb +61 -0
  133. data/test/test_reader.rb +88 -0
  134. data/test/test_reader_from_string.rb +65 -0
  135. data/test/test_round_auto.rb +370 -0
  136. data/test/test_round_def.rb +109 -0
  137. data/test/test_round_header.rb +183 -0
  138. data/test/test_scores.rb +70 -0
  139. data/test/test_squad_club_reader.rb +76 -0
  140. data/test/test_squad_national_team_reader.rb +116 -0
  141. data/test/test_standings.rb +279 -0
  142. data/test/test_standings_ii.rb +46 -0
  143. data/test/test_utils.rb +124 -0
  144. data/test/test_winner.rb +95 -0
  145. metadata +378 -0
@@ -0,0 +1,52 @@
1
+
2
+ module SportDb
3
+
4
+ class Deleter
5
+ ######
6
+ # NB: make models available in sportdb module by default with namespace
7
+ # e.g. lets you use Team instead of Model::Team
8
+ include SportDb::Models
9
+
10
+ def run
11
+ # for now delete all tables
12
+
13
+ ## stats
14
+ AlltimeStandingEntry.delete_all
15
+ AlltimeStanding.delete_all
16
+ GroupStandingEntry.delete_all
17
+ GroupStanding.delete_all
18
+
19
+
20
+ Goal.delete_all
21
+
22
+ Game.delete_all
23
+ Event.delete_all
24
+ EventTeam.delete_all
25
+ EventGround.delete_all
26
+ Group.delete_all
27
+ GroupTeam.delete_all
28
+ Round.delete_all
29
+ Badge.delete_all
30
+
31
+ Roster.delete_all
32
+
33
+ Team.delete_all
34
+
35
+ League.delete_all
36
+ Season.delete_all
37
+
38
+ Ground.delete_all # stadiums
39
+
40
+ Assoc.delete_all # associations / organizations
41
+ AssocAssoc.delete_all # associations / organizations
42
+
43
+ ## note: moved to racing.db - delete/remove!!!
44
+ ## Record.delete_all
45
+ ## Run.delete_all
46
+ ## Race.delete_all
47
+ ## Track.delete_all
48
+ end
49
+
50
+ end # class Deleter
51
+
52
+ end # module SportDb
@@ -0,0 +1,374 @@
1
+ # encoding: utf-8
2
+
3
+ #### fix: move to textutils for reuse !!!!!
4
+
5
+
6
+ module SportDb
7
+
8
+ class DateFinder
9
+
10
+ include LogUtils::Logging
11
+
12
+ # todo: make more generic for reuse
13
+ ### fix:
14
+ ### move to textutils
15
+ ## date/fr.yml en.yml etc. ???
16
+ ## why? why not?
17
+
18
+ MONTH_FR = 'Janvier|Janv|Jan|' +
19
+ 'Février|Févr|Fév|' +
20
+ 'Mars|Mar|' +
21
+ 'Avril|Avri|Avr|' +
22
+ 'Mai|' +
23
+ 'Juin|' +
24
+ 'Juillet|Juil|' +
25
+ 'Août|' +
26
+ 'Septembre|Sept|' +
27
+ 'Octobre|Octo|Oct|' +
28
+ 'Novembre|Nove|Nov|' +
29
+ 'Décembre|Déce|Déc'
30
+ MONTH_FR_TO_MM = {
31
+ 'Janvier' => '1', 'Janv' => '1', 'Jan' => '1', ## check janv in use??
32
+ 'Février' => '2', 'Févr' => '2', 'Fév' => '2', ## check fevr in use???
33
+ 'Mars' => '3', 'Mar' => '3',
34
+ 'Avril' => '4', 'Avri' => '4', 'Avr' => '4', ## check avri in use??? if not remove
35
+ 'Mai' => '5',
36
+ 'Juin' => '6',
37
+ 'Juillet' => '7', 'Juil' => '7',
38
+ 'Août' => '8',
39
+ 'Septembre' => '9', 'Sept' => '9',
40
+ 'Octobre' => '10', 'Octo' => '10', 'Oct' => '10', ### check octo in use??
41
+ 'Novembre' => '11', 'Nove' => '11', 'Nov' => '11', ## check nove in use??
42
+ 'Décembre' => '12', 'Déce' => '12', 'Déc' => '12' } ## check dece in use??
43
+ WEEKDAY_FR = 'Lundi|Lun|L|' +
44
+ 'Mardi|Mar|Ma|' +
45
+ 'Mercredi|Mer|Me|' +
46
+ 'Jeudi|Jeu|J|' +
47
+ 'Vendredi|Ven|V|' +
48
+ 'Samedi|Sam|S|' +
49
+ 'Dimanche|Dim|D|'
50
+
51
+
52
+ MONTH_EN = 'January|Jan|'+
53
+ 'February|Feb|'+
54
+ 'March|Mar|'+
55
+ 'April|Apr|'+
56
+ 'May|'+
57
+ 'June|Jun|'+
58
+ 'July|Jul|'+
59
+ 'August|Aug|'+
60
+ 'September|Sept|Sep|'+
61
+ 'October|Oct|'+
62
+ 'November|Nov|'+
63
+ 'December|Dec'
64
+ MONTH_EN_TO_MM = {
65
+ 'Jan' => '1', 'January' => '1',
66
+ 'Feb' => '2', 'February' => '2',
67
+ 'Mar' => '3', 'March' => '3',
68
+ 'Apr' => '4', 'April' => '4',
69
+ 'May' => '5',
70
+ 'Jun' => '6', 'June' => '6',
71
+ 'Jul' => '7', 'July' => '7',
72
+ 'Aug' => '8', 'August' => '8',
73
+ 'Sep' => '9', 'Sept' => '9', 'September' => '9',
74
+ 'Oct' => '10', 'October' => '10',
75
+ 'Nov' => '11', 'November' => '11',
76
+ 'Dec' => '12', 'December' =>'12' }
77
+
78
+ ###
79
+ ## todo: add days
80
+ ## 1. Sunday - Sun. 2. Monday - Mon.
81
+ ## 3. Tuesday - Tu., Tue., or Tues. 4. Wednesday - Wed.
82
+ ## 5. Thursday - Th., Thu., Thur., or Thurs. 6. Friday - Fri.
83
+ ## 7. Saturday - Sat.
84
+
85
+
86
+ MONTH_ES = 'Enero|Ene|Feb|Marzo|Mar|Abril|Abr|Mayo|May|Junio|Jun|Julio|Jul|Agosto|Ago|Sept|Set|Sep|Oct|Nov|Dic'
87
+ MONTH_ES_TO_MM = {
88
+ 'Ene' => '1', 'Enero' => '1',
89
+ 'Feb' => '2',
90
+ 'Mar' => '3', 'Marzo' => '3',
91
+ 'Abr' => '4', 'Abril' => '4',
92
+ 'May' => '5', 'Mayo' => '5',
93
+ 'Jun' => '6', 'Junio' => '6',
94
+ 'Jul' => '7', 'Julio' => '7',
95
+ 'Ago' => '8', 'Agosto' => '8',
96
+ 'Sep' => '9', 'Set' => '9', 'Sept' => '9',
97
+ 'Oct' => '10',
98
+ 'Nov' => '11',
99
+ 'Dic' => '12' }
100
+
101
+ # todo/fix - add de and es too!!
102
+ # note: in Austria - Jänner - in Deutschland Januar allow both ??
103
+ # MONTH_DE = 'J[aä]n|Feb|Mär|Apr|Mai|Jun|Jul|Aug|Sep|Okt|Nov|Dez'
104
+
105
+
106
+ # e.g. 2012-09-14 20:30 => YYYY-MM-DD HH:MM
107
+ # nb: allow 2012-9-3 7:30 e.g. no leading zero required
108
+ # regex_db
109
+ DB__DATE_TIME_REGEX = /\b
110
+ (?<year>\d{4})
111
+ -
112
+ (?<month>\d{1,2})
113
+ -
114
+ (?<day>\d{1,2})
115
+ \s+
116
+ (?<hours>\d{1,2})
117
+ :
118
+ (?<minutes>\d{2})
119
+ \b/x
120
+
121
+ # e.g. 2012-09-14 w/ implied hours (set to 12:00)
122
+ # nb: allow 2012-9-3 e.g. no leading zero required
123
+ # regex_db2
124
+ DB__DATE_REGEX = /\b
125
+ (?<year>\d{4})
126
+ -
127
+ (?<month>\d{1,2})
128
+ -
129
+ (?<day>\d{1,2})
130
+ \b/x
131
+
132
+ # e.g. 14.09.2012 20:30 => DD.MM.YYYY HH:MM
133
+ # nb: allow 2.3.2012 e.g. no leading zero required
134
+ # nb: allow hour as 20.30
135
+ # regex_de
136
+ DD_MM_YYYY__DATE_TIME_REGEX = /\b
137
+ (?<day>\d{1,2})
138
+ \.
139
+ (?<month>\d{1,2})
140
+ \.
141
+ (?<year>\d{4})
142
+ \s+
143
+ (?<hours>\d{1,2})
144
+ [:.]
145
+ (?<minutes>\d{2})
146
+ \b/x
147
+
148
+ # e.g. 14.09. 20:30 => DD.MM. HH:MM
149
+ # nb: allow 2.3.2012 e.g. no leading zero required
150
+ # nb: allow hour as 20.30 or 3.30 instead of 03.30
151
+ # regex_de2
152
+ DD_MM__DATE_TIME_REGEX = /\b
153
+ (?<day>\d{1,2})
154
+ \.
155
+ (?<month>\d{1,2})
156
+ \.
157
+ \s+
158
+ (?<hours>\d{1,2})
159
+ [:.]
160
+ (?<minutes>\d{2})
161
+ \b/x
162
+
163
+ # e.g. 14.09.2012 => DD.MM.YYYY w/ implied hours (set to 12:00)
164
+ # regex_de3
165
+ DD_MM_YYYY__DATE_REGEX = /\b
166
+ (?<day>\d{1,2})
167
+ \.
168
+ (?<month>\d{1,2})
169
+ \.
170
+ (?<year>\d{4})
171
+ \b/x
172
+
173
+ # e.g. 14.09. => DD.MM. w/ implied year and implied hours (set to 12:00)
174
+ # note: allow end delimiter ] e.g. [Sa 12.01.] or end-of-string ($) too
175
+ # note: we use a lookahead for last part e.g. (?:\s+|$|[\]]) - do NOT cosume
176
+ # regex_de4 (use lookahead assert)
177
+ DD_MM__DATE_REGEX = /\b
178
+ (?<day>\d{1,2})
179
+ \.
180
+ (?<month>\d{1,2})
181
+ \.
182
+ (?=\s+|$|[\]])/x ## note: allow end-of-string/line too
183
+
184
+
185
+ # e.g. 12 May 2013 14:00 => D|DD.MMM.YYYY H|HH:MM
186
+ EN__DD_MONTH_YYYY__DATE_TIME_REGEX = /\b
187
+ (?<day>\d{1,2})
188
+ \s
189
+ (?<month_en>#{MONTH_EN})
190
+ \s
191
+ (?<year>\d{4})
192
+ \s+
193
+ (?<hours>\d{1,2})
194
+ :
195
+ (?<minutes>\d{2})
196
+ \b/x
197
+
198
+ ###
199
+ # fix: pass in lang (e.g. en or es)
200
+ # only process format for lang plus fallback to en?
201
+ # e.g. EN__DD_MONTH and ES__DD_MONTH depend on order for match (first listed will match)
202
+
203
+ # e.g. 12 May => D|DD.MMM w/ implied year and implied hours
204
+ EN__DD_MONTH__DATE_REGEX = /\b
205
+ (?<day>\d{1,2})
206
+ \s
207
+ (?<month_en>#{MONTH_EN})
208
+ \b/x
209
+
210
+
211
+ # e.g. Jun/12 2011 14:00
212
+ EN__MONTH_DD_YYYY__DATE_TIME_REGEX = /\b
213
+ (?<month_en>#{MONTH_EN})
214
+ \/
215
+ (?<day>\d{1,2})
216
+ \s
217
+ (?<year>\d{4})
218
+ \s+
219
+ (?<hours>\d{1,2})
220
+ :
221
+ (?<minutes>\d{2})
222
+ \b/x
223
+
224
+ # e.g. Jun/12 14:00 w/ implied year H|HH:MM
225
+ EN__MONTH_DD__DATE_TIME_REGEX = /\b
226
+ (?<month_en>#{MONTH_EN})
227
+ \/
228
+ (?<day>\d{1,2})
229
+ \s+
230
+ (?<hours>\d{1,2})
231
+ :
232
+ (?<minutes>\d{2})
233
+ \b/x
234
+
235
+ # e.g. Jun/12 2013 w/ implied hours (set to 12:00)
236
+ EN__MONTH_DD_YYYY__DATE_REGEX = /\b
237
+ (?<month_en>#{MONTH_EN})
238
+ \/
239
+ (?<day>\d{1,2})
240
+ \s
241
+ (?<year>\d{4})
242
+ \b/x
243
+
244
+ # e.g. Jun/12 w/ implied year and implied hours (set to 12:00)
245
+ EN__MONTH_DD__DATE_REGEX = /\b
246
+ (?<month_en>#{MONTH_EN})
247
+ \/
248
+ (?<day>\d{1,2})
249
+ \b/x
250
+
251
+
252
+ # e.g. 12 Ene w/ implied year and implied hours (set to 12:00)
253
+ ES__DD_MONTH__DATE_REGEX = /\b
254
+ (?<day>\d{1,2})
255
+ \s
256
+ (?<month_es>#{MONTH_ES})
257
+ \b/x
258
+
259
+ # e.g. Ven 8 Août or [Ven 8 Août] or Ven 8. Août or [Ven 8. Août]
260
+ ### note: do NOT consume [] in regex (use lookahead assert)
261
+ FR__WEEKDAY_DD_MONTH__DATE_REGEX = /\b
262
+ (?:#{WEEKDAY_FR}) # note: skip weekday for now; do NOT capture
263
+ \s+
264
+ (?<day>\d{1,2})
265
+ \.? # note: make dot optional
266
+ \s+
267
+ (?<month_fr>#{MONTH_FR})
268
+ (?=\s+|$|[\]])/x ## note: allow end-of-string/line too
269
+
270
+
271
+
272
+
273
+ # map table - 1) tag, 2) regex - note: order matters; first come-first matched/served
274
+ FORMATS = [
275
+ [ '[YYYY_MM_DD_hh_mm]', DB__DATE_TIME_REGEX ],
276
+ [ '[YYYY_MM_DD]', DB__DATE_REGEX ],
277
+ [ '[DD_MM_YYYY_hh_mm]', DD_MM_YYYY__DATE_TIME_REGEX ],
278
+ [ '[DD_MM_hh_mm]', DD_MM__DATE_TIME_REGEX ],
279
+ [ '[DD_MM_YYYY]', DD_MM_YYYY__DATE_REGEX ],
280
+ [ '[DD_MM]', DD_MM__DATE_REGEX ],
281
+ [ '[FR_WEEKDAY_DD_MONTH]', FR__WEEKDAY_DD_MONTH__DATE_REGEX ],
282
+ [ '[EN_DD_MONTH_YYYY_hh_mm]', EN__DD_MONTH_YYYY__DATE_TIME_REGEX ],
283
+ [ '[EN_MONTH_DD_YYYY_hh_mm]', EN__MONTH_DD_YYYY__DATE_TIME_REGEX ],
284
+ [ '[EN_MONTH_DD_hh_mm]', EN__MONTH_DD__DATE_TIME_REGEX ],
285
+ [ '[EN_MONTH_DD_YYYY]', EN__MONTH_DD_YYYY__DATE_REGEX ],
286
+ [ '[EN_MONTH_DD]', EN__MONTH_DD__DATE_REGEX ],
287
+ [ '[EN_DD_MONTH]', EN__DD_MONTH__DATE_REGEX ],
288
+ [ '[ES_DD_MONTH]', ES__DD_MONTH__DATE_REGEX ]
289
+ ]
290
+
291
+
292
+
293
+ def initialize
294
+ # nothing here for now
295
+ end
296
+
297
+ def find!( line, opts={} )
298
+ # fix: use more lookahead for all required trailing spaces!!!!!
299
+ # fix: use <name capturing group> for month,day,year etc.!!!
300
+
301
+ #
302
+ # fix: !!!!
303
+ # date in [] will become [[DATE.DE4]] - when getting removed will keep ]!!!!
304
+ # fix: change regex to \[[A-Z0-9.]\] !!!!!! plus add unit test too!!!
305
+ #
306
+
307
+ md = nil
308
+ FORMATS.each do |format|
309
+ tag = format[0]
310
+ pattern = format[1]
311
+ md=pattern.match( line )
312
+ if md
313
+ date = parse_date_time( md, opts )
314
+ ## fix: use md[0] e.g. match for sub! instead of using regex again - why? why not???
315
+ ## fix: use md.begin(0), md.end(0)
316
+ line.sub!( md[0], tag )
317
+ ## todo/fix: make sure match data will not get changed (e.g. using sub! before parse_date_time)
318
+ return date
319
+ end
320
+ # no match; continue; try next pattern
321
+ end
322
+
323
+ return nil # no match found
324
+ end
325
+
326
+ private
327
+ def calc_year( month, day, opts )
328
+ start_at = opts[:start_at]
329
+
330
+ logger.debug " [calc_year] ????-#{month}-#{day} -- start_at: #{start_at}"
331
+
332
+ if month >= start_at.month
333
+ # assume same year as start_at event (e.g. 2013 for 2013/14 season)
334
+ start_at.year
335
+ else
336
+ # assume year+1 as start_at event (e.g. 2014 for 2013/14 season)
337
+ start_at.year+1
338
+ end
339
+ end
340
+
341
+ def parse_date_time( match_data, opts={} )
342
+
343
+ # convert regex match_data captures to hash
344
+ # - note: cannont use match_data like a hash (e.g. raises exception if key/name not present/found)
345
+ h = {}
346
+ # - note: do NOT forget to turn name into symbol for lookup in new hash (name.to_sym)
347
+ match_data.names.each { |name| h[name.to_sym] = match_data[name] } # or use match_data.names.zip( match_data.captures ) - more cryptic but "elegant"??
348
+
349
+ ## puts "[parse_date_time] match_data:"
350
+ ## pp h
351
+ logger.debug " [parse_date_time] hash: >#{h.inspect}<"
352
+
353
+ h[ :month ] = MONTH_EN_TO_MM[ h[:month_en] ] if h[:month_en]
354
+ h[ :month ] = MONTH_ES_TO_MM[ h[:month_es] ] if h[:month_es]
355
+ h[ :month ] = MONTH_FR_TO_MM[ h[:month_fr] ] if h[:month_fr]
356
+
357
+ month = h[:month]
358
+ day = h[:day]
359
+ year = h[:year] || calc_year( month.to_i, day.to_i, opts ).to_s
360
+
361
+ hours = h[:hours] || '12' # default to 12:00 for HH:MM (hours:minutes)
362
+ minutes = h[:minutes] || '00'
363
+
364
+ value = '%d-%02d-%02d %02d:%02d' % [year.to_i, month.to_i, day.to_i, hours.to_i, minutes.to_i]
365
+ logger.debug " date: >#{value}<"
366
+
367
+ DateTime.strptime( value, '%Y-%m-%d %H:%M' )
368
+ end
369
+
370
+
371
+ end # class DateFinder
372
+
373
+
374
+ end # module SportDb
@@ -0,0 +1,260 @@
1
+ # encoding: utf-8
2
+
3
+ module SportDb
4
+
5
+
6
+
7
+ class GoalsPlayerStruct
8
+ ##
9
+ # note: player with own goal (o.g) gets listed on other team
10
+ # (thus, player might have two entries if also scored for its own team)
11
+ #
12
+ attr_accessor :name
13
+ attr_accessor :minutes # ary of minutes e.g. 30', 45+2', 72'
14
+
15
+ def initialize
16
+ @minutes = []
17
+ end
18
+ end
19
+
20
+
21
+ class GoalsMinuteStruct
22
+ attr_accessor :minute, :offset
23
+ attr_accessor :penalty, :owngoal # flags
24
+
25
+ def initialize
26
+ @offset = 0
27
+ @penalty = false
28
+ @owngoal = false
29
+ end
30
+ end
31
+
32
+
33
+ class GoalStruct
34
+ ######
35
+ # flat struct for goals - one entry per goals
36
+ attr_accessor :name
37
+ attr_accessor :team # 1 or 2 ? check/todo: add team1 or team2 flag?
38
+ attr_accessor :minute, :offset
39
+ attr_accessor :penalty, :owngoal
40
+ attr_accessor :score1, :score2 # gets calculated
41
+
42
+ ## add pos for sequence number? e.g. 1,2,3,4 (1st goald, 2nd goal, etc.) ???
43
+
44
+ def initialize
45
+ # do nothing
46
+ end
47
+ end
48
+
49
+
50
+
51
+ # todo: find a better name? to avoid confusing w/ GoalsParser? use MatchGoalsParser or similar?
52
+ class GoalsFinder
53
+ include LogUtils::Logging
54
+ include FixtureHelpers # e.g. cut_off_end_of_line_comment!
55
+
56
+ def initialize
57
+ # nothing here for now
58
+ end
59
+
60
+ def find!( line, opts={} )
61
+ # remove end-of-line comments
62
+ # - move to textutils ?? why? why not??
63
+ cut_off_end_of_line_comment!( line ) ## note: func defined in utils.rb (FixtureHelpers)
64
+
65
+ # remove [] if presents e.g. [Neymar 12']
66
+ line = line.gsub( /[\[\]]/, '' )
67
+ # remove (single match) if line starts w/ - (allow spaces) e.g. [-;Neymar 12'] or [ - ;Neymar 12']
68
+ line = line.sub( /^[ ]*-[ ]*/, '' )
69
+
70
+ # split into left hand side (lhs) for team1 and
71
+ # right hand side (rhs) for team2
72
+
73
+ values = line.split( ';' )
74
+
75
+ # note: allow empty right hand side (e.g. team2 did NOT score any goals e.g. 3-0 etc.)
76
+ lhs = values[0]
77
+ rhs = values[1]
78
+
79
+ lhs = lhs.strip unless lhs.nil?
80
+ rhs = rhs.strip unless rhs.nil?
81
+
82
+ parser = GoalsParser.new
83
+ ## todo/check: only call if not nil?
84
+
85
+ logger.debug " lhs (team1): >#{lhs}<"
86
+ lhs_data = parser.parse!( lhs )
87
+ pp lhs_data
88
+
89
+ logger.debug " rhs (team2): >#{rhs}<"
90
+ rhs_data = parser.parse!( rhs )
91
+ pp rhs_data
92
+
93
+ ### merge into flat goal structs
94
+ goals = []
95
+ lhs_data.each do |player|
96
+ player.minutes.each do |minute|
97
+ goal = GoalStruct.new
98
+ goal.name = player.name
99
+ goal.team = 1
100
+ goal.minute = minute.minute
101
+ goal.offset = minute.offset
102
+ goal.penalty = minute.penalty
103
+ goal.owngoal = minute.owngoal
104
+ goals << goal
105
+ end
106
+ end
107
+
108
+ rhs_data.each do |player|
109
+ player.minutes.each do |minute|
110
+ goal = GoalStruct.new
111
+ goal.name = player.name
112
+ goal.team = 2
113
+ goal.minute = minute.minute
114
+ goal.offset = minute.offset
115
+ goal.penalty = minute.penalty
116
+ goal.owngoal = minute.owngoal
117
+ goals << goal
118
+ end
119
+ end
120
+
121
+
122
+ # sort by minute + offset
123
+ goals = goals.sort do |l,r|
124
+ res = l.minute <=> r.minute
125
+ if res == 0
126
+ res = l.offset <=> r.offset # pass 2: sort by offset
127
+ end
128
+ res
129
+ end
130
+
131
+ ## calc score1,score2
132
+ score1 = 0
133
+ score2 = 0
134
+ goals.each do |goal|
135
+ if goal.team == 1
136
+ score1 += 1
137
+ elsif goal.team == 2
138
+ score2 += 1
139
+ else
140
+ # todo: should not happen: issue warning
141
+ end
142
+ goal.score1 = score1
143
+ goal.score2 = score2
144
+ end
145
+
146
+ logger.debug " #{goals.size} goals:"
147
+ pp goals
148
+
149
+ goals
150
+ end
151
+
152
+ end # class GoalsFinder
153
+
154
+
155
+ class GoalsParser
156
+ include LogUtils::Logging
157
+
158
+
159
+ # note: use ^ for start of string only!!!
160
+ # - for now slurp everything up to digits (inlc. spaces - use strip to remove)
161
+ # todo/check: use/rename to NAME_UNTIL_REGEX ??? ( add lookahead for spaces?)
162
+ NAME_REGEX = /^
163
+ [^0-9]+
164
+ /x
165
+
166
+
167
+ # todo/check: change to MINUTE_REGEX ??
168
+ # add MINUTE_SKIP_REGEX or MINUTE_SEP_REGEX /^[ ,]+/
169
+ # todo/fix: split out penalty and owngoal flag in PATTERN constant for reuse
170
+ MINUTES_REGEX = /^ # note: use ^ for start of string only!!!
171
+ (?<minute>[0-9]{1,3})
172
+ (?:\+
173
+ (?<offset>[1-9]{1})
174
+ )?
175
+ '
176
+ (?:[ ]*
177
+ \(
178
+ (?<type>P|pen\.|o\.g\.)
179
+ \)
180
+ )?
181
+ /x
182
+
183
+
184
+
185
+ def initialize
186
+ # nothing here for now
187
+ end
188
+
189
+ def parse!( line, opts={} )
190
+
191
+ ## for now assume
192
+ ## everything up-to 0-9 and , and () is part of player name
193
+
194
+ ## try parsing lhs
195
+ ## todo: check for empty - remove (make it same as empty string)
196
+
197
+ players = []
198
+
199
+ name = get_player_name!( line )
200
+ while name
201
+ logger.debug " found player name >#{name}< - remaining >#{line}<"
202
+
203
+ player = GoalsPlayerStruct.new
204
+ player.name = name
205
+
206
+ minute_hash = get_minute_hash!( line )
207
+ while minute_hash
208
+ logger.debug " found minutes >#{minute_hash.inspect}< - remaining >#{line}<"
209
+
210
+ minute = GoalsMinuteStruct.new
211
+ minute.minute = minute_hash[:minute].to_i
212
+ minute.offset = minute_hash[:offset].to_i if minute_hash[:offset]
213
+ if minute_hash[:type]
214
+ minute.owngoal = true if minute_hash[:type] =~ /o\.g\./
215
+ minute.penalty = true if minute_hash[:type] =~ /P|pen\./
216
+ end
217
+ player.minutes << minute
218
+
219
+ # remove commas and spaces (note: use ^ for start of string only!!!)
220
+ line.sub!( /^[ ,]+/, '' )
221
+ minute_hash = get_minute_hash!( line )
222
+ end
223
+
224
+ players << player
225
+ name = get_player_name!( line )
226
+ end
227
+
228
+ players
229
+ end # method parse!
230
+
231
+ private
232
+ def get_player_name!( line )
233
+ m = NAME_REGEX.match( line )
234
+ if m
235
+ ## remove from line
236
+ line.slice!( 0...m[0].length )
237
+ m[0].strip # remove leading and trailing spaces
238
+ else
239
+ nil
240
+ end
241
+ end
242
+
243
+ def get_minute_hash!( line )
244
+ m = MINUTES_REGEX.match( line ) # note: use ^ for start of string only!!!
245
+ if m
246
+ h = {}
247
+ # - note: do NOT forget to turn name into symbol for lookup in new hash (name.to_sym)
248
+ m.names.each { |n| h[n.to_sym] = m[n] } # or use match_data.names.zip( match_data.captures ) - more cryptic but "elegant"??
249
+
250
+ ## remove matched string from line
251
+ line.slice!( 0...m[0].length )
252
+ h
253
+ else
254
+ nil
255
+ end
256
+ end
257
+
258
+ end # class GoalsParser
259
+
260
+ end # module SportDb