In some projects it's imperative to enable users to set their own rules for repeated events. Sometimes the event rules can be pretty complex, for instance "each second to last day of month" or "the second Friday of each month until a certain date". In order to handle such tasks easily and efficiently, you can use ice_cube gem.

Gem ice_cube allows to specify multiple rules and dates for repeated events using its API similar to iCalendar, and serialize/deserialize schedules to/from YAML and Ruby Hash formats. The power of ice_cube lies in the ability to store only the schedule itself, as opposed to generating the repeated events in advance all at once. We chose ice_cube namely for its easy and flexible API, constant updates and troubleshooting, popularity among other developers.

Gem installation:

gem install ice_cube

In order to create a schedule you should use class IceCube::Schedule:

require 'rubygems'
require 'ice_cube'

include IceCube

# Parameters:
# - date/time of schedule beginning
# - {
#  :duration => 3600  - duration in seconds
#  :end_time => Time.now + 3600 - end time
# }
schedule = Schedule.new(Date.today)  

# Add recurrence
schedule.add_recurrence_time(Date.today)
# Add exception
schedule.add_exception_time(Date.today + 1)

In order to add recurrence rules to a schedule you should use class IceCube::Rule. Ice_сube allows to create rules for daily, weekly, monthly, yearly, hourly, minutely and secondly recurrences. Several use cases are presented below (a more comprehensive list of examples can be found on the GitHub page of this project):

# Every fourth day
schedule.add_recurrence_rule Rule.daily(4)

# Every other week, on Mondays and Fridays
schedule.add_recurrence_rule Rule.weekly(2).day(:monday, :friday)

# Every month on the 10th, 20th and last day of the month
schedule.add_recurrence_rule Rule.monthly.day_of_month(10, 20, -1)

# Every month on the first Monday and last Tuesday
schedule.add_recurrence_rule Rule.monthly.day_of_week(
  :monday => [1],
  :tuesday => [-1]
)

# Every year on the 50th day and 100th day from the end of the year
schedule.add_recurrence_rule Rule.yearly.day_of_year(50, -100)  

It is possible to combine several rules in a schedule, including exception rules:

# Every fourth day except Mondays and Fridays
schedule.add_recurrence_rule Rule.daily(4)
schedule.add_exception_rule Rule.weekly.day(1, 5)

Recurrence rules may optionally include restrictions by occurrence count or until a certain date:

# Every other day, 10 times
schedule.add_recurrence_rule Rule.daily(2).count(10)

# Every other day until the end of the month
schedule.add_recurrence_rule Rule.daily(2).until(Date.today.next_month - Date.today.day)

And now probably the most interesting part - querying a schedule:

# All occurrences
schedule.all_occurrences

# All occurrences until a certain time
schedule.occurrences((Date.today + 5).to_time)

# Occurs at a certain time
schedule.occurs_at?(Time.now)

# Occurs on a certain date
schedule.occurs_on?(Date.today)

# Occurs during a certain time-frame
schedule.occurs_between?(Time.now, (Date.today + 5).to_time)

# First occurrences
schedule.first
schedule.first(3)

# Next occurrence
schedule.next_occurrence
# Next 3 occurrences
schedule.next_occurrences(3)
# Remaining occurrences
schedule.remaining_occurrences

Data serialization to YAML/HASH/iCal:

# YAML
yaml = schedule.to_yaml
Schedule.from_yaml(yaml)

# Hash
hash = schedule.to_hash
Schedule.from_hash(hash)

# iCalendar
schedule.to_ical

We use ice_cube gem to implement repeated events calendar in combination with FullCalendar and DelayedJob, a live example can be found on this page.

Some examples incorporated in this article have been taken from official project documentation. If you have any questions or remarks, please address them in the Comments section below. We will do our best to answer them all.

Reference


Tags dev, ruby, ice_cube
Published at December 01, 2012 22:00
Updated at December 09, 2012 12:58

comments powered by Disqus