sportdb-formats 1.1.6 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +2 -0
  3. data/Manifest.txt +4 -25
  4. data/Rakefile +1 -1
  5. data/lib/sportdb/formats/country/country_reader.rb +142 -142
  6. data/lib/sportdb/formats/datafile.rb +59 -59
  7. data/lib/sportdb/formats/event/event_reader.rb +184 -183
  8. data/lib/sportdb/formats/goals.rb +53 -9
  9. data/lib/sportdb/formats/ground/ground_reader.rb +289 -0
  10. data/lib/sportdb/formats/league/league_reader.rb +152 -168
  11. data/lib/sportdb/formats/lines_reader.rb +47 -0
  12. data/lib/sportdb/formats/match/match_parser.rb +130 -13
  13. data/lib/sportdb/formats/match/match_parser_auto_conf.rb +270 -202
  14. data/lib/sportdb/formats/outline_reader.rb +0 -1
  15. data/lib/sportdb/formats/package.rb +394 -374
  16. data/lib/sportdb/formats/search/sport.rb +357 -0
  17. data/lib/sportdb/formats/search/world.rb +139 -0
  18. data/lib/sportdb/formats/team/club_index_history.rb +134 -134
  19. data/lib/sportdb/formats/team/club_reader.rb +318 -350
  20. data/lib/sportdb/formats/team/club_reader_history.rb +203 -203
  21. data/lib/sportdb/formats/team/wiki_reader.rb +108 -108
  22. data/lib/sportdb/formats/version.rb +4 -7
  23. data/lib/sportdb/formats.rb +60 -27
  24. metadata +13 -35
  25. data/lib/sportdb/formats/country/country_index.rb +0 -192
  26. data/lib/sportdb/formats/event/event_index.rb +0 -141
  27. data/lib/sportdb/formats/league/league_index.rb +0 -178
  28. data/lib/sportdb/formats/team/club_index.rb +0 -338
  29. data/lib/sportdb/formats/team/national_team_index.rb +0 -114
  30. data/lib/sportdb/formats/team/team_index.rb +0 -43
  31. data/test/helper.rb +0 -132
  32. data/test/test_club_index.rb +0 -183
  33. data/test/test_club_index_history.rb +0 -107
  34. data/test/test_club_reader.rb +0 -201
  35. data/test/test_club_reader_history.rb +0 -212
  36. data/test/test_club_reader_props.rb +0 -54
  37. data/test/test_country_index.rb +0 -63
  38. data/test/test_country_reader.rb +0 -89
  39. data/test/test_datafile.rb +0 -30
  40. data/test/test_datafile_package.rb +0 -46
  41. data/test/test_goals.rb +0 -113
  42. data/test/test_league_index.rb +0 -157
  43. data/test/test_league_outline_reader.rb +0 -55
  44. data/test/test_league_reader.rb +0 -72
  45. data/test/test_outline_reader.rb +0 -31
  46. data/test/test_package.rb +0 -78
  47. data/test/test_package_match.rb +0 -102
  48. data/test/test_regex.rb +0 -67
  49. data/test/test_wiki_reader.rb +0 -77
@@ -0,0 +1,357 @@
1
+ ###
2
+ # sport search service api for leagues, clubs and more
3
+ #
4
+ # core api is:
5
+
6
+
7
+ class SportSearch
8
+
9
+ class Search ## base search service - use/keep - why? why not?
10
+ def initialize( service ) @service = service; end
11
+ end # class Search
12
+
13
+
14
+ class PlayerSearch < Search
15
+ ###################
16
+ ## core required delegates - use delegate generator - why? why not?
17
+ def match_by( name:, country: nil, year: nil )
18
+ @service.match_by( name: name,
19
+ country: country,
20
+ year: year )
21
+ end
22
+
23
+ ###############
24
+ ### more deriv support functions / helpers
25
+ def match( name ) match_by( name: name ); end
26
+ ## add more here - why? why not?
27
+ end # class PlayerSearch
28
+
29
+
30
+ class LeagueSearch < Search
31
+ ###################
32
+ ## core required delegates - use delegate generator - why? why not?
33
+ def match_by( name:, country: nil )
34
+ @service.match_by( name: name,
35
+ country: country )
36
+ end
37
+
38
+ ###############
39
+ ### more deriv support functions / helpers
40
+ def match( name ) match_by( name: name ); end
41
+
42
+ def find!( name )
43
+ league = find( name )
44
+ if league.nil?
45
+ puts "** !!! ERROR - no league match found for >#{name}<, add to leagues table; sorry"
46
+ exit 1
47
+ end
48
+ league
49
+ end
50
+
51
+ def find( name )
52
+ league = nil
53
+ recs = match( name )
54
+ # pp m
55
+
56
+ if recs.empty?
57
+ ## fall through/do nothing
58
+ elsif recs.size > 1
59
+ puts "** !!! ERROR - ambigious league name; too many leagues (#{recs.size}) found:"
60
+ pp recs
61
+ exit 1
62
+ else
63
+ league = recs[0]
64
+ end
65
+
66
+ league
67
+ end
68
+ end # class LeagueSearch
69
+
70
+
71
+ class GroundSearch < Search
72
+ ###################
73
+ ## core required delegates - use delegate generator - why? why not?
74
+ def match_by( name:, country: nil, city: nil )
75
+ @service.match_by( name: name,
76
+ country: country,
77
+ city: city )
78
+ end
79
+
80
+ ###############
81
+ ### more deriv support functions / helpers
82
+ def match( name ) match_by( name: name ); end
83
+ ## add more here - why? why not?
84
+ end # class GroundSearch
85
+
86
+
87
+
88
+ class NationalTeamSearch < Search
89
+ ###################
90
+ ## core required delegates - use delegate generator - why? why not?
91
+
92
+ ## changle core api to match( q ) only - why? why not?
93
+ ## and make find and find! derivs???
94
+ def find( q ) @service.find( q ); end
95
+ def find!( q ) @service.find!( q ); end
96
+ end # class NationalTeamSearch
97
+
98
+
99
+ class ClubSearch < Search
100
+ ###################
101
+ ## core required delegates - use delegate generator - why? why not?
102
+
103
+ ## add mods here - why? why not?
104
+
105
+ def match_by( name:, country: nil,
106
+ league: nil,
107
+ mods: nil )
108
+ ## for now assume "global" mods - checks only for name
109
+ ##
110
+ if mods && mods[ name ]
111
+ club = mods[ name ]
112
+ return [club] # note: wrap (single record) in array
113
+ end
114
+
115
+ ## note: add "auto-magic" country calculation via league record
116
+ ## if league is a national league for football clubs
117
+ if league
118
+ raise ArgumentError, "match_by - league AND country NOT supported; sorry" if country
119
+ ### find countries via league
120
+ ### support league.intl? too - why? why not?
121
+ ### or only nationa league
122
+ raise ArgumentError, "match_by - league - only national club leagues supported (not int'l or national teams for now); sorry" unless league.national? && league.clubs?
123
+
124
+ ### calc countries
125
+ ### uses "global" func in sports-catalogs for now
126
+ ## move code here - why? why not?
127
+ country = find_countries_for_league( league )
128
+ @service.match_by( name: name,
129
+ country: country )
130
+ else
131
+ @service.match_by( name: name,
132
+ country: country )
133
+ end
134
+ end
135
+
136
+
137
+ ## todo/fix/check: use rename to find_canon or find_canonical() or something??
138
+ ## remove (getting used?) - why? why not?
139
+ # def []( name ) ## lookup by canoncial name only; todo/fix: add find alias why? why not?
140
+ # puts "WARN!! do not use ClubIndex#[] for lookup >#{name}< - will get removed!!!"
141
+ # @clubs[ name ]
142
+ # end
143
+
144
+
145
+ ###############
146
+ ### more deriv support functions / helpers
147
+ def match( name ) match_by( name: name ); end
148
+
149
+ ##########
150
+ # "legacy" finders - return zero or one club
151
+ ## (if more than one match, exit/raise error/exception)
152
+ def find( name ) find_by( name: name ); end
153
+ def find!( name ) find_by!( name: name ); end
154
+
155
+ ## find - always returns a single record / match or nil
156
+ ## if there is more than one match than find aborts / fails
157
+ def find_by!( name:, country: nil,
158
+ league: nil ) ## todo/fix: add international or league flag?
159
+ club = find_by( name: name,
160
+ country: country,
161
+ league: league )
162
+
163
+ if club.nil?
164
+ puts "** !!! ERROR - no match for club >#{name}<"
165
+ exit 1
166
+ end
167
+
168
+ club
169
+ end
170
+
171
+
172
+ def find_by( name:, country: nil,
173
+ league: nil ) ## todo/fix: add international or league flag?
174
+ ## note: allow passing in of country key too (auto-counvert)
175
+ ## and country struct too
176
+ ## - country assumes / allows the country key or fifa code for now
177
+ recs = match_by( name: name,
178
+ country: country,
179
+ league: league )
180
+
181
+ club = nil
182
+ if recs.empty?
183
+ ## puts "** !!! WARN !!! no match for club >#{name}<"
184
+ elsif recs.size > 1
185
+ puts "** !!! ERROR - too many matches (#{recs.size}) for club >#{name}<:"
186
+ pp recs
187
+ exit 1
188
+ else # bingo; match - assume size == 1
189
+ club = recs[0]
190
+ end
191
+
192
+ club
193
+ end
194
+
195
+
196
+ #######
197
+ # more support methods
198
+ def build_mods( mods )
199
+ ## e.g.
200
+ ## { 'Arsenal | Arsenal FC' => 'Arsenal, ENG',
201
+ ## 'Liverpool | Liverpool FC' => 'Liverpool, ENG',
202
+ ## 'Barcelona' => 'Barcelona, ESP',
203
+ ## 'Valencia' => 'Valencia, ESP' }
204
+
205
+ mods.reduce({}) do |h,(club_names, club_line)|
206
+
207
+ values = club_line.split( ',' )
208
+ values = values.map { |value| value.strip } ## strip all spaces
209
+
210
+ ## todo/fix: make sure country is present !!!!
211
+ club_name, country_name = values
212
+ club = find_by!( name: club_name, country: country_name )
213
+
214
+ values = club_names.split( '|' )
215
+ values = values.map { |value| value.strip } ## strip all spaces
216
+
217
+ values.each do |club_name|
218
+ h[club_name] = club
219
+ end
220
+ h
221
+ end
222
+ end
223
+ end # class ClubSearch
224
+
225
+
226
+
227
+ ## todo/check - change to EventInfoSearch - why? why not?
228
+ class EventSearch < Search
229
+ ##
230
+ ## todo - eventinfo search still open / up for change
231
+
232
+ ###################
233
+ ## core required delegates - use delegate generator - why? why not?
234
+ def seasons( league )
235
+ @service.seasons( league )
236
+ end
237
+ def find_by( league:, season: )
238
+ @service.find_by( league: league,
239
+ season: season )
240
+ end
241
+ end # class EventSearch
242
+
243
+
244
+ ####
245
+ ## virtual table for season lookup
246
+ ## note - use EventSeaon to avoid name conflict with (global) Season class
247
+ ## find a better name SeasonInfo or SeasonFinder or SeasonStore
248
+ ## or SeasonQ or ??
249
+ class EventSeasonSearch
250
+ def initialize( events: )
251
+ @events = events
252
+ end
253
+
254
+ ###############
255
+ ## todo/fix: find a better algo to guess season for date!!!
256
+ ##
257
+ def find_by( date:, league: )
258
+ date = Date.strptime( date, '%Y-%m-%d' ) if date.is_a?( String )
259
+
260
+ infos = @events.seasons( league )
261
+
262
+ infos.each do |info|
263
+ return info.season if info.include?( date )
264
+ end
265
+ nil
266
+ end
267
+ end # class EventSeasonSearch
268
+
269
+
270
+ ######
271
+ ### add virtual team search ( clubs + national teams)
272
+ ## note: no record base!!!!!
273
+ class TeamSearch
274
+ ## note: "virtual" index lets you search clubs and/or national_teams (don't care)
275
+
276
+ def initialize( clubs:, national_teams: )
277
+ @clubs = clubs
278
+ @national_teams = national_teams
279
+ end
280
+
281
+ ## todo/check: rename to/use map_by! for array version - why? why not?
282
+ def find_by!( name:, league:, mods: nil )
283
+ if name.is_a?( Array )
284
+ recs = []
285
+ name.each do |q|
286
+ recs << _find_by!( name: q, league: league, mods: mods )
287
+ end
288
+ recs
289
+ else ## assume single name
290
+ _find_by!( name: name, league: league, mods: mods )
291
+ end
292
+ end
293
+
294
+
295
+ def _find_by!( name:, league:, mods: nil )
296
+ if mods && mods[ league.key ] && mods[ league.key ][ name ]
297
+ mods[ league.key ][ name ]
298
+ else
299
+ if league.clubs?
300
+ if league.intl? ## todo/fix: add intl? to ActiveRecord league!!!
301
+ @clubs.find!( name )
302
+ else ## assume clubs in domestic/national league tournament
303
+ ## note - search by league countries (may incl. more than one country
304
+ ## e.g. us incl. ca, fr incl. mc, ch incl. li, etc.
305
+ @clubs.find_by!( name: name, league: league )
306
+ end
307
+ else ## assume national teams (not clubs)
308
+ @national_teams.find!( name )
309
+ end
310
+ end
311
+ end # method _find_by!
312
+ end # class TeamSearch
313
+
314
+
315
+
316
+ def initialize( leagues:,
317
+ national_teams:,
318
+ clubs:,
319
+ grounds:,
320
+ events:,
321
+ players:
322
+ )
323
+ @leagues = LeagueSearch.new( leagues )
324
+ @national_teams = NationalTeamSearch.new( national_teams )
325
+ @clubs = ClubSearch.new( clubs )
326
+ @events = EventSearch.new( events )
327
+
328
+ @grounds = GroundSearch.new( grounds )
329
+
330
+ @players = PlayerSearch.new( players )
331
+
332
+ ## virtual deriv ("composite") search services
333
+ @teams = TeamSearch.new( clubs: @clubs,
334
+ national_teams: @national_teams )
335
+ @event_seasons = EventSeasonSearch.new( events: @events )
336
+
337
+ end
338
+
339
+ def countries
340
+ puts
341
+ puts "[WARN] do NOT use catalog.countries, deprecated!!!"
342
+ puts " please, switch to new world.countries search service"
343
+ puts
344
+ exit 1
345
+ end
346
+
347
+ def leagues() @leagues; end
348
+ def national_teams() @national_teams; end
349
+ def clubs() @clubs; end
350
+ def events() @events; end
351
+ def grounds() @grounds; end
352
+
353
+ def players() @players; end
354
+
355
+ def teams() @teams; end ## note - virtual table
356
+ def seasons() @event_seasons; end ## note - virtual table
357
+ end # class SportSearch
@@ -0,0 +1,139 @@
1
+ ###
2
+ # world search service api for countries and more
3
+ #
4
+ # core api is:
5
+ # - world.countries.find_by_code
6
+ # - .find_by_name
7
+
8
+
9
+ class WorldSearch
10
+
11
+ class CitySearch
12
+ def initialize( service ) @service = service; end
13
+
14
+ ###################
15
+ ## core required delegates - use delegate generator - why? why not?
16
+ def match_by( name: )
17
+ @service.match_by( name: name )
18
+ end
19
+ end # class CitySearch
20
+
21
+
22
+ class CountrySearch
23
+ def initialize( service ) @service = service; end
24
+
25
+ ###################
26
+ ## core required delegates - use delegate generator - why? why not?
27
+ def find_by_code( code ) @service.find_by_code( code ); end
28
+ def find_by_name( name ) @service.find_by_name( name ); end
29
+
30
+
31
+ ###############
32
+ ### more deriv support functions / helpers
33
+ def find( q )
34
+ country = find_by_code( q )
35
+ country = find_by_name( q ) if country.nil? ## try lookup / find by (normalized) name
36
+ country
37
+ end
38
+ alias_method :[], :find ### keep shortcut - why? why not?
39
+
40
+ ###
41
+ ## split/parse country line
42
+ ##
43
+ ## split on bullet e.g.
44
+ ## split into name and code with regex - make code optional
45
+ ##
46
+ ## Examples:
47
+ ## Österreich • Austria (at)
48
+ ## Österreich • Austria
49
+ ## Austria
50
+ ## Deutschland (de) • Germany
51
+ ##
52
+ ## todo/check: support more formats - why? why not?
53
+ ## e.g. Austria, AUT (e.g. with comma - why? why not?)
54
+ def parse( line )
55
+ values = line.split( '•' ) ## use/support multi-lingual separator
56
+ country = nil
57
+ values.each do |value|
58
+ value = value.strip
59
+ ## check for trailing country code e.g. (at), (eng), etc.
60
+ if value =~ /[ ]+\((?<code>[a-z]{1,4})\)$/ ## e.g. Austria (at)
61
+ code = $~[:code]
62
+ name = value[0...(value.size-code.size-2)].strip ## note: add -2 for brackets
63
+ candidates = [ find_by_code( code ), find_by_name( name ) ]
64
+ if candidates[0].nil?
65
+ puts "** !!! ERROR !!! country - unknown code >#{code}< in line: #{line}"
66
+ pp line
67
+ exit 1
68
+ end
69
+ if candidates[1].nil?
70
+ puts "** !!! ERROR !!! country - unknown name >#{code}< in line: #{line}"
71
+ pp line
72
+ exit 1
73
+ end
74
+ if candidates[0] != candidates[1]
75
+ puts "** !!! ERROR !!! country - name and code do NOT match the same country:"
76
+ pp line
77
+ pp candidates
78
+ exit 1
79
+ end
80
+ if country && country != candidates[0]
81
+ puts "** !!! ERROR !!! country - names do NOT match the same country:"
82
+ pp line
83
+ pp country
84
+ pp candidates
85
+ exit 1
86
+ end
87
+ country = candidates[0]
88
+ else
89
+ ## just assume value is name or code
90
+ candidate = find( value )
91
+ if candidate.nil?
92
+ puts "** !!! ERROR !!! country - unknown name or code >#{value}< in line: #{line}"
93
+ pp line
94
+ exit 1
95
+ end
96
+ if country && country != candidate
97
+ puts "** !!! ERROR !!! country - names do NOT match the same country:"
98
+ pp line
99
+ pp country
100
+ pp candidate
101
+ exit 1
102
+ end
103
+ country = candidate
104
+ end
105
+ end
106
+ country
107
+ end # method parse
108
+ end # class CountrySearch
109
+
110
+
111
+ def initialize( countries:, cities: )
112
+ ## change service to country_service or such - why? why not?
113
+ ## add city_service and such later
114
+ @countries = CountrySearch.new( countries )
115
+ @cities = CitySearch.new( cities )
116
+ end
117
+
118
+ ####
119
+ # note: for now setup only for countries
120
+ def countries() @countries; end
121
+ def cities() @cities; end
122
+ end # class WorldSearch
123
+
124
+
125
+
126
+
127
+
128
+ class DummyCountrySearch
129
+ def find_by_code( code )
130
+ puts "[WARN] no world search configured; cannot find country by code"
131
+ nil
132
+ end
133
+ def find_by_name( name )
134
+ puts "[WARN] no world search configured; cannot find country by name"
135
+ nil
136
+ end
137
+ end # class DummyCountrySearch
138
+
139
+