class Competition

Results that derive their results from other Events. Se TYPES. Year-long: BAR, Ironman, WSBA Rider Rankings, Oregon Cup. Event-based: Cross Crusade, Mount Tabor Series.

point_schedule: Array. How many points for each place? source_events: Which events count toward Competition? Not all Competitions use this relationship. Many dynamically choose their source events each time they calculate. competition_event_memberships: Relationship between source_events and competition.

calculate! is the main method

Constants

TYPES

Public Class Methods

calculate!(year = Time.zone.today.year) click to toggle source

Update results based on source event results. (Calculate clashes with internal Rails method)

# File app/models/competitions/competition.rb, line 59
def self.calculate!(year = Time.zone.today.year)
  benchmark(name, :level => :info) {
    transaction do
      year = year.to_i if year.is_a?(String)
      competition = self.find_or_create_for_year(year)
      raise(ActiveRecord::ActiveRecordError, competition.errors.full_messages) unless competition.errors.empty?
      competition.destroy_races
      competition.create_races
      competition.create_children
      # Could bulk load all Event and Races at this point, but hardly seems to matter
      competition.calculate_members_only_places
      competition.calculate!
    end
  }
  # Don't return the entire populated instance!
  true
end
find_for_year(year = RacingAssociation.current.year) click to toggle source
# File app/models/competitions/competition.rb, line 45
def self.find_for_year(year = RacingAssociation.current.year)
  self.where("date between ? and ?", Time.zone.local(year).beginning_of_year.to_date, Time.zone.local(year).end_of_year.to_date).first
end
find_for_year!(year = RacingAssociation.current.year) click to toggle source
# File app/models/competitions/competition.rb, line 49
def self.find_for_year!(year = RacingAssociation.current.year)
  self.find_for_year(year) || raise(ActiveRecord::RecordNotFound)
end
find_or_create_for_year(year = RacingAssociation.current.year) click to toggle source
# File app/models/competitions/competition.rb, line 53
def self.find_or_create_for_year(year = RacingAssociation.current.year)
  self.find_for_year(year) || self.create(:date => (Time.zone.local(year).beginning_of_year))
end

Public Instance Methods

after_calculate() click to toggle source

Callback

# File app/models/competitions/competition.rb, line 118
def after_calculate
  self.updated_at = Time.zone.now
end
after_create_competition_results_for(race) click to toggle source

By default, does nothing. Useful to apply rule like:

  • Any results after the first four only get 50-point bonus

  • Drop lowest-scoring result

# File app/models/competitions/competition.rb, line 165
def after_create_competition_results_for(race)
  if maximum_events
    race.results.each do |result|
      # Don't bother sorting scores unless we need to drop some
      if result.scores.size > maximum_events
        result.scores.sort! { |x, y| y.points <=> x.points }
        lowest_scores = result.scores[maximum_events, 2]
        lowest_scores.each do |lowest_score|
          result.scores.destroy(lowest_score)
        end
        # Rails destroys Score in database, but doesn't update the current association
        result.scores(true)
      end

      if preliminary?(result)
        result.preliminary = true       
      end    
    end
  end
end
break_ties?() click to toggle source
# File app/models/competitions/competition.rb, line 190
def break_ties?
  true
end
calculate!() click to toggle source

Rebuild results

# File app/models/competitions/competition.rb, line 105
def calculate!
  races.each do |race|
    results = source_results_with_benchmark(race)
    create_competition_results_for(results, race)
    after_create_competition_results_for(race)
    race.place_results_by_points(break_ties?, ascending_points?)
  end
  
  after_calculate
  save!
end
calculate_members_only_places() click to toggle source

Some competitions are only open to RacingAssociation members, and non-members are dropped from the results.

# File app/models/competitions/competition.rb, line 92
def calculate_members_only_places
  if place_members_only?
    # Uses batch_size, Rails 2.3 db cursor, to limit load on memory
    Race.find_each(:include => :event,
              :conditions => [ "events.type != ? and events.date between ? and ? and (events.updated_at > ? || races.updated_at > ?)", 
                               self.class.name.demodulize, start_date, end_date, 1.week.ago, 1.week.ago ]
              ) do |r|
                r.calculate_members_only_places!
              end
  end
end
create_children() click to toggle source

Override in superclass for Competitions like OBRA OverallBAR

# File app/models/competitions/competition.rb, line 87
def create_children
  true
end
create_competition_results_for(results, race) click to toggle source

If same rider places twice in same race, only highest result counts TODO Replace ifs with methods

# File app/models/competitions/competition.rb, line 129
def create_competition_results_for(results, race)
  competition_result = nil
  person = nil

  results.each_with_index do |source_result, index|
    logger.debug("#{self.class.name} scoring result: #{source_result.date} race: #{source_result.race_name} pl: #{source_result.place} mem pl: #{source_result.members_only_place if place_members_only?} #{source_result.last_name} #{source_result.team_name}") if logger.debug?

    points = points_for(source_result)

    if person.nil? || source_result.try(:person_id) != person.id
      person = Person.includes(:names, :team => :names).where(:id => source_result.person_id).first
    end
    
    if points > 0.0 && (!members_only? || member?(person, source_result.date))
      if first_result_for_person?(source_result, competition_result)
        # Intentionally not using results association create method. No need to hang on to all competition results.
        # In fact, this could cause serious memory issues with the Ironman
        competition_result = Result.create!(
           :person => person, 
           :team => person.try(:team),
           :event => self,
           :race => race)
      end
 
      competition_result.scores.create_if_best_result_for_race(
        :source_result => source_result, 
        :competition_result_id => competition_result.id, 
        :points => points
      )
    end
  end
end
create_races() click to toggle source
# File app/models/competitions/competition.rb, line 81
def create_races
  category = Category.find_or_create_by_name(friendly_name)
  self.races.create(:category => category)
end
default_ironman() click to toggle source
# File app/models/competitions/competition.rb, line 77
def default_ironman
  false
end
disable_notification!() click to toggle source

This method does nothing, and always returns true. Competitions don’t participate in event notification.

# File app/models/competitions/competition.rb, line 207
def disable_notification!
  true
end
enable_notification!() click to toggle source

This method does nothing, and always returns true. Competitions don’t participate in event notification.

# File app/models/competitions/competition.rb, line 212
def enable_notification!
  true
end
expire_cache() click to toggle source
# File app/models/competitions/competition.rb, line 221
def expire_cache
  if ApplicationController.perform_caching
    ApplicationController.expire_cache
  end
end
first_result_for_person?(source_result, competition_result) click to toggle source
# File app/models/competitions/competition.rb, line 194
def first_result_for_person?(source_result, competition_result)
  competition_result.nil? || source_result.person_id != competition_result.person_id
end
first_result_for_team?(source_result, competition_result) click to toggle source
# File app/models/competitions/competition.rb, line 198
def first_result_for_team?(source_result, competition_result)
  competition_result.nil? || source_result.team_id != competition_result.team_id
end
maximum_events() click to toggle source
# File app/models/competitions/competition.rb, line 186
def maximum_events
  nil
end
notification_enabled?() click to toggle source

This method always returns false. Competitions don’t participate in event notification.

# File app/models/competitions/competition.rb, line 217
def notification_enabled?
  false
end
requires_combined_results?() click to toggle source
# File app/models/competitions/competition.rb, line 202
def requires_combined_results?
  false
end
source_results(race) click to toggle source

#source_results must be in person, place ascending order

# File app/models/competitions/competition.rb, line 123
def source_results(race)
  []
end
to_s() click to toggle source
# File app/models/competitions/competition.rb, line 227
def to_s
  "#<#{self.class} #{id} #{name} #{start_date} #{end_date}>"
end

Protected Instance Methods

source_results_with_benchmark(race) click to toggle source
# File app/models/competitions/competition.rb, line 233
def source_results_with_benchmark(race)
  results = []
  Competition.benchmark("#{self.class.name} source_results", :level => :debug) {
    results = source_results(race)
  }
  logger.debug("#{self.class.name} Found #{results.size} source results for '#{race.name}'") if logger.debug?
  results
end