Apr 24 fetching Google Calendar events in Ruby
tags:
You have a Google Calendar and you want to make some cool things by fetching your events, the Google Calendar API and the gdata ruby gem make that a charm. It’s all about login in to your calendar, fetching the events and parsing the REXML response.
Let’s see an easy example:
# gcal.rb
# to run standalone we require rubygems
# you surely don't need it to to use the GCal class inside your web app
require 'rubygems'
# the ruby magic gem that makes this all posible
require 'gdata'
require 'ostruct'
class GCal
attr_accessor :events, :user
def initialize(user = GOOGLE_USER_WITH_PUBLIC_CALENDAR, pwd = PASSWORD)
@user = user
@events = []
@cal = GData::Client::Calendar.new
# we are login to google
@cal.clientlogin(user,pwd)
# and fetching the public calendar of the user
response = @cal.get("https://www.google.com/calendar/feeds/#{@user}/private/full")
# entries are the events, we turn the response into an REXML object to iterate the XML elements
response.to_xml.elements.each('entry') do |entry|
# we fill the details of the events
details = OpenStruct.new({ :title => entry.elements['title'].text })
details.attendees = []
entry.elements.each do |elem|
case elem.name
when "who"
unless elem.attributes['valueString'] == "calendar calendar"
details.attendees << elem.attributes['valueString']
end
when "when"
details.starts_at = DateTime.parse elem.attributes['startTime']
details.ends_at = DateTime.parse elem.attributes['endTime']
when "where"
details.where = elem.attributes['valueString']
end
end
@events << details
end
# just as an example, printing the event details
def list_events
unless @events.nil?
@events.each do |event|
puts "event #{event.title}"
puts "from #{event.starts_at} to #{event.ends_at}"
puts "where #{event.where}"
event.attendees.each do |attendee|
puts "attendee: #{attendee}"
end
end
end
end
end
end
# just a running example, remove the line to use inside your web app
GCal.new.list_events
You notice the calendar is public, well it turned out I could not get to fetch the non-public ones, and every Google example was about public ones.
And the Specs?
Yes, you are a cool kid and can live without the Specs, huh? Well we copy an example
of expected Google response and stub the network access.
# gcal_spec.rb
require File.dirname(__FILE__) + '/../spec_helper'
# gcal.rb lives in RAILS_ROOT/lib
require File.dirname(__FILE__) + '/../../lib/gcal'
describe GCal do
it 'should retrieve events correctly' do
user = "calendar@example.com"
# we are stubbing all google access, if you are better with real google access comment it
stub_gdata_google_calendar
cl = GCal.new user, "fake"
cl.user.should == user
cl.events.length.should == 2
first_event = cl.events.first
first_event.title.should == "some event"
first_event.starts_at.should be_instance_of(DateTime)
first_event.ends_at.should be_instance_of(DateTime)
first_event.attendees.size.should == 2
first_event.where.should == "plaza"
end
private
def stub_gdata_google_calendar
# we stub the whole Calendar object
GData::Client::Calendar.stub!(:new)
# bypassing google login
@cal.stub!(:clientlogin).and_return(true)
# and stub the response also
@cal.stub!(:get).and_return(my_stubbed_response)
end
def my_stubbed_response
response = GData::HTTP::Response.new
# we are not caring about headers
response.headers = { }
response.body = GCAL_BODY
response.status_code = 200
response
end
# hey, if google changes its response the specs still pass, but your gcal WILL NOT really work
# you could problably set a public self calendar, remove the stub_gdata_google_calendar line
# and set login info for that user and check against real google response
# google body response
GCAL_BODY = grab the value from http://gist.github.com/101258
end
well, that’s it