sportdb-readers 0.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f26c8211ce5ab383f35775134f230cbc22d71112
4
+ data.tar.gz: 7bfb83d1e338e101578fdd4487e3fa35c7f13580
5
+ SHA512:
6
+ metadata.gz: cee60d57c7f687397f0daa0333cdd6eaeee924141215b57ecc89691d3ae6daf5b40bf6f4aca4d65cf713613732e2ccafd7c9cd0256564b58e3d516241b495a14
7
+ data.tar.gz: fc4dcbc250a5d56b31bdbe6f82b78073e45ec1df499554861cc623695deb752ce94fe1934fe4b69b47b2245e44a6baeafb07b2eb9de0f2134317cac1eccb15d6
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ ### 0.0.1 / 2019-10-29
2
+
3
+ * Everything is new. First release.
data/Manifest.txt ADDED
@@ -0,0 +1,14 @@
1
+ CHANGELOG.md
2
+ Manifest.txt
3
+ README.md
4
+ Rakefile
5
+ lib/sportdb/readers.rb
6
+ lib/sportdb/readers/event_reader.rb
7
+ lib/sportdb/readers/match_parser.rb
8
+ lib/sportdb/readers/match_reader.rb
9
+ lib/sportdb/readers/outline_reader.rb
10
+ lib/sportdb/readers/sync.rb
11
+ lib/sportdb/readers/version.rb
12
+ test/helper.rb
13
+ test/test_match_parser.rb
14
+ test/test_reader.rb
data/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # sportdb-readers - sport.db readers
2
+
3
+
4
+ * home :: [github.com/sportdb/sport.db](https://github.com/sportdb/sport.db)
5
+ * bugs :: [github.com/sportdb/sport.db/issues](https://github.com/sportdb/sport.db/issues)
6
+ * gem :: [rubygems.org/gems/sportdb-readers](https://rubygems.org/gems/sportdb-readers)
7
+ * rdoc :: [rubydoc.info/gems/sportdb-readers](http://rubydoc.info/gems/sportdb-readers)
8
+ * forum :: [opensport](http://groups.google.com/group/opensport)
9
+
10
+
11
+
12
+ ## Usage
13
+
14
+ To be done
15
+
16
+ ## License
17
+
18
+ The `sportdb-readers` scripts are dedicated to the public domain.
19
+ Use it as you please with no restrictions whatsoever.
20
+
21
+
22
+ ## Questions? Comments?
23
+
24
+ Send them along to the
25
+ [Open Sports & Friends Forum/Mailing List](http://groups.google.com/group/opensport).
26
+ Thanks!
data/Rakefile ADDED
@@ -0,0 +1,31 @@
1
+ require 'hoe'
2
+ require './lib/sportdb/readers/version.rb'
3
+
4
+ Hoe.spec 'sportdb-readers' do
5
+
6
+ self.version = SportDb::Readers::VERSION
7
+
8
+ self.summary = "sportdb-readers - sport.db readers"
9
+ self.description = summary
10
+
11
+ self.urls = ['https://github.com/sportdb/sport.db']
12
+
13
+ self.author = 'Gerald Bauer'
14
+ self.email = 'opensport@googlegroups.com'
15
+
16
+ # switch extension to .markdown for gihub formatting
17
+ self.readme_file = 'README.md'
18
+ self.history_file = 'CHANGELOG.md'
19
+
20
+ self.licenses = ['Public Domain']
21
+
22
+ self.extra_deps = [
23
+ ['sportdb-config', '>= 0.8.1'],
24
+ ['sportdb-models', '>= 1.18.0'],
25
+ ]
26
+
27
+ self.spec_extras = {
28
+ required_ruby_version: '>= 2.2.2'
29
+ }
30
+
31
+ end
@@ -0,0 +1,22 @@
1
+ # encoding: UTF-8
2
+
3
+
4
+ require 'sportdb/config'
5
+ require 'sportdb/models' ## add sql database support
6
+
7
+
8
+
9
+ ###
10
+ # our own code
11
+ require 'sportdb/readers/version' # let version always go first
12
+ require 'sportdb/readers/sync'
13
+ require 'sportdb/readers/outline_reader'
14
+ require 'sportdb/readers/event_reader'
15
+ require 'sportdb/readers/match_parser'
16
+ require 'sportdb/readers/match_reader'
17
+
18
+
19
+
20
+
21
+
22
+ puts SportDb::Readers.banner # say hello
@@ -0,0 +1,104 @@
1
+ # encoding: utf-8
2
+
3
+ module SportDb
4
+
5
+
6
+ class EventReaderV2 ## todo/check: rename to EventsReaderV2 (use plural?) why? why not?
7
+
8
+ def self.read( path ) ## use - rename to read_file or from_file etc. - why? why not?
9
+ txt = File.open( path, 'r:utf-8' ).read
10
+ parse( txt )
11
+ end
12
+
13
+ def self.parse( txt )
14
+ recs = LeagueOutlineReader.parse( txt )
15
+ pp recs
16
+
17
+ ## pass 2 - check & map; replace inline (string with record)
18
+ recs.each do |rec|
19
+ league = rec[:league]
20
+ clubs = [] ## convert lines to clubs
21
+ rec[:lines].each do |line|
22
+
23
+ next if line =~ /^[ -]+$/ ## skip decorative lines with dash only (e.g. ---- or - - - -) etc.
24
+
25
+ scan = StringScanner.new( line )
26
+
27
+ if scan.check( /\d{1,2}[ ]+/ ) ## entry with standaning starts with ranking e.g. 1,2,3, etc.
28
+ puts " table entry >#{line}<"
29
+ rank = scan.scan( /\d{1,2}[ ]+/ ).strip # note: strip trailing spaces
30
+
31
+ ## note: uses look ahead scan until we hit at least two spaces
32
+ ## or the end of string (standing records for now optional)
33
+ name = scan.scan_until( /(?=\s{2})|$/ )
34
+ if scan.eos?
35
+ standing = nil
36
+ else
37
+ standing = scan.rest.strip # note: strip leading and trailing spaces
38
+ end
39
+ puts " rank: >#{rank}<, name: >#{name}<, standing: >#{standing}<"
40
+
41
+ ## note: rank and standing gets ignored (not used) for now
42
+ else
43
+ ## assume club is full line
44
+ name = line
45
+ end
46
+
47
+ clubs << find_club( name, league.country )
48
+ end
49
+
50
+ rec[:clubs] = clubs
51
+ rec.delete( :lines ) ## remove lines entry
52
+ end
53
+
54
+ ## pass 3 - import (insert/update) into db
55
+ recs.each do |rec|
56
+ league = Sync::League.find_or_create( rec[:league] )
57
+ season = Sync::Season.find_or_create( rec[:season] )
58
+
59
+ event = Sync::Event.find_or_create( league: league, season: season )
60
+
61
+ rec[:clubs].each do |club_rec|
62
+ club = Sync::Club.find_or_create( club_rec )
63
+ ## add teams to event
64
+ ## todo/fix: check if team is alreay included?
65
+ ## or clear/destroy_all first!!!
66
+ event.teams << club
67
+ end
68
+ end
69
+
70
+ recs
71
+ end # method read
72
+
73
+
74
+
75
+ def self.find_club( name, country ) ## todo/fix: add international or league flag?
76
+ club = nil
77
+ m = CLUBS.match_by( name: name, country: country )
78
+
79
+ if m.nil?
80
+ ## (re)try with second country - quick hacks for known leagues
81
+ ## todo/fix: add league flag to activate!!!
82
+ m = CLUBS.match_by( name: name, country: COUNTRIES['wal']) if country.key == 'eng'
83
+ m = CLUBS.match_by( name: name, country: COUNTRIES['nir']) if country.key == 'ie'
84
+ m = CLUBS.match_by( name: name, country: COUNTRIES['mc']) if country.key == 'fr'
85
+ m = CLUBS.match_by( name: name, country: COUNTRIES['li']) if country.key == 'ch'
86
+ m = CLUBS.match_by( name: name, country: COUNTRIES['ca']) if country.key == 'us'
87
+ end
88
+
89
+ if m.nil?
90
+ puts "** !!! ERROR !!! no match for club >#{name}<"
91
+ exit 1
92
+ elsif m.size > 1
93
+ puts "** !!! ERROR !!! too many matches (#{m.size}) for club >#{name}<:"
94
+ pp m
95
+ exit 1
96
+ else # bingo; match - assume size == 1
97
+ club = m[0]
98
+ end
99
+
100
+ club
101
+ end
102
+
103
+ end # class EventReaderV2
104
+ end # module SportDb
@@ -0,0 +1,466 @@
1
+ # encoding: utf-8
2
+
3
+ module SportDb
4
+
5
+ class MatchParserSimpleV2 ## simple match parser for club match schedules
6
+ include LogUtils::Logging
7
+
8
+ def initialize( lines, teams, start_at )
9
+ @lines = lines ## todo/check: change to text instead of array of lines - why? why not?
10
+ @mapper_teams = TeamMapper.new( teams )
11
+ @start_at = start_at
12
+
13
+ ## build lookup hash by (team) key
14
+ @teams = teams.reduce({}) { |h,team| h[team.key]=team; h }
15
+
16
+ ## debug_dump_teams( teams )
17
+ ## exit 1
18
+ end
19
+
20
+ def debug_dump_teams( teams )
21
+ puts "== #{teams.size} teams"
22
+ teams.each do |team|
23
+ print "#{team.key}, "
24
+ print "#{team.title}, "
25
+ print "#{team.synonyms.split('|').join(', ')}"
26
+ puts
27
+ end
28
+ end
29
+
30
+
31
+
32
+ Round = Struct.new( :pos, :title )
33
+ ##
34
+ ## todo: change db schema
35
+ ## make start and end date optional
36
+ ## change pos to num - why? why not?
37
+ ## make pos/num optional too
38
+ ##
39
+ ## sort round by scheduled/planed start date
40
+ Match = Struct.new( :date,
41
+ :team1, :team2, ## todo/fix: use team1_name, team2_name or similar - for compat with db activerecord version? why? why not?
42
+ :score1i, :score2i, ## half time (first (i) part)
43
+ :score1, :score2, ## full time
44
+ :round )
45
+
46
+ def parse
47
+ @last_date = nil
48
+ @last_round = nil
49
+ @rounds = {}
50
+ @matches = []
51
+
52
+
53
+ @lines.each do |line|
54
+ if is_round?( line )
55
+ parse_round_header( line )
56
+ elsif try_parse_game( line )
57
+ # do nothing here
58
+ elsif try_parse_date_header( line )
59
+ # do nothing here
60
+ else
61
+ logger.info "skipping line (no match found): >#{line}<"
62
+ end
63
+ end # lines.each
64
+
65
+ [@rounds.values, @matches]
66
+ end # method parse
67
+
68
+
69
+ def is_round?( line )
70
+ ## note: =~ return nil if not match found, and 0,1, etc for match
71
+ (line =~ SportDb.lang.regex_round) != nil
72
+ end
73
+
74
+
75
+ def find_round_pos!( line )
76
+ # pass #1) extract optional round pos from line
77
+ # e.g. (1) - must start line
78
+ regex_pos = /^[ \t]*\((\d{1,3})\)[ \t]+/
79
+
80
+ # pass #2) find free standing number e.g. Matchday 3 or Round 5 or 3. Spieltag etc.
81
+ # note: /\b(\d{1,3})\b/
82
+ # will match -12
83
+ # thus, use space required - will NOT match -2 e.g. Group-2 Play-off
84
+ # note: allow 1. Runde n
85
+ # 1^ Giornata
86
+ regex_num = /(?:^|\s)(\d{1,3})(?:[.\^\s]|$)/
87
+
88
+ if line =~ regex_pos
89
+ logger.debug " pos: >#{$1}<"
90
+
91
+ line.sub!( regex_pos, '[ROUND.POS] ' ) ## NB: add back trailing space that got swallowed w/ regex -> [ \t]+
92
+ return $1.to_i
93
+ elsif line =~ regex_num
94
+ ## assume number in title is pos (e.g. Jornada 3, 3 Runde etc.)
95
+ ## NB: do NOT remove pos from string (will get removed by round title)
96
+
97
+ num = $1.to_i # note: clone capture; keep a copy (another regex follows; will redefine $1)
98
+
99
+ #### fix:
100
+ # use/make keywords required
101
+ # e.g. Round of 16 -> should NOT match 16!
102
+ # Spiel um Platz 3 (or 5) etc -> should NOT match 3!
103
+ # Round 16 - ok
104
+ # thus, check for required keywords
105
+
106
+ ## quick hack for round of 16
107
+ # todo: mask match e.g. Round of xxx ... and try again - might include something
108
+ # reuse pattern for Group XX Replays for example
109
+ if line =~ /^\s*Round of \d{1,3}\b/
110
+ return nil
111
+ end
112
+
113
+ logger.debug " pos: >#{num}<"
114
+ return num
115
+ else
116
+ ## fix: add logger.warn no round pos found in line
117
+ return nil
118
+ end
119
+ end # method find_round_pos!
120
+
121
+ def find_round_header_title!( line )
122
+ # assume everything left is the round title
123
+ # extract all other items first (round title2, round pos, group title n pos, etc.)
124
+
125
+ ## todo/fix:
126
+ ## cleanup method
127
+ ## use buf.index( '//' ) to split string (see found_round_def)
128
+ ## why? simpler why not?
129
+ ## - do we currently allow groups if title2 present? add example if it works?
130
+
131
+ buf = line.dup
132
+ logger.debug " find_round_header_title! line-before: >>#{buf}<<"
133
+
134
+ buf.gsub!( /\[[^\]]+\]/, '' ) # e.g. remove [ROUND.POS], [ROUND.TITLE2], [GROUP.TITLE+POS] etc.
135
+ buf.strip! # remove leading and trailing whitespace
136
+
137
+ logger.debug " find_round_title! line-after: >>#{buf}<<"
138
+
139
+ ### bingo - assume what's left is the round title
140
+
141
+ logger.debug " title: >>#{buf}<<"
142
+ line.sub!( buf, '[ROUND.TITLE]' )
143
+
144
+ buf
145
+ end
146
+
147
+ def parse_round_header( line )
148
+ logger.debug "parsing round header line: >#{line}<"
149
+
150
+ ## todo/check/fix:
151
+ # make sure Round of 16 will not return pos 16 -- how? possible?
152
+ # add unit test too to verify
153
+ pos = find_round_pos!( line )
154
+
155
+ title = find_round_header_title!( line )
156
+
157
+ logger.debug " line: >#{line}<"
158
+
159
+
160
+ round = @rounds[ title ]
161
+ if round.nil?
162
+ round = Round.new( pos, title )
163
+ @rounds[ title ] = round
164
+ end
165
+ ## todo/check: if pos match (MUST always match for now)
166
+ @last_round = round
167
+
168
+
169
+ ## NB: dummy/placeholder start_at, end_at date
170
+ ## replace/patch after adding all games for round
171
+
172
+ =begin
173
+ round_attribs = {
174
+ title: title,
175
+ title2: title2,
176
+ knockout: knockout_flag
177
+ }
178
+
179
+ if pos > 999000
180
+ # no pos (e.g. will get autonumbered later) - try match by title for now
181
+ # e.g. lets us use title 'Group Replays', for example, multiple times
182
+ @round = Round.find_by_event_id_and_title( @event.id, title )
183
+ else
184
+ @round = Round.find_by_event_id_and_pos( @event.id, pos )
185
+ end
186
+
187
+ if @round.present?
188
+ logger.debug "update round #{@round.id}:"
189
+ else
190
+ logger.debug "create round:"
191
+ @round = Round.new
192
+
193
+ round_attribs = round_attribs.merge( {
194
+ event_id: @event.id,
195
+ pos: pos,
196
+ start_at: Date.parse('1911-11-11'),
197
+ end_at: Date.parse('1911-11-11')
198
+ })
199
+ end
200
+
201
+ logger.debug round_attribs.to_json
202
+
203
+ @round.update_attributes!( round_attribs )
204
+
205
+ @patch_round_ids_pos << @round.id if pos > 999000
206
+ ### store list of round ids for patching start_at/end_at at the end
207
+ @patch_round_ids_dates << @round.id # todo/fix/check: check if round has definition (do NOT patch if definition (not auto-added) present)
208
+ =end
209
+ end
210
+
211
+
212
+ def find_scores!( line, opts={} )
213
+ # note: always call after find_dates !!!
214
+ # scores match date-like patterns!! e.g. 10-11 or 10:00 etc.
215
+ # -- note: score might have two digits too
216
+
217
+ finder = ScoresFinder.new
218
+ finder.find!( line, opts )
219
+ end
220
+
221
+ def try_parse_game( line )
222
+ # note: clone line; for possible test do NOT modify in place for now
223
+ # note: returns true if parsed, false if no match
224
+ parse_game( line.dup )
225
+ end
226
+
227
+
228
+ def parse_game( line )
229
+ logger.debug "parsing game (fixture) line: >#{line}<"
230
+
231
+ @mapper_teams.map_teams!( line ) ### todo/fix: limit mapping to two(2) teams - why? why not? might avoid matching @ Barcelona ??
232
+ team_keys = @mapper_teams.find_teams!( line )
233
+ team1_key = team_keys[0]
234
+ team2_key = team_keys[1]
235
+
236
+ ## note: if we do NOT find two teams; return false - no match found
237
+ if team1_key.nil? || team2_key.nil?
238
+ logger.debug " no game match (two teams required) found for line: >#{line}<"
239
+ return false
240
+ end
241
+
242
+ ## pos = find_game_pos!( line )
243
+
244
+ date = find_date!( line, start_at: @start_at )
245
+
246
+ ###
247
+ # check if date found?
248
+ # NB: ruby falsey is nil & false only (not 0 or empty array etc.)
249
+ if date
250
+ ### check: use date_v2 if present? why? why not?
251
+ @last_date = date # keep a reference for later use
252
+ else
253
+ date = @last_date # no date found; (re)use last seen date
254
+ end
255
+
256
+
257
+ scores = find_scores!( line )
258
+
259
+ logger.debug " line: >#{line}<"
260
+
261
+
262
+ ## todo/check: scores are integers or strings?
263
+ @matches << Match.new( date,
264
+ @teams[ team1_key ],
265
+ @teams[ team2_key ],
266
+ scores[0], ## score1i - half time (first (i) part)
267
+ scores[1], ## score2i
268
+ scores[2], ## score1 - full time
269
+ scores[3], ## score2
270
+ @last_round )
271
+
272
+ ### todo: cache team lookups in hash?
273
+
274
+ =begin
275
+ team1 = Team.find_by_key!( team1_key )
276
+ team2 = Team.find_by_key!( team2_key )
277
+
278
+ @last_team1 = team1 # store for later use for goals etc.
279
+ @last_team2 = team2
280
+
281
+
282
+ if @round.nil?
283
+ ## no round header found; calculate round from date
284
+
285
+ ###
286
+ ## todo/fix: add some unit tests for round look up
287
+ # fix: use date_v2 if present!! (old/original date; otherwise use date)
288
+
289
+ #
290
+ # fix: check - what to do with hours e.g. start_at use 00:00 and for end_at use 23.59 ??
291
+ # -- for now - remove hours (e.g. use end_of_day and beginnig_of_day)
292
+
293
+ ##
294
+ # note: start_at and end_at are dates ONLY (note datetime)
295
+ # - do NOT pass in hours etc. in query
296
+ # again use --> date.end_of_day, date.beginning_of_day
297
+ # new: not working: date.to_date, date.to_date
298
+ # will not find round if start_at same as date !! (in theory hours do not matter)
299
+
300
+ ###
301
+ # hack:
302
+ # special case for sqlite3 (date compare not working reliable; use casts)
303
+ # fix: move to adapter_name to activerecord_utils as sqlite? or similar?
304
+
305
+ if ActiveRecord::Base.connection.adapter_name.downcase.starts_with?( 'sqlite' )
306
+ logger.debug( " [sqlite] using sqlite-specific query for date compare for rounds finder" )
307
+ round = Round.where( 'event_id = ? AND ( julianday(start_at) <= julianday(?)'+
308
+ 'AND julianday(end_at) >= julianday(?))',
309
+ @event.id, date.to_date, date.to_date).first
310
+ else # all other dbs (postgresql, mysql, etc.)
311
+ round = Round.where( 'event_id = ? AND (start_at <= ? AND end_at >= ?)',
312
+ @event.id, date.to_date, date.to_date).first
313
+ end
314
+
315
+ pp round
316
+ if round.nil?
317
+ logger.warn( " !!!! no round match found for date #{date}" )
318
+ pp Round.all
319
+
320
+ ###################################
321
+ # -- try auto-adding matchday
322
+ round = Round.new
323
+
324
+ round_attribs = {
325
+ event_id: @event.id,
326
+ title: "Matchday #{date.to_date}",
327
+ pos: 999001+@patch_round_ids_pos.length, # e.g. 999<count> - 999001,999002,etc.
328
+ start_at: date.to_date,
329
+ end_at: date.to_date
330
+ }
331
+
332
+ logger.info( " auto-add round >Matchday #{date.to_date}<" )
333
+ logger.debug round_attribs.to_json
334
+
335
+ round.update_attributes!( round_attribs )
336
+
337
+ @patch_round_ids_pos << round.id # todo/check - add just id or "full" record as now - why? why not?
338
+ end
339
+
340
+ # store pos for auto-number next round if missing
341
+ # - note: only if greater/bigger than last; use max
342
+ # - note: last_round_pos might be nil - thus set to 0
343
+ if round.pos > 999000
344
+ # note: do NOT update last_round_pos for to-be-patched rounds
345
+ else
346
+ @last_round_pos = [round.pos,@last_round_pos||0].max
347
+ end
348
+
349
+ ## note: will crash (round.pos) if round is nil
350
+ logger.debug( " using round #{round.pos} >#{round.title}< start_at: #{round.start_at}, end_at: #{round.end_at}" )
351
+ else
352
+ ## use round from last round header
353
+ round = @round
354
+ end
355
+
356
+
357
+ ### check if games exists
358
+ ## with this teams in this round if yes only update
359
+ game = Game.find_by_round_id_and_team1_id_and_team2_id(
360
+ round.id, team1.id, team2.id
361
+ )
362
+
363
+ game_attribs = {
364
+ score1i: scores[0],
365
+ score2i: scores[1],
366
+ score1: scores[2],
367
+ score2: scores[3],
368
+ score1et: scores[4],
369
+ score2et: scores[5],
370
+ score1p: scores[6],
371
+ score2p: scores[7],
372
+ play_at: date,
373
+ play_at_v2: date_v2,
374
+ postponed: postponed,
375
+ knockout: round.knockout, ## note: for now always use knockout flag from round - why? why not??
376
+ ground_id: ground.present? ? ground.id : nil,
377
+ group_id: @group.present? ? @group.id : nil
378
+ }
379
+
380
+ game_attribs[ :pos ] = pos if pos.present?
381
+
382
+ ####
383
+ # note: only update if any changes (or create if new record)
384
+ if game.present? &&
385
+ game.check_for_changes( game_attribs ) == false
386
+ logger.debug " skip update game #{game.id}; no changes found"
387
+ else
388
+ if game.present?
389
+ logger.debug "update game #{game.id}:"
390
+ else
391
+ logger.debug "create game:"
392
+ game = Game.new
393
+
394
+ more_game_attribs = {
395
+ round_id: round.id,
396
+ team1_id: team1.id,
397
+ team2_id: team2.id
398
+ }
399
+
400
+ ## NB: use round.games.count for pos
401
+ ## lets us add games out of order if later needed
402
+ more_game_attribs[ :pos ] = round.games.count+1 if pos.nil?
403
+
404
+ game_attribs = game_attribs.merge( more_game_attribs )
405
+ end
406
+
407
+ logger.debug game_attribs.to_json
408
+ game.update_attributes!( game_attribs )
409
+ end
410
+
411
+ @last_game = game # store for later reference (e.g. used for goals etc.)
412
+ =end
413
+
414
+ return true # game match found
415
+ end # method parse_game
416
+
417
+
418
+
419
+ def try_parse_date_header( line )
420
+ # note: clone line; for possible test do NOT modify in place for now
421
+ # note: returns true if parsed, false if no match
422
+ parse_date_header( line.dup )
423
+ end
424
+
425
+ def find_date!( line, opts={} )
426
+ ## NB: lets us pass in start_at/end_at date (for event)
427
+ # for auto-complete year
428
+
429
+ # extract date from line
430
+ # and return it
431
+ # NB: side effect - removes date from line string
432
+
433
+ finder = DateFinder.new
434
+ finder.find!( line, opts )
435
+ end
436
+
437
+ def parse_date_header( line )
438
+ # note: returns true if parsed, false if no match
439
+
440
+ # line with NO teams plus include date e.g.
441
+ # [Fri Jun/17] or
442
+ # Jun/17 or
443
+ # Jun/17: etc.
444
+
445
+ @mapper_teams.map_teams!( line )
446
+ team_keys = @mapper_teams.find_teams!( line )
447
+ team1_key = team_keys[0]
448
+ team2_key = team_keys[1]
449
+
450
+ date = find_date!( line, start_at: @start_at )
451
+
452
+ if date && team1_key.nil? && team2_key.nil?
453
+ logger.debug( "date header line found: >#{line}<")
454
+ logger.debug( " date: #{date}")
455
+
456
+ @last_date = date # keep a reference for later use
457
+ return true
458
+ else
459
+ return false
460
+ end
461
+ end
462
+
463
+
464
+
465
+ end # class MatchParserSimpleV2
466
+ end # module SportDb