First contribution from Brian: a class for recursive time-based operations, and our use in a Rails project

20Nov07

by Josh Adams

Ever wanted to be able to do something like an Outlook-style recursive event generator? Say, schedule an event each MWF for the next six weeks from 8:00 – 8:30 AM? There’s a nice library called RUNT that I ran across today that makes this kind of temporal work easier.

Then Brian, the newest hire at isotope11, created a library to ease the particular use case we had, which was using a form similar to the following:

Screenshot

The code for the GroupEvent class is as follows:


require 'runt'

class GroupEvent
  include Runt
  def self.schedule(start, finished, weekdays, type, &date)
    case type
    when /w/i
      self.weekly(start, finished, weekdays) { |day| date.call(day) }
    when /b/i
      self.biweekly(start, finished, weekdays) { |day| date.call(day) }
    when /m/i
      self.monthly(start, finished) { |day| date.call(day) }
    when /y/i
      self.yearly(start, finished) { |day| date.call(day) }
    end
  end 

  def self.weekly(start, finished, weekdays, &day)
    day = nil
    exp = nil
    for i in weekdays
      if (exp.nil?)
        exp = DIWeek.new(i)
      else
        exp ||= DIWeek.new(i)
      end
    end
    for day in (start..finished)
      if(exp.include?(day))
        yield(day)
      end
    end
  end

  def self.biweekly(start, finished, weekdays, &biday)
    self.weekly(start, finished, weekdays) do |biday|
      if((biday.day%2) == (start.day%2))
        yield(biday)
      end
    end
  end

  def self.monthly(start, finished, &month)
    current = start
    begin
      yield(current)
      current = current.to_time.months_since 1
    end while(current.to_time < finished.to_time)
  end

  def self.yearly(start, finished, &year)
    current = start
    begin
      yield(current)
      current = current.to_time.years_since 1
    end while(current.to_time < finished.to_time)
  end
end

Inside the controller that form points to, I call the following (*horrendously ugly*) method:


  def create_events
    if params[:recursive]
      start_date = Date.new(params[:start_date][:year].to_i, params[:start_date][:month].to_i, params[:start_date][:day].to_i)
      end_date = Date.new(params[:end_date][:year].to_i, params[:end_date][:month].to_i, params[:end_date][:day].to_i)
      GroupEvent.schedule(start_date, end_date, params[:days].map(&:to_i), params[:period]) do |date|
        starts_at = DateTime.new(date.year, date.month, date.day, params[:start_time][:hour].to_i, params[:start_time][:minute].to_i)
        ends_at = DateTime.new(date.year, date.month, date.day, params[:end_time][:hour].to_i, params[:end_time][:minute].to_i)
        DateEvent.create( :starts_at => starts_at, :ends_at => ends_at, :description => params[:event][:description])
      end
    else
      @event = DateEvent.new(params[:event])
    end
  end

Please, please forgive me for that code. It was well past five and we just wanted to get it working, okay? That code was mine, the good looking stuff above was Brian’s. Don’t pin my trespasses on him.

Anyway, the code appears to do exactly what we want so far, haven’t found any quirks yet. We’ll get better test coverage of this stuff tomorrow.

Advertisements


One Response to “First contribution from Brian: a class for recursive time-based operations, and our use in a Rails project”

  1. Well, now I see at least one issue. Bi-weekly will screw up on 50% or so of the months in some edge cases. Imagine one Friday it’s the 30th of September and the next Friday is the 6th of October. They will both get scheduled for, even though it hasn’t been a week. We can get the weeknumber for a given date, so let’s use that.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s


%d bloggers like this: