Class: Vpim::Icalendar
- Inherits:
-
Object
- Object
- Vpim::Icalendar
- Includes:
- Enumerable, Vpim
- Defined in:
- lib/vpim/icalendar.rb,
lib/vpim/vtodo.rb,
lib/vpim/vevent.rb,
lib/vpim/address.rb,
lib/vpim/vjournal.rb,
lib/vpim/property/base.rb,
lib/vpim/property/common.rb,
lib/vpim/property/location.rb,
lib/vpim/property/priority.rb,
lib/vpim/property/resources.rb,
lib/vpim/property/recurrence.rb
Overview
An iCalendar.
A Calendar is some meta-information followed by a sequence of components.
Defined components are Event, Todo, Freebusy, Journal, and Timezone, each of which are represented by their own class, though they share many properties in common. For example, Event and Todo may both contain multiple Alarm components.
Reference
The iCalendar format is specified by a series of IETF documents:
-
RFC2445: Internet Calendaring and Scheduling Core Object Specification
-
RFC2446: iCalendar Transport-Independent Interoperability Protocol (iTIP) Scheduling Events, BusyTime, To-dos and Journal Entries
-
RFC2447: iCalendar Message-Based Interoperability Protocol
iCalendar and vCalendar
iCalendar files have VERSION:2.0 and vCalendar have VERSION:1.0. iCalendar (RFC 2445) is based on vCalendar, but is not very compatible. While much appears to be similar, the recurrence rule syntax is completely different.
iCalendars are usually transmitted in files with .ics
extensions.
Defined Under Namespace
Modules: Bnf, Property, Set Classes: Address, Vevent, Vjournal, Vtodo
Constant Summary
Constants included from Vpim
Class Method Summary collapse
-
.create(fields = []) ⇒ Object
Create a new Icalendar object with the minimal set of fields for a valid Calendar.
-
.create2(producer = Vpim::PRODID) ⇒ Object
The producer ID defaults to Vpim::PRODID but you can set it to something specific to your application.
-
.create_reply(fields = []) ⇒ Object
Create a new Icalendar object with a protocol method of REPLY.
-
.decode(cal, e = nil) ⇒ Object
Decode iCalendar data into an array of Icalendar objects.
-
.decode_duration(str) ⇒ Object
:nodoc:.
Instance Method Summary collapse
-
#add_event(&block) ⇒ Object
Add an event to this calendar.
-
#calscale ⇒ Object
The value of the CALSCALE: property, or “GREGORIAN” if CALSCALE: is not present.
-
#components(klass = Object) ⇒ Object
The array of all supported calendar components.
-
#each(klass = nil, &block) ⇒ Object
Enumerate the top-level calendar components.
-
#encode(width = nil) ⇒ Object
(also: #to_s)
Encode the Calendar as a string.
-
#events(&block) ⇒ Object
Short-hand for #each(Icalendar::Vevent).
-
#fields ⇒ Object
Used during encoding.
-
#initialize(fields) ⇒ Icalendar
constructor
Create a new Icalendar object from
fields
, an array of DirectoryInfo::Field objects. -
#journals(&block) ⇒ Object
Short-hand for #each(Icalendar::Vjournal).
-
#producer ⇒ Object
The value of the PRODID field, an unstructured string meant to identify the software which encoded the Calendar data.
-
#protocol ⇒ Object
The value of the METHOD field.
-
#protocol?(method) ⇒ Boolean
Check if the protocol method is
method
. -
#push(component) ⇒ Object
(also: #<<)
Push a calendar component onto the calendar.
-
#todos(&block) ⇒ Object
Short-hand for #each(Icalendar::Vtodo).
-
#version ⇒ Object
The iCalendar version multiplied by 10 as an Integer.
Methods included from Vpim
array_datetime_to_time, decode_date, decode_date_list, decode_date_time, decode_date_time_list, decode_date_time_to_datetime, decode_date_to_date, decode_integer, decode_list, decode_text, decode_text_list, decode_time, decode_time_list, decode_time_to_time, encode_date, encode_date_time, encode_paramtext, encode_paramvalue, encode_text, encode_text_list, encode_time, expand, outer_inner, unfold, version
Constructor Details
#initialize(fields) ⇒ Icalendar
Create a new Icalendar object from fields
, an array of DirectoryInfo::Field objects.
When decoding Calendar data, you would usually use Icalendar.decode(), which decodes the data into the field arrays, and calls this method for each Calendar it finds.
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/vpim/icalendar.rb', line 69 def initialize(fields) #:nodoc: # seperate into the outer-level fields, and the arrays of component # fields outer, inner = Vpim.outer_inner(fields) # Make a dirinfo out of outer, and check its an iCalendar @properties = DirectoryInfo.create(outer) @properties.check_begin_end('VCALENDAR') @components = [] # could use #constants instead of this factory = { 'VEVENT' => Vevent, 'VTODO' => Vtodo, 'VJOURNAL' => Vjournal, # TODO - VTIMEZONE } inner.each do |component| name = component.first.value if klass = factory[name] @components << klass.new(component) end end end |
Class Method Details
.create(fields = []) ⇒ Object
Create a new Icalendar object with the minimal set of fields for a valid Calendar. If specified, fields
must be an array of DirectoryInfo::Field objects to add. They can override the the default Calendar fields, so, for example, this can be used to set a custom PRODID field.
140 141 142 143 144 145 146 147 148 149 |
# File 'lib/vpim/icalendar.rb', line 140 def Icalendar.create(fields=[]) di = DirectoryInfo.create( [ DirectoryInfo::Field.create('VERSION', '2.0') ], 'VCALENDAR' ) DirectoryInfo::Field.create_array(fields).each { |f| di.push_unique f } di.push_unique DirectoryInfo::Field.create('PRODID', Vpim::PRODID) di.push_unique DirectoryInfo::Field.create('CALSCALE', "Gregorian") new(di.to_a) end |
.create2(producer = Vpim::PRODID) ⇒ Object
The producer ID defaults to Vpim::PRODID but you can set it to something specific to your application.
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/vpim/icalendar.rb', line 120 def Icalendar.create2(producer = Vpim::PRODID) #:yield: self # FIXME - make the primary API di = DirectoryInfo.create( [ DirectoryInfo::Field.create('VERSION', '2.0') ], 'VCALENDAR' ) di.push_unique DirectoryInfo::Field.create('PRODID', producer.to_str) di.push_unique DirectoryInfo::Field.create('CALSCALE', "Gregorian") cal = new(di.to_a) if block_given? yield cal end cal end |
.create_reply(fields = []) ⇒ Object
Create a new Icalendar object with a protocol method of REPLY.
Meeting requests, and such, are Calendar containers with a protocol method of REQUEST, and contains some number of Events, Todos, etc., that may need replying to. In order to reply to any of these components of a request, you must first build a Calendar object to hold your reply components.
This method builds the reply Calendar, you then will add to it replies to the specific components of the request Calendar that you are replying to. If you have any particular fields that you want to be in the Calendar, other than the defaults, then can be supplied as fields
, an array of Field objects.
164 165 166 167 168 |
# File 'lib/vpim/icalendar.rb', line 164 def Icalendar.create_reply(fields=[]) fields << DirectoryInfo::Field.create('METHOD', 'REPLY') Icalendar.create(fields) end |
.decode(cal, e = nil) ⇒ Object
Decode iCalendar data into an array of Icalendar objects.
Since iCalendars are self-delimited (by a BEGIN:VCALENDAR and an END:VCALENDAR), multiple iCalendars can be concatenated into a single file.
cal must be String or IO, or implement #each by returning each line in the input as those classes do.
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
# File 'lib/vpim/icalendar.rb', line 258 def Icalendar.decode(cal, e = nil) entities = Vpim.(Vpim.decode(cal)) # Since all iCalendars must have a begin/end, the top-level should # consist entirely of entities/arrays, even if its a single iCalendar. if entities.detect { |e| ! e.kind_of? Array } raise "Not a valid iCalendar" end calendars = [] entities.each do |e| calendars << new(e) end calendars end |
.decode_duration(str) ⇒ Object
:nodoc:
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
# File 'lib/vpim/icalendar.rb', line 210 def Icalendar.decode_duration(str) #:nodoc: unless match = %r{\s*#{Bnf::DURATION}\s*}.match(str) raise InvalidEncodingError, "duration not valid (#{str})" end dur = 0 # Remember: match[0] is the whole match string, match[1] is $1, etc. # Week if match[2] dur = match[2].to_i end # Days dur *= 7 if match[3] dur += match[3].to_i end # Hours dur *= 24 if match[4] dur += match[4].to_i end # Minutes dur *= 60 if match[5] dur += match[5].to_i end # Seconds dur *= 60 if match[6] dur += match[6].to_i end if match[1] && match[1] == '-' dur = -dur end dur end |
Instance Method Details
#add_event(&block) ⇒ Object
Add an event to this calendar.
Yields an event maker, Icalendar::Vevent::Maker.
100 101 102 |
# File 'lib/vpim/icalendar.rb', line 100 def add_event(&block) #:yield:event push Vevent::Maker.make( &block ) end |
#calscale ⇒ Object
The value of the CALSCALE: property, or “GREGORIAN” if CALSCALE: is not present.
This is of academic interest only. There aren’t any other calendar scales defined, and given that its hard enough just dealing with Gregorian calendars, there probably won’t be.
316 317 318 |
# File 'lib/vpim/icalendar.rb', line 316 def calscale (@properties['CALSCALE'] || 'GREGORIAN').upcase end |
#components(klass = Object) ⇒ Object
The array of all supported calendar components. If a class is provided, return only the components of that class.
If a block is provided, yield the components instead of returning them.
Examples:
calendar.components(Vpim::Icalendar::Vevent)
=> array of all calendar components
calendar.components(Vpim::Icalendar::Vtodo) {|c| c... }
=> yield all todo components
calendar.components {|c| c... }
=> yield all components
Note - use of this is mildly deprecated in favour of #each, #events, #todos, #journals because those won’t return timezones, and will return Enumerators if called without a block.
338 339 340 341 342 343 344 345 346 347 348 349 350 351 |
# File 'lib/vpim/icalendar.rb', line 338 def components(klass=Object) #:yields:component klass ||= Object unless block_given? return @components.select{|c| klass === c}.freeze end @components.each do |c| if klass === c yield c end end self end |
#each(klass = nil, &block) ⇒ Object
Enumerate the top-level calendar components. Yields them if a block is provided, otherwise returns an Enumerator.
This skips components that are only internally meaningful to iCalendar, such as timezone definitions.
360 361 362 363 364 365 |
# File 'lib/vpim/icalendar.rb', line 360 def each(klass=nil, &block) # :yield: component unless block return Enumerable::Enumerator.new(self, :each, klass) end components(klass, &block) end |
#encode(width = nil) ⇒ Object Also known as: to_s
Encode the Calendar as a string. The width is the maximum width of the encoded lines, it can be specified, but is better left to the default.
183 184 185 186 187 188 |
# File 'lib/vpim/icalendar.rb', line 183 def encode(width=nil) # We concatenate the fields of all objects, create a DirInfo, then # encode it. di = DirectoryInfo.create(self.fields.flatten) di.encode(width) end |
#events(&block) ⇒ Object
Short-hand for #each(Icalendar::Vevent).
368 369 370 |
# File 'lib/vpim/icalendar.rb', line 368 def events(&block) #:yield: Vevent each(Icalendar::Vevent, &block) end |
#fields ⇒ Object
Used during encoding.
171 172 173 174 175 176 177 178 179 |
# File 'lib/vpim/icalendar.rb', line 171 def fields # :nodoc: f = @properties.to_a last = f.pop # Use of #each means we won't encode components in our View, but also # that we won't encode timezones... but we don't decode/support timezones # anyhow, so fix later. each { |c| f << c.fields } f.push last end |
#journals(&block) ⇒ Object
Short-hand for #each(Icalendar::Vjournal).
378 379 380 |
# File 'lib/vpim/icalendar.rb', line 378 def journals(&block) #:yield: Vjournal each(Icalendar::Vjournal, &block) end |
#producer ⇒ Object
The value of the PRODID field, an unstructured string meant to identify the software which encoded the Calendar data.
291 292 293 294 295 |
# File 'lib/vpim/icalendar.rb', line 291 def producer #f = @properties.field('PRODID') #f && f.to_text @properties.text('PRODID').first end |
#protocol ⇒ Object
The value of the METHOD field. Protocol methods are used when iCalendars are exchanged in a calendar messaging system, such as iTIP or iMIP. When METHOD is not specified, the Calendar object is merely being used to transport a snapshot of some calendar information; without the intention of conveying a scheduling semantic.
Note that this method can’t be called method
, thats already a method of Object.
305 306 307 308 |
# File 'lib/vpim/icalendar.rb', line 305 def protocol m = @properties['METHOD'] m ? m.upcase : m end |
#protocol?(method) ⇒ Boolean
Check if the protocol method is method
206 207 208 |
# File 'lib/vpim/icalendar.rb', line 206 def protocol?(method) Vpim::Methods.casecmp?(protocol, method) end |
#push(component) ⇒ Object Also known as: <<
Push a calendar component onto the calendar.
193 194 195 196 197 198 199 200 201 |
# File 'lib/vpim/icalendar.rb', line 193 def push(component) case component when Vevent, Vtodo, Vjournal @components << component else raise ArgumentError, "can't add a #{component.type} to a calendar" end self end |
#todos(&block) ⇒ Object
Short-hand for #each(Icalendar::Vtodo).
373 374 375 |
# File 'lib/vpim/icalendar.rb', line 373 def todos(&block) #:yield: Vtodo each(Icalendar::Vtodo, &block) end |
#version ⇒ Object
The iCalendar version multiplied by 10 as an Integer. iCalendar must have a version of 20, and vCalendar must have a version of 10.
278 279 280 281 282 283 284 285 286 287 |
# File 'lib/vpim/icalendar.rb', line 278 def version v = @properties['VERSION'] unless v raise InvalidEncodingError, "Invalid calendar, no version field!" end v = v.to_f * 10 v = v.to_i end |