class EventParser

Public Class Methods

new(calendar_content) click to toggle source
# File lib/event_parser.rb, line 5
def initialize(calendar_content)
  @calendar_content = calendar_content
end

Public Instance Methods

events() click to toggle source
# File lib/event_parser.rb, line 9
def events
  events = []

  get_events_in_calendar.each do |event|
    summary = parse_summary event
    starts_at = parse_starts_at event
    ends_at = parse_ends_at event

    if recurring_event? event
      recurring_dates = parse_recurring_dates(event)

      recurring_dates.each do |recurring_starts_at, recurring_ends_at|
        events << new_event(summary,
                            recurring_starts_at,
                            recurring_ends_at)
      end
    else
      events << new_event(summary,
                          starts_at,
                          ends_at)
    end
  end

  events
end

Private Instance Methods

add_days_to_time(time, days) click to toggle source
# File lib/event_parser.rb, line 118
def add_days_to_time(time, days)
  new_time = time + (days * 24 * 60 * 60)
  # required to keep the same hour after summer/winter time change
  if time.hour > new_time.hour
    new_time + 60 * 60
  elsif time.hour < new_time.hour
    new_time - 60 * 60
  else
    new_time
  end
end
get_events_in_calendar() click to toggle source
# File lib/event_parser.rb, line 43
def get_events_in_calendar
  beginnings = @calendar_content.split('BEGIN:VEVENT')
  events = []

  beginnings.each do |event_beginning|
    next unless event_beginning.include? 'END:VEVENT'

    events << event_beginning.split('END:VEVENT').first
  end

  events
end
is_date_excluded?(date, event) click to toggle source
# File lib/event_parser.rb, line 112
def is_date_excluded?(date, event)
  date_str = date.strftime '%Y%m%dT%I%M%S'
  not_excluded = /EXDATE[\w\/=;]*:#{date_str}/.match(event).nil?
  !not_excluded
end
new_event(summary, starts_at, ends_at) click to toggle source
# File lib/event_parser.rb, line 37
def new_event(summary, starts_at, ends_at)
  OpenStruct.new(summary: summary,
                 starts_at: starts_at,
                 ends_at: ends_at)
end
parse_ends_at(event) click to toggle source
# File lib/event_parser.rb, line 64
def parse_ends_at(event)
  Time.parse(/DTEND[\w\/=;\s]*:(\d+T\d+)/.match(event)[1])
end
parse_recurring_dates(event) click to toggle source
# File lib/event_parser.rb, line 72
def parse_recurring_dates(event)
  recurring_dates = {}
  starts_at = parse_starts_at event
  ends_at = parse_ends_at event
  summary = parse_summary event

  if event.include? 'RRULE:FREQ=WEEKLY;COUNT='
    count = /RRULE:FREQ=WEEKLY;COUNT=(\d+)/.match(event)[1].to_i

    count.times do |i|
      recurring_starts_at = add_days_to_time(starts_at, i * 7)
      recurring_ends_at = add_days_to_time(ends_at, i * 7)

      unless is_date_excluded?(recurring_starts_at, event)
        recurring_dates[recurring_starts_at] = recurring_ends_at
      end
    end

  elsif event.include? 'RRULE:FREQ=WEEKLY;UNTIL='
    until_time = Time.parse(/RRULE:FREQ=WEEKLY;UNTIL=(\d+T\d+)/.match(event)[1])

    last_starts_at = starts_at
    last_ends_at = ends_at

    while last_starts_at <= until_time
      unless is_date_excluded?(last_starts_at, event)
        recurring_dates[last_starts_at] = last_ends_at
      end

      last_starts_at = add_days_to_time(last_starts_at, 7)
      last_ends_at = add_days_to_time(last_ends_at, 7)
    end

  else
    raise "Unsupported recurring event type: #{summary}"
  end

  recurring_dates
end
parse_starts_at(event) click to toggle source
# File lib/event_parser.rb, line 60
def parse_starts_at(event)
  Time.parse(/DTSTART[\w\/=;\s]*:(\d+T\d+)/.match(event)[1])
end
parse_summary(event) click to toggle source
# File lib/event_parser.rb, line 56
def parse_summary(event)
  /SUMMARY:(.*)/.match(event)[1].strip
end
recurring_event?(event) click to toggle source
# File lib/event_parser.rb, line 68
def recurring_event?(event)
  event.include? 'RRULE:FREQ=WEEKLY;'
end