gcal4ruby 0.2.11 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +5 -0
- data/lib/gcal4ruby/calendar.rb +15 -13
- data/lib/gcal4ruby/event.rb +41 -29
- data/lib/gcal4ruby/recurrence.rb +61 -12
- data/lib/gcal4ruby/service.rb +7 -3
- data/test/unit.rb +39 -0
- metadata +2 -2
data/CHANGELOG
CHANGED
@@ -1,4 +1,9 @@
|
|
1
1
|
#=CHANGELOG
|
2
|
+
#==version 0.3.0
|
3
|
+
#* Rewrote Event.find to improve performance significantly.
|
4
|
+
#* Added improvements to event recurrence handling, including loading existing recurrences, changing recurring events to non recurring and vice versa.
|
5
|
+
#* Added support for initialization attributes to Event, Calendar, Service and Recurrence.
|
6
|
+
#* Fixed query string typo in Event.find. Fix provided by nat.lownes.
|
2
7
|
#==version 0.2.11
|
3
8
|
#* Added support for GML elements in calendar events. Fix provided by nat.lownes.
|
4
9
|
#* Fixed event status bug where cancelled events were marked confirmed. Fix provided by rifraf.
|
data/lib/gcal4ruby/calendar.rb
CHANGED
@@ -116,24 +116,26 @@ class Calendar
|
|
116
116
|
#end
|
117
117
|
end
|
118
118
|
|
119
|
-
#Accepts a Service object. Returns the new Calendar
|
120
|
-
#error.
|
121
|
-
def initialize(service)
|
119
|
+
#Accepts a Service object and an optional attributes hash for initialization. Returns the new Calendar
|
120
|
+
#if successful, otherwise raises the InvalidService error.
|
121
|
+
def initialize(service, attributes = {})
|
122
122
|
super()
|
123
123
|
if !service.is_a?(Service)
|
124
124
|
raise InvalidService
|
125
125
|
end
|
126
|
-
|
127
|
-
|
126
|
+
attributes.each do |key, value|
|
127
|
+
self.send("#{key}=", value)
|
128
|
+
end
|
129
|
+
@xml ||= CALENDAR_XML
|
130
|
+
@service ||= service
|
128
131
|
@exists = false
|
129
|
-
@title
|
130
|
-
@summary
|
131
|
-
@public
|
132
|
-
@
|
133
|
-
@
|
134
|
-
@
|
135
|
-
@
|
136
|
-
@where = ""
|
132
|
+
@title ||= ""
|
133
|
+
@summary ||= ""
|
134
|
+
@public ||= false
|
135
|
+
@hidden ||= false
|
136
|
+
@timezone ||= "America/Los_Angeles"
|
137
|
+
@color ||= "#2952A3"
|
138
|
+
@where ||= ""
|
137
139
|
return true
|
138
140
|
end
|
139
141
|
|
data/lib/gcal4ruby/event.rb
CHANGED
@@ -115,8 +115,8 @@ module GCal4Ruby
|
|
115
115
|
#Sets the event's recurrence information to a Recurrence object. Returns the recurrence if successful,
|
116
116
|
#false otherwise
|
117
117
|
def recurrence=(r)
|
118
|
-
if r.is_a?(Recurrence)
|
119
|
-
r.event = self
|
118
|
+
if r.is_a?(Recurrence) or r.nil?
|
119
|
+
r.event = self unless r.nil?
|
120
120
|
@recurrence = r
|
121
121
|
else
|
122
122
|
return false
|
@@ -178,24 +178,21 @@ module GCal4Ruby
|
|
178
178
|
end
|
179
179
|
end
|
180
180
|
|
181
|
-
#Creates a new Event. Accepts a valid Calendar object.
|
182
|
-
def initialize(calendar)
|
181
|
+
#Creates a new Event. Accepts a valid Calendar object and optional attributes hash.
|
182
|
+
def initialize(calendar, attributes = {})
|
183
183
|
if not calendar.editable
|
184
184
|
raise CalendarNotEditable
|
185
185
|
end
|
186
186
|
super()
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
@
|
191
|
-
@
|
192
|
-
@
|
193
|
-
@
|
194
|
-
@
|
195
|
-
@
|
196
|
-
@attendees = []
|
197
|
-
@reminder = nil
|
198
|
-
@all_day = false
|
187
|
+
attributes.each do |key, value|
|
188
|
+
self.send("#{key}=", value)
|
189
|
+
end
|
190
|
+
@xml ||= EVENT_XML
|
191
|
+
@calendar ||= calendar
|
192
|
+
@transparency ||= "http://schemas.google.com/g/2005#event.opaque"
|
193
|
+
@status ||= "http://schemas.google.com/g/2005#event.confirmed"
|
194
|
+
@attendees ||= []
|
195
|
+
@all_day ||= false
|
199
196
|
end
|
200
197
|
|
201
198
|
#If the event does not exist on the Google Calendar service, save creates it. Otherwise
|
@@ -268,6 +265,19 @@ module GCal4Ruby
|
|
268
265
|
end
|
269
266
|
when "where"
|
270
267
|
ele.attributes["valueString"] = @where
|
268
|
+
when "recurrence"
|
269
|
+
puts 'recurrence element found' if @calendar.service.debug
|
270
|
+
if @recurrence
|
271
|
+
puts 'setting recurrence' if @calendar.service.debug
|
272
|
+
ele.text = @recurrence.to_s
|
273
|
+
else
|
274
|
+
puts 'no recurrence, adding when' if @calendar.service.debug
|
275
|
+
w = xml.root.add_element("gd:when")
|
276
|
+
xml.root.delete_element("/entry/gd:recurrence")
|
277
|
+
w.attributes["startTime"] = @all_day ? @start.strftime("%Y-%m-%d") : @start.xmlschema
|
278
|
+
w.attributes["endTime"] = @all_day ? @end.strftime("%Y-%m-%d") : @end.xmlschema
|
279
|
+
set_reminder(w)
|
280
|
+
end
|
271
281
|
end
|
272
282
|
end
|
273
283
|
if not @attendees.empty?
|
@@ -332,6 +342,8 @@ module GCal4Ruby
|
|
332
342
|
when "http://schemas.google.com/g/2005#event.cancelled"
|
333
343
|
@status = :cancelled
|
334
344
|
end
|
345
|
+
when 'recurrence'
|
346
|
+
@recurrence = Recurrence.new(ele.text)
|
335
347
|
when "transparency"
|
336
348
|
case ele.attributes["value"]
|
337
349
|
when "http://schemas.google.com/g/2005#event.transparent"
|
@@ -380,18 +392,18 @@ module GCal4Ruby
|
|
380
392
|
|
381
393
|
if test
|
382
394
|
puts "id passed, finding event by id" if calendar.service.debug
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
+
#ugly, but Google doesn't return the self url as ID as described in the API reference http://code.google.com/apis/calendar/data/2.0/developers_guide_protocol.html#RetrievingEvents
|
396
|
+
event_id = query.gsub("http://www.google.com/calendar/feeds/#{CGI::escape(calendar.service.account)}/events/",
|
397
|
+
"http://www.google.com/calendar/feeds/#{CGI::escape(calendar.service.account)}/private/full/")
|
398
|
+
es = calendar.service.send_get(event_id)
|
399
|
+
puts es.inspect if calendar.service.debug
|
400
|
+
if es
|
401
|
+
entry = REXML::Document.new(es.read_body).root
|
402
|
+
puts 'event found' if calendar.service.debug
|
403
|
+
Event.define_xml_namespaces(entry)
|
404
|
+
event = Event.new(calendar)
|
405
|
+
event.load("<?xml version='1.0' encoding='UTF-8'?>#{entry.to_s}")
|
406
|
+
return event
|
395
407
|
end
|
396
408
|
return nil
|
397
409
|
end
|
@@ -420,7 +432,7 @@ module GCal4Ruby
|
|
420
432
|
query_string += "&max-results=#{max_results}" if max_results
|
421
433
|
query_string += "&sortorder=#{sort_order}" if sort_order
|
422
434
|
query_string += "&ctz=#{timezone.gsub(" ", "_")}" if timezone
|
423
|
-
query_string += "&singleevents
|
435
|
+
query_string += "&singleevents=#{single_events}" if single_events
|
424
436
|
if query_string
|
425
437
|
events = calendar.service.send_get("http://www.google.com/calendar/feeds/#{calendar.id}/private/full?"+query_string)
|
426
438
|
ret = []
|
data/lib/gcal4ruby/recurrence.rb
CHANGED
@@ -3,6 +3,11 @@ class Time
|
|
3
3
|
def complete
|
4
4
|
self.utc.strftime("%Y%m%dT%H%M%S")
|
5
5
|
end
|
6
|
+
|
7
|
+
def self.parse_complete(value)
|
8
|
+
d, h = value.split("T")
|
9
|
+
return Time.parse(d+" "+h.gsub("Z", ""))
|
10
|
+
end
|
6
11
|
end
|
7
12
|
|
8
13
|
module GCal4Ruby
|
@@ -22,15 +27,59 @@ module GCal4Ruby
|
|
22
27
|
#True if the event is all day (i.e. no start/end time)
|
23
28
|
attr_accessor :all_day
|
24
29
|
|
25
|
-
#Returns a new Recurrence object
|
26
|
-
def initialize
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
#Accepts an optional attributes hash or a string containing a properly formatted ISO 8601 recurrence rule. Returns a new Recurrence object
|
31
|
+
def initialize(vars = {})
|
32
|
+
if vars.is_a? Hash
|
33
|
+
vars.each do |key, value|
|
34
|
+
self.send("#{key}=", value)
|
35
|
+
end
|
36
|
+
elsif vars.is_a? String
|
37
|
+
self.load(vars)
|
38
|
+
end
|
39
|
+
@all_day ||= false
|
40
|
+
end
|
41
|
+
|
42
|
+
#Accepts a string containing a properly formatted ISO 8601 recurrence rule and loads it into the recurrence object
|
43
|
+
def load(rec)
|
44
|
+
attrs = rec.split("\n")
|
45
|
+
attrs.each do |val|
|
46
|
+
key, value = val.split(":")
|
47
|
+
case key
|
48
|
+
when 'DTSTART'
|
49
|
+
@start = Time.parse_complete(value)
|
50
|
+
when 'DTSTART;VALUE=DATE'
|
51
|
+
@start = Time.parse(value)
|
52
|
+
@all_day = true
|
53
|
+
when 'DTSTART;VALUE=DATE-TIME'
|
54
|
+
@start = Time.parse_complete(value)
|
55
|
+
when 'DTEND'
|
56
|
+
@end = Time.parse_complete(value)
|
57
|
+
when 'DTEND;VALUE=DATE'
|
58
|
+
@end = Time.parse(value)
|
59
|
+
when 'DTEND;VALUE=DATE-TIME'
|
60
|
+
@end = Time.parse_complete(value)
|
61
|
+
when 'RRULE'
|
62
|
+
vals = value.split(";")
|
63
|
+
key = ''
|
64
|
+
by = ''
|
65
|
+
int = nil
|
66
|
+
vals.each do |rr|
|
67
|
+
a, h = rr.split("=")
|
68
|
+
case a
|
69
|
+
when 'FREQ'
|
70
|
+
key = h.downcase.capitalize
|
71
|
+
when 'INTERVAL'
|
72
|
+
int = h
|
73
|
+
when 'UNTIL'
|
74
|
+
@repeat_until = Time.parse(value)
|
75
|
+
else
|
76
|
+
by = h.split(",")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
@frequency = {key => by}
|
80
|
+
@frequency.merge({'interval' => int}) if int
|
81
|
+
end
|
82
|
+
end
|
34
83
|
end
|
35
84
|
|
36
85
|
#Returns a string with the correctly formatted ISO 8601 recurrence rule
|
@@ -75,7 +124,7 @@ module GCal4Ruby
|
|
75
124
|
when "monthly"
|
76
125
|
by += "BYDAY=#{value};"
|
77
126
|
when "yearly"
|
78
|
-
by += "BYYEARDAY=#{value}"
|
127
|
+
by += "BYYEARDAY=#{value};"
|
79
128
|
when 'interval'
|
80
129
|
i += "INTERVAL=#{value};"
|
81
130
|
end
|
@@ -83,7 +132,7 @@ module GCal4Ruby
|
|
83
132
|
output += f+i+by
|
84
133
|
end
|
85
134
|
if @repeat_until
|
86
|
-
output += "
|
135
|
+
output += "UNTIL=#{@repeat_until.strftime("%Y%m%d")}"
|
87
136
|
end
|
88
137
|
|
89
138
|
output += "\n"
|
@@ -136,7 +185,7 @@ module GCal4Ruby
|
|
136
185
|
#- *Monthly*: A value of a positive or negative integer (i.e. +1) prepended to a day-of-week string ('TU') to indicate the position of the day within the month. E.g. +1TU would be the first tuesday of the month.
|
137
186
|
#- *Yearly*: A value of 1 to 366 indicating the day of the year. May be negative to indicate counting down from the last day of the year.
|
138
187
|
#
|
139
|
-
#Optionally, you may specific a second hash pair to set the
|
188
|
+
#Optionally, you may specific a second hash pair to set the interval the event repeats:
|
140
189
|
# "interval" => '2'
|
141
190
|
#If the interval is missing, it is assumed to be 1.
|
142
191
|
#
|
data/lib/gcal4ruby/service.rb
CHANGED
@@ -29,9 +29,13 @@ class Service < Base
|
|
29
29
|
# adequate permissions
|
30
30
|
attr_accessor :check_public
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
32
|
+
#Accepts an optional attributes hash for initialization values
|
33
|
+
def initialize(attributes = {})
|
34
|
+
super()
|
35
|
+
attributes.each do |key, value|
|
36
|
+
self.send("#{key}=", value)
|
37
|
+
end
|
38
|
+
@check_public ||= true
|
35
39
|
end
|
36
40
|
|
37
41
|
# The authenticate method passes the username and password to google servers.
|
data/test/unit.rb
CHANGED
@@ -23,6 +23,7 @@ def tester
|
|
23
23
|
service_test
|
24
24
|
calendar_test
|
25
25
|
event_test
|
26
|
+
event_recurrence_test
|
26
27
|
end
|
27
28
|
|
28
29
|
def service_test
|
@@ -127,6 +128,44 @@ def event_test
|
|
127
128
|
end
|
128
129
|
end
|
129
130
|
|
131
|
+
def event_recurrence_test
|
132
|
+
puts "---Starting Event Recurrence Test---"
|
133
|
+
|
134
|
+
@first_start = Time.now
|
135
|
+
@first_end = Time.now+3600
|
136
|
+
@first_freq = {'weekly' => ['TU']}
|
137
|
+
@second_start = Time.now+86000
|
138
|
+
@second_end = Time.now+89600
|
139
|
+
@second_freq = {'weekly' => ['SA']}
|
140
|
+
|
141
|
+
puts "1. Create Recurring Event"
|
142
|
+
event = Event.new(@service.calendars[0])
|
143
|
+
event.title = "Test Recurring Event"
|
144
|
+
event.content = "Test event content"
|
145
|
+
event.recurrence = Recurrence.new({:start => @first_start, :end => @first_end, :frequency => @first_freq})
|
146
|
+
if event.save
|
147
|
+
successful event.to_xml
|
148
|
+
else
|
149
|
+
failed("recurrence = "+event.recurrence.to_s)
|
150
|
+
end
|
151
|
+
|
152
|
+
puts "2. Edit Recurrence"
|
153
|
+
event.title = "Edited recurring title"
|
154
|
+
event.recurrence = Recurrence.new({:start => @second_start, :end => @second_end, :frequency => @second_freq})
|
155
|
+
if event.save
|
156
|
+
successful event.to_xml
|
157
|
+
else
|
158
|
+
failed
|
159
|
+
end
|
160
|
+
|
161
|
+
puts "3. Delete Event"
|
162
|
+
if event.delete
|
163
|
+
successful
|
164
|
+
else
|
165
|
+
failed
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
130
169
|
def failed(m = nil)
|
131
170
|
puts "Test Failed"
|
132
171
|
puts m if m
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gcal4ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Reich
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-01-
|
12
|
+
date: 2010-01-25 00:00:00 +11:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|