class Vpim::Icalendar

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:

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.

Public Class Methods

create(fields=[]) click to toggle source

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.

# File lib/vpim/icalendar.rb, line 139
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) { |self| ... } click to toggle source

TODO

# Allows customization of calendar creation.
class Maker
  def initialize #:nodoc:
    @prodid = Vpim::PRODID
  end

  attr :prodid
end

# The producer ID defaults to Vpim::PRODID but you can set it to something # specific to your application.

# File lib/vpim/icalendar.rb, line 119
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=[]) click to toggle source

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.

# File lib/vpim/icalendar.rb, line 163
def Icalendar.create_reply(fields=[])
  fields << DirectoryInfo::Field.create('METHOD', 'REPLY')

  Icalendar.create(fields)
end
decode(cal, e = nil) click to toggle source

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.

# File lib/vpim/icalendar.rb, line 257
def Icalendar.decode(cal, e = nil)
  entities = Vpim.expand(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

Public Instance Methods

<<(component)
Alias for: push
add_event() { |event| ... } click to toggle source

Add an event to this calendar.

Yields an event maker, Icalendar::Vevent::Maker.

# File lib/vpim/icalendar.rb, line 99
def add_event(&block) #:yield:event
  push Vevent::Maker.make( &block )
end
calscale() click to toggle source

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.

# File lib/vpim/icalendar.rb, line 315
def calscale
  (@properties['CALSCALE'] || 'GREGORIAN').upcase
end
components(klass=Object) { |component| ... } click to toggle source

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.

# File lib/vpim/icalendar.rb, line 337
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) { |component| ... } click to toggle source

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.

# File lib/vpim/icalendar.rb, line 359
def each(klass=nil, &block) # :yield: component
  unless block
    return Enumerable::Enumerator.new(self, :each, klass)
  end
  components(klass, &block)
end
encode(width=nil) click to toggle source

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.

# File lib/vpim/icalendar.rb, line 182
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
Also aliased as: to_s
events() { |Vevent| ... } click to toggle source

Short-hand for each(Icalendar::Vevent).

# File lib/vpim/icalendar.rb, line 367
def events(&block) #:yield: Vevent
  each(Icalendar::Vevent, &block)
end
journals() { |Vjournal| ... } click to toggle source

Short-hand for each(Icalendar::Vjournal).

# File lib/vpim/icalendar.rb, line 377
def journals(&block) #:yield: Vjournal
  each(Icalendar::Vjournal, &block)
end
producer() click to toggle source

The value of the PRODID field, an unstructured string meant to identify the software which encoded the Calendar data.

# File lib/vpim/icalendar.rb, line 290
def producer
  #f = @properties.field('PRODID')
  #f && f.to_text
  @properties.text('PRODID').first
end
protocol() click to toggle source

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.

# File lib/vpim/icalendar.rb, line 304
def protocol
  m = @properties['METHOD']
  m ? m.upcase : m
end
protocol?(method) click to toggle source

Check if the protocol method is method

# File lib/vpim/icalendar.rb, line 205
def protocol?(method)
  Vpim::Methods.casecmp?(protocol, method)
end
push(component) click to toggle source

Push a calendar component onto the calendar.

# File lib/vpim/icalendar.rb, line 192
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
Also aliased as: <<
to_s(width=nil)
Alias for: encode
todos() { |Vtodo| ... } click to toggle source

Short-hand for each(Icalendar::Vtodo).

# File lib/vpim/icalendar.rb, line 372
def todos(&block) #:yield: Vtodo
  each(Icalendar::Vtodo, &block)
end
version() click to toggle source

The iCalendar version multiplied by 10 as an Integer. iCalendar must have a version of 20, and vCalendar must have a version of 10.

# File lib/vpim/icalendar.rb, line 277
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