Class: SportDb::MatchTree

Inherits:
Object
  • Object
show all
Includes:
LogUtils::Logging
Defined in:
lib/sportdb/quick/match_tree.rb,
lib/sportdb/quick/match_tree/goal.rb,
lib/sportdb/quick/match_tree/group.rb,
lib/sportdb/quick/match_tree/match.rb,
lib/sportdb/quick/match_tree/round.rb,
lib/sportdb/quick/match_tree-helpers.rb,
lib/sportdb/quick/match_tree_on/on_goal_line.rb,
lib/sportdb/quick/match_tree_on/on_group_def.rb,
lib/sportdb/quick/match_tree_on/on_round_def.rb,
lib/sportdb/quick/match_tree_on/on_match_line.rb,
lib/sportdb/quick/match_tree_on/on_date_header.rb,
lib/sportdb/quick/match_tree_on/on_round_outline.rb

Overview

simple (match) parse tree to structs walker/handler/converter

Defined Under Namespace

Classes: Goal, Group, Match, Round

Constant Summary collapse

GROUP_RE =

note - do NOT match group phase or group playoff or such

for now only works for group a,b,c or group 1, group 2, etc.
%r{\A
      Group [ ] (?:
                     [a-z]
                   | \d+
                 )
\z}ix

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(tree, start: nil) ⇒ MatchTree

note: allow start(_date) nil

if in use (start: nil) years expected on first date!!!


19
20
21
22
23
24
# File 'lib/sportdb/quick/match_tree.rb', line 19

def initialize( tree, start: nil )
  @tree    = tree
  @start   = start

  @errors = []
end

Instance Attribute Details

#errorsObject (readonly)

Returns the value of attribute errors.



26
27
28
# File 'lib/sportdb/quick/match_tree.rb', line 26

def errors
  @errors
end

Class Method Details

.debug=(value) ⇒ Object



7
# File 'lib/sportdb/quick/match_tree.rb', line 7

def self.debug=(value) @@debug = value; end

.debug?Boolean

note: default is FALSE

Returns:

  • (Boolean)


8
# File 'lib/sportdb/quick/match_tree.rb', line 8

def self.debug?() @@debug ||= false; end

Instance Method Details

#_build_date(m:, d:, y:, yy:, wday:, start:, last_year:) ⇒ Object

check - rename last_year to running_last_year to make intent clearer - why? why not?



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/sportdb/quick/match_tree-helpers.rb', line 16

def _build_date( m:, d:, y:, yy:, wday:,
                  start:,
                  last_year: )

  if m.nil? || d.nil?
    puts "[debug] !! ERROR - _build_date required month or day missing:"
    pp [m,d,y,yy,wday,start]
    exit 1
  end


 ## quick debug hack
 if m == 2 && d == 29
    puts "quick check  feb/29 dates"
    pp [d,m,y]
    pp start
 end


  ####
  ## support two digit shortcut for year
  if yy
    ###
    ## for now assume 00,01 to 30 is 2000,2001 to 2030
    ##   and          31 to 99   is  1931 to 1999
    y =   yy <= 30 ?  2000+yy : 1900+yy
  end


  if y.nil?   ## try to calculate year
    if last_year && @last_year   ## use new formula
       y = @last_year
    elsif start.nil?
       puts "!! ERROR - _build_date - year expected for (first) date; cannot infer/guess; sorry"
       exit 1
    else  ## fallback to "old" formula - FIX/FIX remove later
       ## puts "[deprecated] WARN - do NOT use old year (date) auto-complete; add year to first date"
       y =  if  m > start.month ||
               (m == start.month && d >= start.day)
                # assume same year as start_at event (e.g. 2013 for 2013/14 season)
                start.year
            else
                # assume year+1 as start_at event (e.g. 2014 for 2013/14 season)
                start.year+1
            end
    end
  else
    ### note - reset @start to new date
    ##            use @last_year
    if last_year
      @last_year = y
      puts "  [debug] _build_date - set running last_year to #{y}"
    end
  end


    date = Date.new( y,m,d )  ## y,m,d

    ### todo/fix
    ###  check/validate  wday here

    date
end

#_is_group?(text) ⇒ Boolean

Returns:

  • (Boolean)


96
97
98
99
# File 'lib/sportdb/quick/match_tree_on/on_round_outline.rb', line 96

def _is_group?( text )
  ## use regex for match
  GROUP_RE.match?( text )
end

#convertObject



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/sportdb/quick/match_tree.rb', line 30

def convert
  ## note: every (new) read call - resets errors list to empty
  @errors = []
  @warns  = []    ## track list of warnings (unmatched lines)  too - why? why not?

  ### todo/fix - FIX/FIX
  ##     check start year from first date
  ##    for now (auto-)update - @start with every date that incl. a year!!!
  @last_year    = nil
  @last_date    = nil
  @last_time    = nil

  ## todo/fix - use stack push/pop in the future - why? why not?
  @last_round   = nil  ##  merge - "top-level" - Round struct
  @last_round_name1  = nil  ## level 1 - string
  @last_round_name2  = nil  ## level 2 - string
  @last_round_name3  = nil  ## level 3 - string

  @last_group   = nil


  @teams   = Hash.new(0)   ## track counts (only) for now for (interal) team stats - why? why not?
  @rounds  = {}
  @groups  = {}
  @matches = []


  @tree.each do |node|
     if node.is_a? RaccMatchParser::RoundDef
      ## todo/fix:  add round definition (w begin n end date)
      ## todo: do not patch rounds with definition (already assume begin/end date is good)
      ##  -- how to deal with matches that get rescheduled/postponed?
        on_round_def( node )
      elsif node.is_a? RaccMatchParser::GroupDef  ## NB: group goes after round (round may contain group marker too)
      ### todo: add pipe (|) marker (required)
        on_group_def( node )
    elsif node.is_a? RaccMatchParser::RoundOutline
        on_round_outline( node )
    elsif node.is_a? RaccMatchParser::DateHeader
        on_date_header( node )
    elsif node.is_a? RaccMatchParser::MatchLine
        on_match_line( node )
    elsif node.is_a? RaccMatchParser::MatchLineWalkover
        on_match_line_walkover( node )
    elsif node.is_a? RaccMatchParser::MatchLineBye
        on_match_line_bye( node )
    elsif node.is_a? RaccMatchParser::GoalLine
        on_goal_line( node )
    elsif node.is_a?( RaccMatchParser::LineupLine ) ||
          node.is_a?( RaccMatchParser::RefereeLine )
         ## skip lineup, referee props for now
    elsif node.is_a?( RaccMatchParser::Heading1 ) ||
          node.is_a?( RaccMatchParser::Heading2 ) ||
          node.is_a?( RaccMatchParser::Heading3 )
        ###  skip headings (1/2/3) for now
    elsif node.is_a?( RaccMatchParser::BlankLine )
        ### skip for now; do nothing
    else
      ## report error
      msg = "!! WARN - unknown node (parse tree type) - #{node.class.name}"
      puts msg
      pp node

      log( msg )
      log( node.pretty_inspect )
    end
  end  # tree.each

  ## note - team keys are names and values are "internal" stats e.g. usage count!!
  ##                      and NOT team/club/nat_team structs!!
  [@teams.keys, @matches, @rounds.values, @groups.values]
end

#debug?Boolean

Returns:

  • (Boolean)


9
# File 'lib/sportdb/quick/match_tree.rb', line 9

def debug?()  self.class.debug?; end

#errors?Boolean

Returns:

  • (Boolean)


27
# File 'lib/sportdb/quick/match_tree.rb', line 27

def errors?() @errors.size > 0; end

#log(msg) ⇒ Object



5
6
7
8
9
10
11
12
# File 'lib/sportdb/quick/match_tree-helpers.rb', line 5

def log( msg )
  ## append msg to ./logs.txt
  ##     use ./errors.txt - why? why not?
  File.open( './logs.txt', 'a:utf-8' ) do |f|
    f.write( msg )
    f.write( "\n" )
  end
end

#on_date_header(node) ⇒ Object



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/sportdb/quick/match_tree_on/on_date_header.rb', line 7

def on_date_header( node )
  logger.debug( "date header: >#{node}<")

  date = _build_date( m: node.date[:m],
                      d: node.date[:d],
                      y: node.date[:y],
                      yy: node.date[:yy],
                      wday: node.date[:wday],
                      start: @start,
                      last_year: true )

  logger.debug( "    date: #{date} with start: #{@start}")

    @last_date = date   # keep a reference for later use
    @last_time = nil

    ###  quick "corona" hack - support seasons going beyond 12 month (see swiss league 2019/20 and others!!)
    ##    find a better way??
    ##  set @start date to full year (e.g. 1.1.) if date.year  is @start.year+1
    ##   todo/fix: add to linter to check for chronological dates!! - warn if NOT chronological
    ###  todo/check: just turn on for 2019/20 season or always? why? why not?

    ## todo/fix: add switch back to old @start_org
    ##   if year is date.year == @start.year-1    -- possible when full date with year set!!!
=begin
    if @start.month != 1
       if date.year == @start.year+1
         logger.debug( "!! hack - extending start date to full (next/end) year; assumes all dates are chronologigal - always moving forward" )
         @start_org = @start   ## keep a copy of the original (old) start date - why? why not? - not used for now
         @start = Date.new( @start.year+1, 1, 1 )
       end
    end
=end
end

#on_goal_line(node) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/sportdb/quick/match_tree_on/on_goal_line.rb', line 5

def on_goal_line( node )
  logger.debug "on goal line: >#{node}<"

  goals1 = node.goals1
  goals2 = node.goals2


  pp [goals1,goals2]     if debug?


## special rule
##    if goals 2 empty check if score for team 1 is zero
##                           and team 2 is NOT zero than
##                                make goals1 goald2!!
##   e.g. Norway 0-1  Austria
##                   (Hof 32)

 if goals2.empty? && !goals1.empty?

   match = @matches[-1]

   ##
   ## todo/fix
   ##   move upstream
   ##    use score1_zero? or such - why? why not?
   if (match.score.is_a?(Array) && match.score[0] == 0 ) ||
      (match.score.is_a?(Hash)  && match.score[:et] && match.score[:et][0] == 0) ||
      (match.score.is_a?(Hash)  && match.score[:et].nil? &&
                                   match.score[:ft] && match.score[:ft][0] == 0)
      ## "parallel assignment (or multiple assignment") - swap values in single line
      goals2, goals1 = goals1, goals2
   end
 end



  goals = []

  goals1.each do |rec|
    rec.minutes.each do |minute|
      goal = Goal.new(
                player: rec.player,
                team:   1,
                minute:  minute.m,
                offset:  minute.offset,
                penalty: minute.pen || false, #  note: pass along/use false NOT nil
                owngoal: minute.og || false
              )
      goals << goal
    end
  end

  goals2.each do |rec|
    rec.minutes.each do |minute|
      goal = Goal.new(
                player: rec.player,
                team:   2,
                minute:  minute.m,
                offset:  minute.offset,
                penalty: minute.pen || false, #  note: pass along/use false NOT nil
                owngoal: minute.og || false
              )
    goals << goal
    end
  end

  pp goals   if debug?

  ## quick & dirty - auto add goals to last match
  ##   note - for hacky (quick& dirty) multi-line support
  ##     always append for now
  match = @matches[-1]
  match.goals ||= []
  match.goals += goals

  ## todo/fix
  ##   sort by minute
  ##    PLUS auto-fill score1,score2 - why? why not?
end

#on_group_def(node) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/sportdb/quick/match_tree_on/on_group_def.rb', line 5

def on_group_def( node )
  logger.debug "on group def: >#{node}<"

 ## e.g
 ##  [:group_def, "Group A"],
 ##   [:team, "Germany"],
 ##   [:team, "Scotland"],
 ##   [:team, "Hungary"],
 ##   [:team, "Switzerland"]

  node.teams.each do |team|
        @teams[ team ] += 1
  end

  group = Group.new( name:  node.name,
                     teams: node.teams )

  @groups[ node.name ] = group
end

#on_match_line(node) ⇒ Object



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/sportdb/quick/match_tree_on/on_match_line.rb', line 6

def on_match_line( node )
  logger.debug( "on match: >#{node}<" )

  ## collect (possible) nodes by type
  num    = nil
  num = node.num   if node.num

  date   = nil
  date =  _build_date( m: node.date[:m],
                       d: node.date[:d],
                       y: node.date[:y],
                       yy: node.date[:yy],
                       wday: node.date[:wday],
                       start: @start,
                       last_year: true )   if node.date

  ## note - there's no time (-only) type in ruby
  ##  use string (e.g. '14:56', '1:44')
  ##   use   01:44 or 1:44 ?
  ##  check for 0:00 or 24:00  possible?
  time   = nil
  if node.time
     time   =  ('%d:%02d' % [node.time[:h], node.time[:m]])
     ## check for timezone
     time += " #{node.time[:timezone]}"   if node.time[:timezone]
  end



  ## todo/fix -
  ##   keep  time & time_local as pairs for @last_time/@last_time_local
  ##    - check for timezone
  ##      incl. timezone in time (string) - why? why not?
  time_local = nil
  if node.time_local
    time_local  =  ('%d:%02d' % [node.time_local[:h], node.time_local[:m]])
    time_local +=  " #{node.time_local[:timezone]}"   if node.time_local[:timezone]
  end


  ### todo/fix
  ##    add keywords (e.g. ht, ft or such) to Score.new - why? why not?
  ##     or use new Score.build( ht:, ft:, ) or such - why? why not?
  ## pp score
  score  = nil
  score = node.score   if node.score

  ## if node.score.is_a?(Array)
  ##    ## assume "undefined" score
  ##    score = node.score
  ##  else  ## (default) assume Hash
  ##     # ht = node.score[:ht] || [nil,nil]
  ##     # ft = node.score[:ft] || [nil,nil]
  ##     # et = node.score[:et] || [nil,nil]
  ##     # p  = node.score[:p]  || [nil,nil]
  ##     # values = [*ht, *ft, *et, *p]
  ##     # pp values
  ##     ## pp node.score
  ##    score = node.score
  ##  end
  ## end


  status = nil
  status =  node.status   if node.status   ### assume text for now
  ## if node_type == :status  # e.g. awarded, canceled, postponed, etc.
  ##  status = node[1]
  #
  ## todo - add    ## find (optional) match status e.g. [abandoned] or [replay] or [awarded]
  ##                                   or [cancelled] or [postponed] etc.
  ##    status = find_status!( line )   ## todo/check: allow match status also in geo part (e.g. after @) - why? why not?



  team1 = node.team1
  team2 = node.team2

  @teams[ team1 ] += 1
  @teams[ team2 ] += 1


  if node.header ## note - date/time for matches (w/ header) CANNOT get inherited!!
     @last_date = nil
     @last_time = nil
  else  ## no (match header), use date/time inheritance rules
    ###
    # check if date found?
    #   note: ruby falsey is nil & false only (not 0 or empty array etc.)
    if date
      ### check: use date_v2 if present? why? why not?
      @last_date = date    # keep a reference for later use
      @last_time = nil
      # @last_time = nil
    else
      date = @last_date    # no date found; (re)use last seen date
    end

    if time
      @last_time = time
    else
      time = @last_time
    end
  end



  group =  nil
  group =  @last_group  if @last_group

  round = nil
  round =  @last_round  if @last_round


  ### try auto-fill round
  ##    find (first) matching round by date if rounds / matchdays defined
  ##   if not rounds / matchdays defined - YES, allow matches WITHOUT rounds!!!
  if date && round.nil?
      if @rounds.size > 0
        @rounds.values.each do |round_rec|
          ## note: convert date to date only (no time) with to_date!!!
          if (round_rec.start_date && round_rec.end_date) &&
             (date.to_date >= round_rec.start_date &&
             date.to_date <= round_rec.end_date)
            round = round_rec
            break
          end
        end
        if round.nil?
          ## todo/fix - issue a warning (do NOT stop)
          puts "!! PARSE ERROR - no matching round found for match date:"
          pp date
          exit 1
        end
      end
  end


  ## todo/check: scores are integers or strings?

  ## todo/check: pass along round and group refs or just string (canonical names) - why? why not?

  ## split date in date & time if DateTime
=begin
  time_str = nil
  date_str = nil
  if date.is_a?( DateTime )
      date_str = date.strftime('%Y-%m-%d')
      time_str = date.strftime('%H:%M')
  elsif date.is_a?( Date )
      date_str = date.strftime('%Y-%m-%d')
  else  # assume date is nil
  end
=end

  time_str       = nil
  time_local_str = nil
  date_str       = nil

  date_str       = date.strftime('%Y-%m-%d')  if date
  time_str       = time           if date && time
  time_local_str = time_local     if date && time_local



  ground   = nil
  ground = node.geo  if node.geo

  ## attendance
  att = nil
  att =  node.att   if node.att


  @matches << Match.new( num:        num,
                         date:       date_str,
                         time:       time_str,
                         time_local: time_local_str,
                         team1:    team1,  ## note: for now always use mapping value e.g. rec (NOT string e.g. team1.name)
                         team2:    team2,  ## note: for now always use mapping value e.g. rec (NOT string e.g. team2.name)
                         score:    score,
                         round:    round ? round.name : nil,  ## note: for now always use string (assume unique canonical name for event)
                         group:    group ? group.name : nil,  ## note: for now always use string (assume unique canonical name for event)
                         status:   status,
                         ground:   ground,
                         att:      att )
  ### todo: cache team lookups in hash?
end

#on_match_line_bye(node) ⇒ Object



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/sportdb/quick/match_tree.rb', line 136

def on_match_line_bye( node )
  logger.debug( "on match (bye): >#{node}<" )

  ## note - bye    records NO date/time or ground (or score etc.)
  ##                 for now only team1/team2 and match status!!
  ##                  plus inherited round/group

  status = 'bye'

  team = node.team

  @teams[ team ] += 1

  group =  nil
  group =  @last_group  if @last_group

  round = nil
  round =  @last_round  if @last_round

  @matches << Match.new( team1:    team,  ## note: for now always use mapping value e.g. rec (NOT string e.g. team1.name)
                         round:    round ? round.name : nil,  ## note: for now always use string (assume unique canonical name for event)
                         group:    group ? group.name : nil,  ## note: for now always use string (assume unique canonical name for event)
                         status:   status )
  ### todo: cache team lookups in hash?
end

#on_match_line_walkover(node) ⇒ Object



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/sportdb/quick/match_tree.rb', line 106

def on_match_line_walkover( node )
  logger.debug( "on match (w/o): >#{node}<" )

  ## note - w/o (walkover) records NO date/time or ground (or score etc.)
  ##                 for now only team1/team2 and match status!!
  ##                  plus inherited round/group

  status = 'walkover'   ## use w/o - why? why not?

  team1 = node.team1
  team2 = node.team2

  @teams[ team1 ] += 1
  @teams[ team2 ] += 1


  group =  nil
  group =  @last_group  if @last_group

  round = nil
  round =  @last_round  if @last_round

  @matches << Match.new( team1:    team1,  ## note: for now always use mapping value e.g. rec (NOT string e.g. team1.name)
                         team2:    team2,  ## note: for now always use mapping value e.g. rec (NOT string e.g. team2.name)
                         round:    round ? round.name : nil,  ## note: for now always use string (assume unique canonical name for event)
                         group:    group ? group.name : nil,  ## note: for now always use string (assume unique canonical name for event)
                         status:   status )
  ### todo: cache team lookups in hash?
end

#on_round_def(node) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/sportdb/quick/match_tree_on/on_round_def.rb', line 5

def on_round_def( node )
  logger.debug "on round def: >#{node}<"

  ## e.g. [[:round_def, "Matchday 1"], [:duration, "Fri Jun 14 - Tue Jun 18"]]
  ##      [[:round_def, "Matchday 2"], [:duration, "Wed Jun 19 - Sat Jun 22"]]
  ##      [[:round_def, "Matchday 3"], [:duration, "Sun Jun 23 - Wed Jun 26"]]

  name  = node.name
  # NB: use extracted round name for knockout check
  # knockout_flag = is_knockout_round?( name )


  ##
  ##  note - do NOT update @last_year on round def dates!!
  ##              only update for running dates in matches!!

  if node.date
      start_date = end_date = _build_date( m: node.date[:m],
                                           d: node.date[:d],
                                           y: node.date[:y],
                                           yy: node.date[:yy],
                                           wday: node.date[:wday],
                                            start: @start,
                                            last_year: false )
  elsif node.duration
    ## reuse year in start date e.g. July 26-27 1930
    ##                               July 26 [1930], [July] 27 1930
    start_date  = _build_date( m: node.duration[:start][:m],
                               d: node.duration[:start][:d],
                               y: node.duration[:start][:y]   || node.duration[:end][:y],
                               yy: node.duration[:start][:yy] || node.duration[:end][:yy],
                               wday: node.duration[:start][:wday],
                                 start: @start,
                                 last_year: false )

    ## reuse month in end date e.g.  July 26-27
    ##                               July 26, [July] 27
    end_date    = _build_date( m: node.duration[:end][:m] || node.duration[:start][:m],
                               d: node.duration[:end][:d],
                               y: node.duration[:end][:y],
                               yy: node.duration[:end][:yy],
                               wday: node.duration[:end][:wday],
                                 start: @start,
                                 last_year: false )
  else
     puts "!! PARSE ERROR - expected date or duration for round def; got:"
     pp node
     exit 1
  end

  # note: - NOT needed; start_at and end_at are saved as date only (NOT datetime)
  #  set hours,minutes,secs to beginning and end of day (do NOT use default 12.00)
  #   e.g. use 00.00 and 23.59
  # start_at = start_at.beginning_of_day
  # end_at   = end_at.end_of_day

  # note: make sure start_at/end_at is date only (e.g. use start_at.to_date)
  #   sqlite3 saves datetime in date field as datetime, for example (will break date compares later!)

  # note - _build_date always returns Date for now - no longer needed!!
  # start_date = start_date.to_date
  #  end_date   = end_date.to_date




  logger.debug "    start_date: #{start_date}"
  logger.debug "    end_date:   #{end_date}"
  logger.debug "    name:    >#{name}<"

  round = Round.new( name:       name,
                     start_date: start_date,
                     end_date:   end_date,
                     auto:       false )

  @rounds[ name ] = round
end

#on_round_outline(node) ⇒ Object



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/sportdb/quick/match_tree_on/on_round_outline.rb', line 6

def on_round_outline( node )
  logger.debug "on round outline: >#{node}<"

  ## always reset dates - why? why not?
  ##    note - needs last_date for year
  ##         track last_year with extra variable

  name  = node.outline
  level = node.level


    ####
    # check for "old" group header in ("automagic") round outline for now
    ##
    ##  todo/fix - use only names from group def for lookup/is_group match!!!
    ##    do NOT use (generic) regex!!
    if level == 1 && _is_group?( name )
      logger.debug "on group header: >#{node}<"

      group = @groups[ name ]

      if group
        # set group for matches
        @last_group = group
          # note: group header resets (last) round  (allows, for example):
          #  e.g.
          #  Group Playoffs/Replays       -- round header
          #    team1 team2                -- match
          #  Group B                      -- group header
          #    team1 team2 - match  (will get new auto-matchday! not last round)
        @last_round     = nil
        return  ## note - return here; do NOT fall through to std round processing!
      else
        puts "!! WARN - no group def found for >#{name}<; will use a (plain) round"
      end
    end  ## is_group?


    ##
    ## todo/fix - also reset round name levels on heading 1/2/3 etc.
    ##                why? why not?

    if level == 1
      @last_round_name1 = name
      @last_round_name2 = nil
      @last_round_name3 = nil
    elsif level == 2
      @last_round_name2 = name
      @last_round_name3 = nil
      name = [@last_round_name1, name].join( ', ' )
    elsif level == 3
      @last_round_name3 == name
      name = [@last_round_name1, @last_round_name2, name].join( ', ')
    else
       puts "!! ERROR - unsupported round outline level #{level}; use 1-3 - sorry"
       exit 1
    end


    round = @rounds[ name ]
    if round.nil?    ## auto-add / create if missing
      round = Round.new( name: name )
      @rounds[ name ] = round
    end

    @last_round = round
    @last_group = nil   # note: always reset group to no group - why? why not?

    ## todo/fix/check
    ##  make round a scope for date(time) - why? why not?
    ##   reset date/time e.g. @last_date = nil !!!!
end