Class: Fbtxt::MatchTree
- Inherits:
-
Object
- Object
- Fbtxt::MatchTree
- Includes:
- Debuggable, Model
- Defined in:
- lib/fbtxt/document/match_tree.rb,
lib/fbtxt/document/match_tree-helpers.rb,
lib/fbtxt/document/match_tree_on/on_goal_line.rb,
lib/fbtxt/document/match_tree_on/on_group_def.rb,
lib/fbtxt/document/match_tree_on/on_match_bye.rb,
lib/fbtxt/document/match_tree_on/on_penalties.rb,
lib/fbtxt/document/match_tree_on/on_round_def.rb,
lib/fbtxt/document/match_tree_on/on_cards_line.rb,
lib/fbtxt/document/match_tree_on/on_match_line.rb,
lib/fbtxt/document/match_tree_on/on_date_header.rb,
lib/fbtxt/document/match_tree_on/on_lineup_line.rb,
lib/fbtxt/document/match_tree_on/on_referee_line.rb,
lib/fbtxt/document/match_tree_on/on_round_outline.rb
Overview
simple (match) parse tree to structs walker/handler/converter
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
-
#errors ⇒ Object
readonly
Returns the value of attribute errors.
Instance Method Summary collapse
-
#_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?.
-
#_collect_bookings(lineup) ⇒ Object
change to _collect_inline_bookings/cards - why? why not?.
-
#_each_player(lineup, &blk) ⇒ Object
fix - move "upstream to lineup" - why? why not? - rename each_lineup?.
- #_is_group?(text) ⇒ Boolean
- #convert ⇒ Object
- #errors? ⇒ Boolean
-
#initialize(tree, start: nil) ⇒ MatchTree
constructor
note: allow start(_date) nil if in use (start: nil) years expected on first date!!!.
- #log(msg) ⇒ Object
- #on_cards_line(node) ⇒ Object
- #on_date_header(node) ⇒ Object
- #on_goal_line(node) ⇒ Object
- #on_group_def(node) ⇒ Object
- #on_lineup_line(node) ⇒ Object
- #on_match_line(node) ⇒ Object
- #on_match_line_bye(node) ⇒ Object
-
#on_penalties(node) ⇒ Object
check - use on_penalties_line ???.
- #on_referee_line(node) ⇒ Object
- #on_round_def(node) ⇒ Object
- #on_round_outline(node) ⇒ Object
Constructor Details
#initialize(tree, start: nil) ⇒ MatchTree
note: allow start(_date) nil if in use (start: nil) years expected on first date!!!
18 19 20 21 22 23 |
# File 'lib/fbtxt/document/match_tree.rb', line 18 def initialize( tree, start: nil ) @tree = tree @start = start @errors = [] end |
Instance Attribute Details
#errors ⇒ Object (readonly)
Returns the value of attribute errors.
25 26 27 |
# File 'lib/fbtxt/document/match_tree.rb', line 25 def errors @errors 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/fbtxt/document/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 |
#_collect_bookings(lineup) ⇒ Object
change to _collect_inline_bookings/cards - why? why not?
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 |
# File 'lib/fbtxt/document/match_tree_on/on_lineup_line.rb', line 22 def _collect_bookings( lineup ) recs = [] ## Lineup = Struct.new( :name, :captain, :cards, :sub ) ## Card = Struct.new( :name, :minute ) _each_player( lineup ) do |item| if item.cards.is_a?(Array) && item.cards.size > 0 item.cards.each do |card| recs << EventCard.new( ## fix/fix/fix change to card.type upstream - why? why not? type: card.name, name: item.name, minute: card.minute ) end end end ## note - (auto-)sort by minute if present recs = recs.sort do |l,r| if l.minute && r.minute ## note - minute is obj!! (Fbtxt::Minute!!) l.minute <=> r.minute else 0 ## keep as is (no minutes available) end end recs end |
#_each_player(lineup, &blk) ⇒ Object
fix - move "upstream to lineup" - why? why not? - rename each_lineup?
9 10 11 12 13 14 15 16 17 18 19 |
# File 'lib/fbtxt/document/match_tree_on/on_lineup_line.rb', line 9 def _each_player( lineup, &blk ) lineup.each do |item| blk.call(item) ## plus (walk) recursive sub(stitution)s current = item while current && current.sub blk.call( current.sub.sub ) current = current.sub.sub end end end |
#_is_group?(text) ⇒ Boolean
96 97 98 99 |
# File 'lib/fbtxt/document/match_tree_on/on_round_outline.rb', line 96 def _is_group?( text ) ## use regex for match GROUP_RE.match?( text ) end |
#convert ⇒ Object
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 |
# File 'lib/fbtxt/document/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::MatchLineBye on_match_line_bye( node ) elsif node.is_a? RaccMatchParser::GoalLine on_goal_line( node ) elsif node.is_a? RaccMatchParser::PenaltiesLine on_penalties( node ) elsif node.is_a? RaccMatchParser::LineupLine on_lineup_line( node ) elsif node.is_a? RaccMatchParser::CardsLine on_cards_line( node ) elsif node.is_a? RaccMatchParser::RefereeLine on_referee_line( node ) 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 |
#errors? ⇒ Boolean
26 |
# File 'lib/fbtxt/document/match_tree.rb', line 26 def errors?() @errors.size > 0; end |
#log(msg) ⇒ Object
5 6 7 8 9 10 11 12 |
# File 'lib/fbtxt/document/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_cards_line(node) ⇒ Object
4 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 |
# File 'lib/fbtxt/document/match_tree_on/on_cards_line.rb', line 4 def on_cards_line( node ) _trace( "on cards: >#{node}<" ) ## get last match match = @matches[-1] ################################ ## CardsLine = Struct.new( :type, :bookings ) ## Booking = Struct.new( :name, :minute ) ## check if match has lineup ?? if match.lineup ## type = node.type ## e.g. 'Y', 'Y/R', 'R', 'SENTOFF', etc. ## note - flatten for now ## fix-fix-fix use lineup[0], lineup[1] latter - why? why not? bookings = node.bookings.flatten bookings.each do |b| ## find player ref in match lineup (team1/team2) player = nil ## note - expapand lineup[] to one or two items [*match.lineup].each_with_index do |lineup,i| player = lineup.find_player( b.name ) next if player.nil? ## fix-fix-fix- keep player obj/ref - why? why not? rec = EventCard.new( type: node.type, name: b.name, minute: b.minute ) match.bookings ||= [[],[]] match.bookings[i] << rec break end if player.nil? ## raise ArgumentError, ## "player >#{b.name}< NOT found in match (lineup): #{match.pretty_inspect}" ### log warn for now ## might be trainer, staff or missing player from bench w/o sub ## fix-fix-fix ## log error!! msg = "!! WARN - player >#{b.name}< NOT found; skipping booking #{b.pretty_inspect}" puts msg log( msg ) end end else ### warn - "standalone" bookings for now not yet supported!!! 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/fbtxt/document/match_tree_on/on_date_header.rb', line 7 def on_date_header( node ) _trace( "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 ) _trace( " 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 _trace( "!! 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 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 |
# File 'lib/fbtxt/document/match_tree_on/on_goal_line.rb', line 5 def on_goal_line( node ) _trace( "on goal line: >#{node}<" ) ### # note: goals formats # (i) [[],[]] (nested/paired) or # (ii) [] (flat/undefined) ## ## add Array#paired? and ## Array#flat? ## helper methods/checks or such - why? why not? if node.goals[0].is_a?( Array ) goals1, goals2 = node.goals[0], node.goals[1] else goals1 = node.goals goals2 = [] end pp [goals1,goals2] 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] ## special rule ## if goals 2 empty check if score for team 1 is zero ## and team 2 is NOT zero than ## make goals1 goals2!! ## e.g. Norway 0-1 Austria ## (Hof 32) if match.score && goals2.empty? && !goals1.empty? ## ## todo/fix: move upstream ## use score1_zero? or such - why? why not? if (match.score.reported? && match.score.reported[0] == 0 ) || (match.score.et? && match.score.et[0] == 0) || (match.score.ft? && !match.score.et? && 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( name: rec.player, team: 1, minute: minute.to_minute, ## from GoalMinute to Minute!! 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( name: rec.player, team: 2, minute: minute.to_minute, ## from GoalMinute to Minute!! penalty: minute.pen || false, # note: pass along/use false NOT nil owngoal: minute.og || false ) goals << goal end end pp goals if debug? ## todo/fix ## PLUS auto-fill score1,score2 - why? why not? ## quick & dirty - auto add goals to last match ## note - for hacky (quick& dirty) multi-line support ## always append for now match.goals ||= [] match.goals += goals ## always keep goal list sorted by minute - why? why not? ## - sort only on serialize (as_json) - why? why not? match.goals = match.goals.sort do |l,r| if l.minute && r.minute ## note - minute is obj!! (Fbtxt::Minute!!) l.minute <=> r.minute else ## keep as is (no minutes available) 0 end end 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/fbtxt/document/match_tree_on/on_group_def.rb', line 5 def on_group_def( node ) _trace( "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_lineup_line(node) ⇒ Object
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 |
# File 'lib/fbtxt/document/match_tree_on/on_lineup_line.rb', line 59 def on_lineup_line( node ) _trace( "on lineup: >#{node}<" ) ## get last match match = @matches[-1] ## collect players team_name = node.team lineup = node.lineup ## note - ## lineup - uses nested array format ## for formation ## ## quick & dirty hack - flatten for now ## refine later lineup = lineup.flatten ## LineupLine = Struct.new( :team, :lineup, :formation, :coach ) do ## Lineup = Struct.new( :name, :captain, :cards, :sub ) do ## Sub = Struct.new( :minute, :sub ) do ## todo/check if team name match ## warn if no match match.lineup ||= [] ## todo/fix-fix-fix add formation here too - why? why not? match.lineup << Lineup.build( lineup ) match.bookings ||=[] match.bookings << _collect_bookings( lineup ) 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 |
# File 'lib/fbtxt/document/match_tree_on/on_match_line.rb', line 6 def on_match_line( node ) _trace( "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 score = nil score = Score.build( node.score ) if node.score ## pp score 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
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 |
# File 'lib/fbtxt/document/match_tree_on/on_match_bye.rb', line 6 def on_match_line_bye( node ) _trace( "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_penalties(node) ⇒ Object
check - use on_penalties_line ???
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 |
# File 'lib/fbtxt/document/match_tree_on/on_penalties.rb', line 6 def on_penalties( node ) _trace( "on penalties: >#{node}<" ) ## get last match match = @matches[-1] ## PenaltiesLine = Struct.new( :penalties ) ## Penalty = Struct.new( :name, :score, :note ) ##### ## note ## (i) [] - single line (no separator) ## (ii) [[],[]] - nested team1/team2 (separator required) recs = nil if node.penalties.is_a?(Array) && node.penalties.size == 2 && node.penalties[0].is_a?(Array) && node.penalties[1].is_a?(Array) ## use zip to make (flattend) sequence - why? why not? ## we do NOT know who really started (picked via coin toss!!) ## keep nested arrays for now recs = [[],[]] node.penalties.each_with_index.each do |pens,i| pens.each do |pen| recs[i] << Penalty.new( name: pen.name, score: pen.score, note: pen.note ) end end else ## assume chronological sequence recs = [] node.penalties.each do |pen| recs << Penalty.new( name: pen.name, score: pen.score, note: pen.note ) end end match.penalties = recs end |
#on_referee_line(node) ⇒ Object
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# File 'lib/fbtxt/document/match_tree_on/on_referee_line.rb', line 5 def on_referee_line( node ) _trace( "on referee(s): >#{node}<" ) ## get last match match = @matches[-1] ## support multiple referees (incl. assistant refs etc.) ## RefereeLine = Struct.new( :referees ) ## Referee = Struct.new( :name, :country ) recs = [] node.referees.each do |ref| recs << Referee.new( name: ref.name, country: ref.country ) end match.referees = recs 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/fbtxt/document/match_tree_on/on_round_def.rb', line 5 def on_round_def( node ) _trace( "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 _trace( " start_date: #{start_date}" ) _trace( " end_date: #{end_date}" ) _trace( " 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/fbtxt/document/match_tree_on/on_round_outline.rb', line 6 def on_round_outline( node ) _trace( "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 ) _trace( "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 |