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:
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.
Filed under: Uncategorized | 1 Comment
Tags: rails, recursive events, ruby, time-based
Search
-
You are currently browsing the RubyHam weblog archives.

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.