lib/sportdb/rsssf_reader.rb in sportdb-models-1.15.0 vs lib/sportdb/rsssf_reader.rb in sportdb-models-1.15.1

- old
+ new

@@ -1,72 +1,127 @@ # encoding: UTF-8 ## -# -# todo/fix: cleanup, remove stuff not needed for "simple" rsssf format/style -# -## for now lets only support leagues with rounds (no cups/knockout rounds n groups) +## note: for now lets only support leagues with rounds (no cups/knockout rounds n groups) ## (re)add later when needed (e.g. for playoffs etc.) module SportDb -class RsssfGameReader +class RsssfGameReader ### todo: rename to RsssfLeagueMatchReader ( or use league/cup option?) - why? why not?? include LogUtils::Logging ## make models available by default with namespace # e.g. lets you use Usage instead of Model::Usage include Models -## value helpers e.g. is_year?, is_taglist? etc. - include TextUtils::ValueHelper - - include FixtureHelpers - ## ## todo: add from_file and from_zip too - def self.from_string( event_key, text ) - ### fix - fix -fix: - ## change event to event_or_event_key !!!!! - allow event_key as string passed in - self.new( event_key, text ) + def self.from_string( event_or_event_key, text ) + self.new( event_or_event_key, text ) end - def initialize( event_key, text ) - ### fix - fix -fix: - ## change event to event_or_event_key !!!!! - allow event_key as string passed in - + def initialize( event_or_event_key, text ) ## todo/fix: how to add opts={} ??? - @event_key = event_key - @text = text + @event_or_event_key = event_or_event_key + @text = text end def read ## note: assume active activerecord connection - @event = Event.find_by!( key: @event_key ) + + if @event_or_event_key.kind_of?( Event ) + @event= @event_or_event_key + else ## assume string + @event = Event.find_by!( key: @event_or_event_key ) + end logger.debug "Event #{@event.key} >#{@event.title}<" - @team_mapper = TextUtils::TitleMapper.new( @event.teams, 'team' ) + @mapper_teams = TeamMapper.new( @event.teams ) ## reset cached values @patch_round_ids = [] @last_round = nil @last_date = nil - ## always use english (en) for now - SportDb.lang.lang = 'en' - reader = LineReader.from_string( @text ) parse_fixtures( reader ) end # method load_fixtures + + RSSSF_FT_REGEX = /\b + (?<score1>\d{1,2}) + - + (?<score2>\d{1,2}) + \b/x + + def find_rsssf_scores!( line ) + # e.g. 1-1 or 0-2 or 3-3 + + m = RSSSF_FT_REGEX.match( line ) + if m + score1 = m[:score1].to_i + score2 = m[:score2].to_i + + logger.debug " score: >#{score1}-#{score2}<" + + line.sub!( m[0], '[SCORE]' ) + else + score1 = nil + score2 = nil + end + + scores = [score1, score2] + scores + end # method find_rsssf_scores! + + + def find_rsssf_date!( line, opts={} ) + finder = RsssfDateFinder.new + finder.find!( line, opts ) + end + + + RSSSF_ROUND_REGEX = /\b + (?<round>Round) + \s + (?<pos>\d{1,3}) + \b/x + + def is_rsssf_round?( line ) + RSSSF_ROUND_REGEX.match( line ).nil? == false ## match found if not nil + end + + def find_rsssf_round!( line ) + ## todo: check if \b works for run on [Apr 13] too ?? + ## todo: allow multiple spaces after round ?? + + m = RSSSF_ROUND_REGEX.match( line ) + if m + title = m[0] ## note: title is complete match e.g. Round 1, Round 2, etc. + pos = m[:pos].to_i + + logger.debug " title: >#{title}<, pos: >#{pos}<" + + line.sub!( m[0], '[ROUND]' ) + else + ## fix: add logger.warn no round pos found in line + title = nil + pos = nil + end + + [title,pos] ## return array; note: [nil,nil] if nothing found + end # method find_rsssf_round! + + def parse_round_header( line ) ## todo/fix: ## simplify - for now round number always required # e.g. no auto-calculation supported here @@ -74,36 +129,25 @@ # # also remove knockout flag for now (set to always false for now) logger.debug "parsing round header line: >#{line}<" - ### todo/fix/check: move cut off optional comment in reader for all lines? why? why not? - cut_off_end_of_line_comment!( line ) # cut off optional comment starting w/ # - ## check for date in header first e.g. Round 36 [Jul 20] !! ## avoid "conflict" with getting "wrong" round number from date etc. date = find_rsssf_date!( line, start_at: @event.start_at ) if date @last_date = date end - ## todo/check/fix: - # make sure Round of 16 will not return pos 16 -- how? possible? - # add unit test too to verify - pos = find_round_pos!( line ) + title, pos = find_rsssf_round!( line ) ## check if pos available; if not auto-number/calculate if pos.nil? logger.error( " no round pos found in line >#{line}<; round pos required in rsssf; sorry" ) fail( "round pos required in rsssf; sorry") end - title = find_round_header_title!( line ) - - ## Note: use extracted round title for knockout check - ## knockout_flag = is_knockout_round?( title ) - logger.debug " line: >#{line}<" ## Note: dummy/placeholder start_at, end_at date ## replace/patch after adding all games for round @@ -123,10 +167,11 @@ round = Round.new round_attribs = round_attribs.merge( { event_id: @event.id, pos: pos, + ## todo: add num e.g. num == pos for round 1, round 2, etc. - why? why not?? start_at: Date.parse('1911-11-11'), end_at: Date.parse('1911-11-11') }) end @@ -147,13 +192,14 @@ end def parse_game( line ) logger.debug "parsing game (fixture) line: >#{line}<" - @team_mapper.map_titles!( line ) - team1_key = @team_mapper.find_key!( line ) - team2_key = @team_mapper.find_key!( line ) + @mapper_teams.map_teams!( line ) + team_keys = @mapper_teams.find_teams!( line ) + team1_key = team_keys[0] + team2_key = team_keys[1] ## note: if we do NOT find two teams; return false - no match found if team1_key.nil? || team2_key.nil? logger.debug " no game match (two teams required) found for line: >#{line}<" return false @@ -168,13 +214,11 @@ @last_date = date # keep a reference for later use else date = @last_date # no date found; (re)use last seen date end - ## fix/todo: use find_rsssf_scores!( line ) - ## use rsssf specific score finder!!! - scores = find_scores!( line ) + scores = find_rsssf_scores!( line ) logger.debug " line: >#{line}<" ### todo: cache team lookups in hash? @@ -183,10 +227,13 @@ round = @last_round ### check if games exists ## with this teams in this round if yes only update + ## + ## todo: add replay flag (true/false) !!!!!!!! + ## allows same match fixture in round !!!!!!!! game = Game.find_by( round_id: round.id, team1_id: team1.id, team2_id: team2.id ) game_attribs = { @@ -238,13 +285,14 @@ # note: returns true if parsed, false if no match # line with NO teams plus include date e.g. # [Jun 17] etc. - @team_mapper.map_titles!( line ) - team1_key = @team_mapper.find_key!( line ) - team2_key = @team_mapper.find_key!( line ) + @mapper_teams.map_teams!( line ) + team_keys= @mapper_teams.find_teams!( line ) + team1_key = team_keys[0] + team2_key = team_keys[1] date = find_rsssf_date!( line, start_at: @event.start_at ) if date && team1_key.nil? && team2_key.nil? logger.debug( "date header line found: >#{line}<") @@ -261,11 +309,10 @@ def parse_fixtures( reader ) reader.each_line do |line| - ## fix: use inline/simpler is_rsssf_round? - if is_round?( line ) + if is_rsssf_round?( line ) parse_round_header( line ) elsif try_parse_game( line ) # do nothing here elsif try_parse_date_header( line ) # do nothing here