Class: RiCal::Parser

Inherits:
Object show all
Defined in:
lib/ri_cal/parser.rb

Overview

  • ©2009 Rick DeNatale

  • All rights reserved. Refer to the file README.txt for the license

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(io = StringIO.new("")) ⇒ Parser

:nodoc:



76
77
78
# File 'lib/ri_cal/parser.rb', line 76

def initialize(io = StringIO.new("")) #:nodoc:
  @io = io
end

Class Method Details

.params_and_value(string, optional_initial_semi = false) ⇒ Object

:nodoc:



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/ri_cal/parser.rb', line 35

def self.params_and_value(string, optional_initial_semi = false) #:nodoc:
  string = string.sub(/^:/,'')
  return [{}, string] unless optional_initial_semi || string.match(/^;/)
  segments = string.sub(';','').split(":")
  return [{}, string] if segments.length < 2
  quote_count = 0
  gathering_params = true
  params = []
  values = []
  segments.each do |segment|
    if gathering_params
      params << segment
      quote_count += segment.count("\"")
      gathering_params = (1 == quote_count % 2)
    else
      values << segment
    end
  end
  [parse_params(params.join(":")), values.join(":")]
end

.parse(io = StringIO.new("")) ⇒ Object

:nodoc:



80
81
82
# File 'lib/ri_cal/parser.rb', line 80

def self.parse(io = StringIO.new("")) #:nodoc:
  new(io).parse
end

.parse_params(string) ⇒ Object

:nodoc:



22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/ri_cal/parser.rb', line 22

def self.parse_params(string) #:nodoc:
  if string
    string.split(";").inject({}) { |result, val|
      m = /^(.+)=(.+)$/.match(val)
      raise "Invalid parameter value #{val.inspect}" unless m
      result[m[1]] = m[2]
      result 
    }
  else
    nil
  end
end

Instance Method Details

#buffer_or_lineObject

:nodoc:



72
73
74
# File 'lib/ri_cal/parser.rb', line 72

def buffer_or_line #:nodoc:
  @buffer ||= @io.readline.chomp
end

#invalidObject

:nodoc:

Raises:

  • (Exception)


84
85
86
# File 'lib/ri_cal/parser.rb', line 84

def invalid #:nodoc:
  raise Exception.new("Invalid icalendar file")
end

#next_lineObject

:nodoc:



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/ri_cal/parser.rb', line 6

def next_line #:nodoc:
  result = nil
  begin
    result = buffer_or_line
    @buffer = nil
    while /^\s/ =~ buffer_or_line
      result = "#{result}#{@buffer[1..-1]}"
      @buffer = nil
    end
  rescue EOFError
    return nil
  ensure
    return result
  end
end

#next_separated_lineObject

:nodoc:



67
68
69
70
# File 'lib/ri_cal/parser.rb', line 67

def next_separated_line #:nodoc:
  line = next_line
  line ? separate_line(line) : nil
end

#parseObject

:nodoc:



93
94
95
96
97
98
99
100
# File 'lib/ri_cal/parser.rb', line 93

def parse #:nodoc:
  result = []
  while start_line = next_line
    @parent_stack = []
    result << parse_one(start_line, nil)
  end
  result
end

#parse_one(start, parent_component) ⇒ Object

TODO: Need to parse non-standard component types (iana-token or x-name)



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/ri_cal/parser.rb', line 103

def parse_one(start, parent_component) #:nodoc:

  @parent_stack << parent_component
  if Hash === start
    first_line = start
  else
    first_line = separate_line(start)
  end
  invalid unless first_line[:name] == "BEGIN"
  result = case first_line[:value]
  when "VCALENDAR"
    RiCal::Component::Calendar.from_parser(self, parent_component)
  when "VEVENT"
    RiCal::Component::Event.from_parser(self, parent_component)
  when "VTODO"
    RiCal::Component::Todo.from_parser(self, parent_component)
  when "VJOURNAL"
    RiCal::Component::Journal.from_parser(self, parent_component)
  when "VFREEBUSY"
    RiCal::Component::Freebusy.from_parser(self, parent_component)
  when "VTIMEZONE"
    RiCal::Component::Timezone.from_parser(self, parent_component)
  when "VALARM"
    RiCal::Component::Alarm.from_parser(self, parent_component)
  when "DAYLIGHT"
    RiCal::Component::Timezone::DaylightPeriod.from_parser(self, parent_component)
  when "STANDARD"
    RiCal::Component::Timezone::StandardPeriod.from_parser(self, parent_component)
  else
    invalid
  end
  @parent_stack.pop
  result
end

#separate_line(string) ⇒ Object

:nodoc:



56
57
58
59
60
61
62
63
64
65
# File 'lib/ri_cal/parser.rb', line 56

def separate_line(string) #:nodoc:
  match = string.match(/^([^;:]*)(.*)$/)
  name = match[1]
  params, value = *Parser.params_and_value(match[2])
  {
    :name => name,
    :params => params,
    :value => value
  }
end

#still_in(component, separated_line) ⇒ Object

:nodoc:



88
89
90
91
# File 'lib/ri_cal/parser.rb', line 88

def still_in(component, separated_line) #:nodoc:
  invalid unless separated_line
  separated_line[:value] != component || separated_line[:name] != "END"
end