<commit_before># This is a 'dumb' model. It is managed by a Run instance, which creates a 
# repeating instance of itself when instructed to. Validation is nonexistent 
# since all data should already have been vetted by the Run instance.
class RepeatingRun < ActiveRecord::Base
  include RunCore
  include RequiredFieldValidatorModule
  include RecurringRideCoordinator
  include RecurringRideCoordinatorScheduler
  include PublicActivity::Common

  has_paper_trail

  has_many :repeating_trips, through: :weekday_assignments
  has_many :weekday_assignments, dependent: :destroy

  has_many :repeating_run_manifest_orders, dependent: :destroy

  validates :comments, :length => { :maximum => 30 }
  validate :name_uniqueness
  normalize_attribute :name, :with => [ :strip ]
  
  validate :driver_availability
  validate :vehicle_availability
  validate :repeating_schedule_day_present
  
  has_many :runs # Child runs created by this RepeatingRun's scheduler

  scope :active, -> { where("end_date is NULL or end_date >= ?", Date.today) }
  # a query to find repeating_runs that can be used to assign repeating_trips
  scope :during, -> (from_time, to_time) { where("NOT (scheduled_start_time::time <= ?) OR NOT(scheduled_end_time::time <= ?)", to_time.utc.to_s(:time), from_time.utc.to_s(:time)) }
  
  # Repeating Runs where schedule conflicts with another Repeating Run's schedule by DATE
  scope :conflicts_with_schedule, -> (repeating_run) do
    where.not(id: repeating_run.id) # not the same record
    .select { |rr| repeating_run.schedule_conflicts_with?(rr) } # checks for overlap between recurrence rules
  end
  
  # Repeating Runs where schedule covers a given DATE
  scope :schedule_occurs_on, -> (date) do
    select do |rr| 
      rr.date_in_active_range?(date) &&         # date is in schedule's active range 
      rr.schedule.occurs_on?(date)              # schedule occurs on this date
    end
  end
  
  # Repeating Runs where the schedule time overlaps with a daily run by both DATE and TIME
  scope :overlaps_with_run, -> (run) do
    time_overlaps_with(run.scheduled_start_time, run.scheduled_end_time)
    .schedule_occurs_on(run.date)
  end
  
  # Not the parent repeating run of the passed daily run
  scope :not_the_parent_of, -> (daily_run) { where.not(id: daily_run.repeating_run_id) }

  schedules_occurrences_with with_attributes: -> (run) {
      {
        repeat:        1,
        interval_unit: "week",
        start_date:    (run.start_date.try(:to_date) || Date.today).to_s,
        interval:      run.repetition_interval, 
        monday:        run.repeats_mondays    ? 1 : 0,
        tuesday:       run.repeats_tuesdays   ? 1 : 0,
        wednesday:     run.repeats_wednesdays ? 1 : 0,
        thursday:      run.repeats_thursdays  ? 1 : 0,
        friday:        run.repeats_fridays    ? 1 : 0,
        saturday:      run.repeats_saturdays  ? 1 : 0,
        sunday:        run.repeats_sundays    ? 1 : 0
      }
    },
    destroy_future_occurrences_with: -> (run) {
      # Be sure not delete occurrences that have already been completed.
      runs = if run.date < Date.today
        Run.where().not(id: run.id).repeating_based_on(run.repeating_run).after_today.incomplete
      else 
        Run.where().not(id: run.id).repeating_based_on(run.repeating_run).after(run.date).incomplete
      end

      schedule = run.repeating_run.schedule
      Run.transaction do
        runs.find_each do |r|
          r.destroy unless schedule.occurs_on?(r.date)
        end
      end
    },
    destroy_all_future_occurrences_with: -> (run) {
      # Be sure not delete occurrences that have already been completed.
      runs = if run.date < Date.today
        Run.where().not(id: run.id).repeating_based_on(run.repeating_run).after_today.incomplete
      else 
        Run.where().not(id: run.id).repeating_based_on(run.repeating_run).after(run.date).incomplete
      end

      runs.destroy_all
    },
    unlink_past_occurrences_with: -> (run) {
      if run.date < Date.today
        Run.where().not(id: run.id).repeating_based_on(run.repeating_run).today_and_prior.update_all "repeating_run_id = NULL"
      else 
        Run.where().not(id: run.id).repeating_based_on(run.repeating_run).prior_to(run.date).update_all "repeating_run_id = NULL"
      end
    }

  # Builds runs based on the repeating run schedule
  def instantiate!
    return unless provider.try(:active?) && active? # Only build runs for active schedules

    # First and last days to create new runs
    now, later = scheduler_window_start, scheduler_window_end
        
    # Transaction block ensures that no DB changes will be made if there are any errors
    RepeatingRun.transaction do
      # Potentially create a run for each schedule occurrence in the scheduler window
      for date in schedule.occurrences_between(now, later)
                
        # Skip if occurrence is outside of schedule's active window
        next unless date_in_active_range?(date.to_date)
                
        # Build a run belonging to the repeating run for each schedule 
        # occurrence that doesn't already have a run built for it.
        unless self.runs.for_date(date).exists?
          run = Run.new(
            self.attributes
              .select{ |k, v| RepeatingRun.ride_coordinator_attributes.include?(k.to_s) }
              .merge( {
                "repeating_run_id" => id,
                "date" => date
              } )
          )

          # unassign unavailable driver
          run.driver = nil if run.driver && !run.driver.available_between?(run.date, run.scheduled_start_time.strftime('%H:%M'), run.scheduled_end_time.strftime('%H:%M'))
          
          run.save(validate: false) #allow invalid run exist

          TrackerActionLog.create_run(run, nil)
        end
                
      end
      
      # Timestamp the scheduler to its current timestamp or the end of the
      # advance scheduling period, whichever comes last
      self.update_column :scheduled_through, [self.scheduled_through, later].compact.max
    end<commit_msg>Add defensive code<commit_after># This is a 'dumb' model. It is managed by a Run instance, which creates a 
# repeating instance of itself when instructed to. Validation is nonexistent 
# since all data should already have been vetted by the Run instance.
class RepeatingRun < ActiveRecord::Base
  include RunCore
  include RequiredFieldValidatorModule
  include RecurringRideCoordinator
  include RecurringRideCoordinatorScheduler
  include PublicActivity::Common

  has_paper_trail

  has_many :repeating_trips, through: :weekday_assignments
  has_many :weekday_assignments, dependent: :destroy

  has_many :repeating_run_manifest_orders, dependent: :destroy

  validates :comments, :length => { :maximum => 30 }
  validate :name_uniqueness
  normalize_attribute :name, :with => [ :strip ]
  
  validate :driver_availability
  validate :vehicle_availability
  validate :repeating_schedule_day_present
  
  has_many :runs # Child runs created by this RepeatingRun's scheduler

  scope :active, -> { where("end_date is NULL or end_date >= ?", Date.today) }
  # a query to find repeating_runs that can be used to assign repeating_trips
  scope :during, -> (from_time, to_time) { where("NOT (scheduled_start_time::time <= ?) OR NOT(scheduled_end_time::time <= ?)", to_time.utc.to_s(:time), from_time.utc.to_s(:time)) }
  
  # Repeating Runs where schedule conflicts with another Repeating Run's schedule by DATE
  scope :conflicts_with_schedule, -> (repeating_run) do
    where.not(id: repeating_run.id) # not the same record
    .select { |rr| repeating_run.schedule_conflicts_with?(rr) } # checks for overlap between recurrence rules
  end
  
  # Repeating Runs where schedule covers a given DATE
  scope :schedule_occurs_on, -> (date) do
    select do |rr| 
      rr.date_in_active_range?(date) &&         # date is in schedule's active range 
      rr.schedule.occurs_on?(date)              # schedule occurs on this date
    end
  end
  
  # Repeating Runs where the schedule time overlaps with a daily run by both DATE and TIME
  scope :overlaps_with_run, -> (run) do
    time_overlaps_with(run.scheduled_start_time, run.scheduled_end_time)
    .schedule_occurs_on(run.date)
  end
  
  # Not the parent repeating run of the passed daily run
  scope :not_the_parent_of, -> (daily_run) { where.not(id: daily_run.repeating_run_id) }

  schedules_occurrences_with with_attributes: -> (run) {
      {
        repeat:        1,
        interval_unit: "week",
        start_date:    (run.start_date.try(:to_date) || Date.today).to_s,
        interval:      run.repetition_interval, 
        monday:        run.repeats_mondays    ? 1 : 0,
        tuesday:       run.repeats_tuesdays   ? 1 : 0,
        wednesday:     run.repeats_wednesdays ? 1 : 0,
        thursday:      run.repeats_thursdays  ? 1 : 0,
        friday:        run.repeats_fridays    ? 1 : 0,
        saturday:      run.repeats_saturdays  ? 1 : 0,
        sunday:        run.repeats_sundays    ? 1 : 0
      }
    },
    destroy_future_occurrences_with: -> (run) {
      # Be sure not delete occurrences that have already been completed.
      runs = if run.date < Date.today
        Run.where().not(id: run.id).repeating_based_on(run.repeating_run).after_today.incomplete
      else 
        Run.where().not(id: run.id).repeating_based_on(run.repeating_run).after(run.date).incomplete
      end

      schedule = run.repeating_run.schedule
      Run.transaction do
        runs.find_each do |r|
          r.destroy unless schedule.occurs_on?(r.date)
        end
      end
    },
    destroy_all_future_occurrences_with: -> (run) {
      # Be sure not delete occurrences that have already been completed.
      runs = if run.date < Date.today
        Run.where().not(id: run.id).repeating_based_on(run.repeating_run).after_today.incomplete
      else 
        Run.where().not(id: run.id).repeating_based_on(run.repeating_run).after(run.date).incomplete
      end

      runs.destroy_all
    },
    unlink_past_occurrences_with: -> (run) {
      if run.date < Date.today
        Run.where().not(id: run.id).repeating_based_on(run.repeating_run).today_and_prior.update_all "repeating_run_id = NULL"
      else 
        Run.where().not(id: run.id).repeating_based_on(run.repeating_run).prior_to(run.date).update_all "repeating_run_id = NULL"
      end
    }

  # Builds runs based on the repeating run schedule
  def instantiate!
    return unless provider.try(:active?) && active? # Only build runs for active schedules

    # First and last days to create new runs
    now, later = scheduler_window_start, scheduler_window_end
        
    # Transaction block ensures that no DB changes will be made if there are any errors
    RepeatingRun.transaction do
      # Potentially create a run for each schedule occurrence in the scheduler window
      for date in schedule.occurrences_between(now, later)
                
        # Skip if occurrence is outside of schedule's active window
        next unless date_in_active_range?(date.to_date)
                
        # Build a run belonging to the repeating run for each schedule 
        # occurrence that doesn't already have a run built for it.
        unless self.runs.for_date(date).exists?
          run = Run.new(
            self.attributes
              .select{ |k, v| RepeatingRun.ride_coordinator_attributes.include?(k.to_s) }
              .merge( {
                "repeating_run_id" => id,
                "date" => date
              } )
          )

          # unassign unavailable driver
          if run.driver && run.scheduled_start_time && run.scheduled_end_time
            run.driver = nil if !run.driver.available_between?(run.date, run.scheduled_start_time.strftime('%H:%M'), run.scheduled_end_time.strftime('%H:%M'))
          end

          run.save(validate: false) #allow invalid run exist

          TrackerActionLog.create_run(run, nil)
        end
                
      end
      
      # Timestamp the scheduler to its current timestamp or the end of the
      # advance scheduling period, whichever comes last
      self.update_column :scheduled_through, [self.scheduled_through, later].compact.max
    end
{'fraction_non_alphanumeric': 0.08633799362276183, 'fraction_numerical': 0.002779821764369226, 'mean_word_length': 2.844123192960402, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5256915', 'n_tokens_mistral': 3931, 'n_tokens_neox': 3729, 'n_words': 983}