MacRuby – Create iCal event with alarm from Ruby

I’ve had to create some very similar events in my calendar, but they did not match a valid recurrence pattern. As I find it quite painful to create multiple iCal events I thought I maybe should try out MacRuby to automate the process as far as I could. As the resources for this topic are rare on the net I thought I could share the basics. I’ll explain the details below the coding.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#!/usr/local/bin/macruby
framework 'calendarstore'
 
defStore = CalCalendarStore.defaultCalendarStore
 
puts "Select the calendar:"
defStore.calendars.each_with_index do |cal,i|
  puts "\t#{i}. #{cal.type}\t#{cal.title}"
end
 
puts "Type in the number for the calendar you wish to use:"
cal_index = gets.to_i
 
puts "Creating an event..."
 
# setting up the basics
e = CalEvent.new
e.calendar = defStore.calendars[cal_index]
e.title = 'Just a macruby test'
e.startDate = Time.now + 3600
e.endDate = Time.now + 7200
 
# creating the alarm
a = CalAlarm.alarm
a.action = CalAlarmActionSound
a.sound = "Basso"
a.relativeTrigger = -60 * 60 # negative seconds
e.addAlarm a
 
# save the event
errorPointer = Pointer.new :object
success = defStore.saveEvent(e, span:CalSpanThisEvent, error:errorPointer)
puts "Error: #{errorPointer[0].userInfo}"if !success
 
puts "Finished calendar macruby test"

In the first step we have to get the default CalCalendarStore. This object contains all calendars we have configured in iCal.

The next few lines query the calendar which the test event should be put in.

From line 17. on the CalEvent object is initialized with several values. Note, that the chosen calendar is a property of the event. In this test case the event is created at now + 2hours end in now + 4hours. You can see that Ruby data types blend wonderfully into Objective-C types, as usually startDate and endDate would need a NSDate object.

For the perfect topping an alarm is created from line 23. on. The CalAlarm object is initialized with several values and then added to the event. You could go forward and start to add more reminders, as e.addAlarm a can be called multiple times.

Until now the stuff is not yet saved. Apple designed the library so that the CalCalendarStore object is responsible to save the event. So we have to call defStore.saveEvent, with the event object itself, the span (relevant for recurring events), and an error pointer.

If you did everything correct, you should see a new event in your iCal!