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 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.
@@ -116,24 +116,26 @@ class Calendar
116
116
  #end
117
117
  end
118
118
 
119
- #Accepts a Service object. Returns the new Calendar if successful, otherwise raises the InvalidService
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
- @xml = CALENDAR_XML
127
- @service = service
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 = false
132
- @id = nil
133
- @hidden = false
134
- @timezone = "America/Los_Angeles"
135
- @color = "#2952A3"
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
 
@@ -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
- @xml = EVENT_XML
188
- @calendar = calendar
189
- @title = nil
190
- @content = nil
191
- @start = nil
192
- @end = nil
193
- @where = nil
194
- @transparency = "http://schemas.google.com/g/2005#event.opaque"
195
- @status = "http://schemas.google.com/g/2005#event.confirmed"
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
- es = calendar.service.send_get("http://www.google.com/calendar/feeds/#{calendar.id}/private/full?max-results=1000000")
384
- REXML::Document.new(es.read_body).root.elements.each("entry"){}.map do |entry|
385
- puts "element = "+entry.name if calendar.service.debug
386
- id = ''
387
- entry.elements.each("id") {|v| id = v.text}
388
- puts "id = #{id}" if calendar.service.debug
389
- if id == query
390
- Event.define_xml_namespaces(entry)
391
- event = Event.new(calendar)
392
- event.load("<?xml version='1.0' encoding='UTF-8'?>#{entry.to_s}")
393
- return event
394
- end
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#{single_events}" if single_events
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 = []
@@ -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
- @start = nil
28
- @end = nil
29
- @event = nil
30
- @day_of_week = nil
31
- @repeat_until = nil
32
- @frequency = nil
33
- @all_day = false
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 += ";UNTIL=#{@repeat_until.strftime("%Y%m%d")}"
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 internal the even repeats:
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
  #
@@ -29,9 +29,13 @@ class Service < Base
29
29
  # adequate permissions
30
30
  attr_accessor :check_public
31
31
 
32
- def initialize
33
- super
34
- @check_public = true
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.2.11
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-23 00:00:00 +11:00
12
+ date: 2010-01-25 00:00:00 +11:00
13
13
  default_executable:
14
14
  dependencies: []
15
15