class Sports::Standings

Public Class Methods

new( match_or_matches=nil, opts={} ) click to toggle source
# File lib/sportdb/structs/structs/standings.rb, line 40
def initialize( match_or_matches=nil, opts={} )
  ## fix:
  # passing in e.g. pts for win (3? 2? etc.)
  # default to 3 for now

  ## lets you pass in 2 as an alterantive, for example
  @pts_won = opts[:pts_won] || 3

  @lines = {}   # StandingsLines cached by team name/key

  ## add init and update all-in-one convenience shortcut
  update( match_or_matches )  if match_or_matches
end

Public Instance Methods

build( source: nil ) click to toggle source

fix: move build to StandingsPart/Report !!!!

# File lib/sportdb/structs/structs/standings.rb, line 114
def build( source: nil )   ## build / pretty print standings table in string buffer
  ## keep pretty printer in struct - why? why not?


  ## add standings table in markdown to buffer (buf)

  ## todo: use different styles/formats (simple/ etc  ???)

## simple table (only totals - no home/away)
##       standings.to_a.each do |l|
##         buf << '%2d. '  % l.rank
##         buf << '%-28s  ' % l.team
##         buf << '%2d '     % l.played
##         buf << '%3d '     % l.won
##         buf << '%3d '     % l.drawn
##         buf << '%3d '     % l.lost
##         buf << '%3d:%-3d ' % [l.goals_for,l.goals_against]
##         buf << '%3d'       % l.pts
##         buf << "\n"
##       end

  buf = ''
  buf << "\n"
  buf << "```\n"
  buf << "                                        - Home -          - Away -            - Total -\n"
  buf << "                                 Pld   W  D  L   F:A     W  D  L   F:A      F:A   +/-  Pts\n"

  to_a.each do |l|
    buf << '%2d. '  % l.rank
    buf << '%-28s  ' % l.team
    buf << '%2d  '     % l.played

    buf << '%2d '      % l.home_won
    buf << '%2d '      % l.home_drawn
    buf << '%2d '      % l.home_lost
    buf << '%3d:%-3d  ' % [l.home_goals_for,l.home_goals_against]

    buf << '%2d '       % l.away_won
    buf << '%2d '       % l.away_drawn
    buf << '%2d '       % l.away_lost
    buf << '%3d:%-3d  ' % [l.away_goals_for,l.away_goals_against]

    buf << '%3d:%-3d ' % [l.goals_for,l.goals_against]

    goals_diff = l.goals_for-l.goals_against
    if goals_diff > 0
      buf << '%3s  '  %  "+#{goals_diff}"
    elsif goals_diff < 0
      buf << '%3s  '  %  "#{goals_diff}"
    else ## assume 0
      buf << '     '
    end

    buf << '%3d'       % l.pts
    buf << "\n"
  end

  buf << "```\n"
  buf << "\n"

  ## optinal: add data source if known / present
  ##   assume (relative) markdown link for now in README.md
  if source
    buf << "(Source: [`#{source}`](#{source}))\n"
    buf << "\n"
  end

  buf
end
each( &block ) click to toggle source

note: add a convenience shortcut

to_a  will sort and add rank (1,2,3) to standing lines
# File lib/sportdb/structs/structs/standings.rb, line 73
def each( &block ) to_a.each( &block ); end
to_a() click to toggle source
# File lib/sportdb/structs/structs/standings.rb, line 75
def to_a
  ## return lines; sort and add rank
  ## note: will update rank!!!! (side effect)

  #############################
  ### calc ranking position (rank)
  ## fix/allow same rank e.g. all 1 or more than one team 3rd etc.

  # build array from hash
  ary = []
  @lines.each do |k,v|
    ary << v
  end

  ary.sort! do |l,r|
    ## note: reverse order (thus, change l,r to r,l)
    value = r.pts <=> l.pts
    if value == 0 # same pts try goal diff
      value = (r.goals_for-r.goals_against) <=> (l.goals_for-l.goals_against)
      if value == 0 # same goal diff too; try assume more goals better for now
        value = r.goals_for <=> l.goals_for
      end
    end
    value
  end

  ## update rank using ordered array
  ary.each_with_index do |line,i|
    line.rank = i+1 ## add ranking (e.g. 1,2,3 etc.) - note: i starts w/ zero (0)
  end

  ary
end
update( match_or_matches ) click to toggle source
# File lib/sportdb/structs/structs/standings.rb, line 55
def update( match_or_matches )
  ## convenience - update all matches at once
  ## todo/check:  check for ActiveRecord_Associations_CollectionProxy and than use to_a (to "force" array) - why? why not?
  matches = if match_or_matches.is_a?(Array)
              match_or_matches
            else
              [match_or_matches]
            end

  matches.each_with_index do |match,i| # note: index(i) starts w/ zero (0)
    update_match( match )
  end
  self  # note: return self to allow chaining
end

Private Instance Methods

update_match( m ) click to toggle source
# File lib/sportdb/structs/structs/standings.rb, line 186
def update_match( m )   ## add a match

  ## note: always use team as string for now
  ##   for now allow passing in of string OR struct - why? why not?
  ##   todo/fix:  change to m.team1_name and m.team2_name - why? why not?
  team1 = m.team1.is_a?( String ) ? m.team1 : m.team1.name
  team2 = m.team2.is_a?( String ) ? m.team2 : m.team2.name

  score = m.score.to_s

  ##  puts "   #{team1} - #{team2} #{score}"

  unless m.over?
    puts " !!!! skipping match - not yet over (date in the future) => #{m.date}"
    return
  end

  unless m.complete?
    puts "!!! [calc_standings] skipping match #{team1} - #{team2} w/ past date #{m.date} - scores incomplete => #{score}"
    return
  end



  line1 = @lines[ team1 ] || StandingsLine.new( team1 )
  line2 = @lines[ team2 ] || StandingsLine.new( team2 )

  line1.played      += 1
  line1.home_played += 1

  line2.played      += 1
  line2.away_played += 1

  if m.winner == 1
    line1.won      += 1
    line1.home_won += 1

    line2.lost      += 1
    line2.away_lost += 1

    line1.pts      += @pts_won
    line1.home_pts += @pts_won
  elsif m.winner == 2
    line1.lost      += 1
    line1.home_lost += 1

    line2.won       += 1
    line2.away_won  += 1

    line2.pts      += @pts_won
    line2.away_pts += @pts_won
  else ## assume drawn/tie (that is, 0)
    line1.drawn      += 1
    line1.home_drawn += 1

    line2.drawn      += 1
    line2.away_drawn += 1

    line1.pts      += 1
    line1.home_pts += 1
    line2.pts      += 1
    line2.away_pts += 1
  end

  if m.score1 && m.score2
    line1.goals_for      += m.score1
    line1.home_goals_for += m.score1
    line1.goals_against      += m.score2
    line1.home_goals_against += m.score2

    line2.goals_for      += m.score2
    line2.away_goals_for += m.score2
    line2.goals_against      += m.score1
    line2.away_goals_against += m.score1
  else
    puts "*** warn: [standings] skipping match with missing scores: #{m.inspect}"
  end

  @lines[ team1 ] = line1
  @lines[ team2 ] = line2
end