Class: RiCal::Parser
Overview
-
©2009 Rick DeNatale
-
All rights reserved. Refer to the file README.txt for the license
Instance Attribute Summary collapse
-
#last_line_str ⇒ Object
readonly
:nodoc:.
Class Method Summary collapse
-
.params_and_value(string, optional_initial_semi = false) ⇒ Object
:nodoc:.
-
.parse(io = StringIO.new("")) ⇒ Object
:nodoc:.
-
.parse_params(string) ⇒ Object
:nodoc:.
Instance Method Summary collapse
-
#buffer_or_line ⇒ Object
:nodoc:.
-
#initialize(io = StringIO.new("")) ⇒ Parser
constructor
:nodoc:.
-
#invalid ⇒ Object
:nodoc:.
-
#next_line ⇒ Object
:nodoc:.
-
#next_separated_line ⇒ Object
:nodoc:.
-
#parse ⇒ Object
:nodoc:.
-
#parse_one(start, parent_component) ⇒ Object
TODO: Need to parse non-standard component types (iana-token or x-name).
-
#separate_line(string) ⇒ Object
:nodoc:.
-
#still_in(component, separated_line) ⇒ Object
:nodoc:.
Constructor Details
#initialize(io = StringIO.new("")) ⇒ Parser
:nodoc:
81 82 83 |
# File 'lib/ri_cal/parser.rb', line 81 def initialize(io = StringIO.new("")) #:nodoc: @io = io end |
Instance Attribute Details
#last_line_str ⇒ Object (readonly)
:nodoc:
6 7 8 |
# File 'lib/ri_cal/parser.rb', line 6 def last_line_str @last_line_str end |
Class Method Details
.params_and_value(string, optional_initial_semi = false) ⇒ Object
:nodoc:
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/ri_cal/parser.rb', line 39 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(":", -1) 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:
85 86 87 |
# File 'lib/ri_cal/parser.rb', line 85 def self.parse(io = StringIO.new("")) #:nodoc: new(io).parse end |
.parse_params(string) ⇒ Object
:nodoc:
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/ri_cal/parser.rb', line 23 def self.parse_params(string) #:nodoc: if string string.split(";").inject({}) { |result, val| m = /^(.+)=(.+)$/.match(val) raise "Invalid parameter value #{val.inspect}" unless m #TODO - The gsub below is a simplest fix for http://rick_denatale.lighthouseapp.com/projects/30941/tickets/19 # it may need further examination if more pathological cases show up. param_val = m[2].sub(/^\"(.*)\"$/, '\1') result[m[1]] = param_val result } else nil end end |
Instance Method Details
#buffer_or_line ⇒ Object
:nodoc:
77 78 79 |
# File 'lib/ri_cal/parser.rb', line 77 def buffer_or_line #:nodoc: @buffer ||= @io.readline.chomp end |
#invalid ⇒ Object
:nodoc:
89 90 91 |
# File 'lib/ri_cal/parser.rb', line 89 def invalid #:nodoc: raise Exception.new("Invalid icalendar file") end |
#next_line ⇒ Object
:nodoc:
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# File 'lib/ri_cal/parser.rb', line 7 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_line ⇒ Object
:nodoc:
72 73 74 75 |
# File 'lib/ri_cal/parser.rb', line 72 def next_separated_line #:nodoc: line = next_line line ? separate_line(line) : nil end |
#parse ⇒ Object
:nodoc:
98 99 100 101 102 103 104 105 106 |
# File 'lib/ri_cal/parser.rb', line 98 def parse #:nodoc: result = [] while start_line = next_line @parent_stack = [] component = parse_one(start_line, nil) result << component if component end result end |
#parse_one(start, parent_component) ⇒ Object
TODO: Need to parse non-standard component types (iana-token or x-name)
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 137 138 139 140 141 142 143 |
# File 'lib/ri_cal/parser.rb', line 109 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" entity_name = first_line[:value] result = case entity_name when "VCALENDAR" RiCal::Component::Calendar.from_parser(self, parent_component, entity_name) when "VEVENT" RiCal::Component::Event.from_parser(self, parent_component, entity_name) when "VTODO" RiCal::Component::Todo.from_parser(self, parent_component, entity_name) when "VJOURNAL" RiCal::Component::Journal.from_parser(self, parent_component, entity_name) when "VFREEBUSY" RiCal::Component::Freebusy.from_parser(self, parent_component, entity_name) when "VTIMEZONE" RiCal::Component::Timezone.from_parser(self, parent_component, entity_name) when "VALARM" RiCal::Component::Alarm.from_parser(self, parent_component, entity_name) when "DAYLIGHT" RiCal::Component::Timezone::DaylightPeriod.from_parser(self, parent_component, entity_name) when "STANDARD" RiCal::Component::Timezone::StandardPeriod.from_parser(self, parent_component, entity_name) else RiCal::Component::NonStandard.from_parser(self, parent_component, entity_name) end @parent_stack.pop result end |
#separate_line(string) ⇒ Object
:nodoc:
60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/ri_cal/parser.rb', line 60 def separate_line(string) #:nodoc: match = string.match(/^([^;:]*)(.*)$/) name = match[1] @last_line_str = string params, value = *Parser.params_and_value(match[2]) { :name => name, :params => params, :value => value, } end |
#still_in(component, separated_line) ⇒ Object
:nodoc:
93 94 95 96 |
# File 'lib/ri_cal/parser.rb', line 93 def still_in(component, separated_line) #:nodoc: invalid unless separated_line separated_line[:value] != component || separated_line[:name] != "END" end |