module ICalPal

def self.call(klass)

Returns:
  • (Class) - The subclass of ICalPal

Parameters:
  • klass (String) -- One of +accounts+, +stores+, +calendars+, +events+, or +tasks+
def self.call(klass)
  case klass
  when 'accounts', 'stores' then Store
  when 'calendars' then Calendar
  when 'events' then Event
  when 'tasks' then Reminder
  else
    $log.fatal("Unknown class: #{klass}")
    exit
  end
end

def self.load_data(db_file, q)

Load data
def self.load_data(db_file, q)
  $log.debug(q.gsub("\n", ' '))
  rows = []
  begin
    # Open the database
    $log.debug("Opening database: #{db_file}")
    db = SQLite3::Database.new(db_file, { readonly: true, results_as_hash: true })
    # Prepare the query
    stmt = db.prepare(q)
    abort(stmt.columns.sort.join(' ')) if $opts[:props].any? 'list'
    $opts[:props] = stmt.columns - $opts[:eep] if $opts[:props].any? 'all'
    # Iterate the SQLite3::ResultSet once
    stmt.execute.each_with_index { |i, j| rows[j] = i }
    stmt.close
    # Close the database
    db.close
    $log.debug("Closed #{db_file}")
  rescue SQLite3::BusyException => e
    $log.error("Non-fatal error closing database #{db.filename}")
    raise e
  rescue SQLite3::CantOpenException => e
    $log.debug("Can't open #{db_file}")
    raise e
  rescue SQLite3::SQLException => e
    $log.info("#{db_file}: #{e}")
    raise e
  rescue SQLite3::Exception => e
    abort("#{db_file}: #{e}")
  end
  rows
end

def self.nth(n, dow, m)

Returns:
  • (RDT) - The resulting day

Parameters:
  • m (RDT) -- The RDT with the year and month we're searching
  • dow (Integer) -- Day of the week
  • n (Integer) -- Integer between -4 and +4
def self.nth(n, dow, m)
  # Get the number of days in the month by advancing to the first of
  # the next month, then going back one day
  a = [ RDT.new(m.year, m.month, 1, m.hour, m.minute, m.second) ]
  a[1] = (a[0] >> 1) - 1
  # Reverse it if going backwards
  a.reverse! if n.negative?
  step = a[1] <=> a[0]
  j = 0
  a[0].step(a[1], step) do |i|
    j += step if dow == i.wday
    return i if j == n
  end
end

def [](k)

@!group Accessors
def [](k)
  @self[k]
end

def []=(k, v)

def []=(k, v)
  @self[k] = v
end

def dump

Returns:
  • (Array) - @self as a key=value array, sorted by key
def dump
  @self.keys.sort.map { |k| "#{k}: #{@self[k]}" }
end

def initialize(obj)

Parameters:
  • obj (ICalPal) -- A +Store+ or +Calendar+
def initialize(obj)
  obj['type'] = EventKit::EKSourceType.find_index { |i| i[:name] == 'Subscribed' } if obj['subcal_url']
  type = EventKit::EKSourceType[obj['type']]
  obj['store'] = obj['account']
  obj['type'] = type[:name]
  obj['color'] ||= type[:color]
  obj['symbolic_color_name'] ||= type[:color]
  @self = obj
end

def keys

def keys
  @self.keys
end

def to_csv(headers)

Returns:
  • (CSV::Row) - The +Store+, +Calendar+, or +CalendarItem+ as a CSV::Row

Parameters:
  • headers (Array) -- Key names used as the header row in a CSV::Table
def to_csv(headers)
  values = headers.map { |h| (@self[h].respond_to?(:gsub))? @self[h].gsub("\n", '\n') : @self[h] }
  CSV::Row.new(headers, values)
end

def to_xml

Returns:
  • (String) - All fields in a simple XML format: value.
def to_xml
  retval = ''
  @self.each_key { |k| retval += xmlify(k, @self[k]) }
  retval
end

def values

def values
  @self.values
end