Class: RiCal::Parser
Overview
:nodoc:
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:
78 79 80 |
# File 'lib/ri_cal/parser.rb', line 78 def initialize(io = StringIO.new("")) #:nodoc: @io = io end |
Instance Attribute Details
#last_line_str ⇒ Object (readonly)
:nodoc:
3 4 5 |
# File 'lib/ri_cal/parser.rb', line 3 def last_line_str @last_line_str end |
Class Method Details
.params_and_value(string, optional_initial_semi = false) ⇒ Object
:nodoc:
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/ri_cal/parser.rb', line 36 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:
82 83 84 |
# File 'lib/ri_cal/parser.rb', line 82 def self.parse(io = StringIO.new("")) #:nodoc: new(io).parse end |
.parse_params(string) ⇒ Object
:nodoc:
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/ri_cal/parser.rb', line 20 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:
74 75 76 |
# File 'lib/ri_cal/parser.rb', line 74 def buffer_or_line #:nodoc: @buffer ||= @io.readline.chomp end |
#invalid ⇒ Object
:nodoc:
86 87 88 |
# File 'lib/ri_cal/parser.rb', line 86 def invalid #:nodoc: raise "Invalid icalendar file" end |
#next_line ⇒ Object
:nodoc:
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# File 'lib/ri_cal/parser.rb', line 4 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:
69 70 71 72 |
# File 'lib/ri_cal/parser.rb', line 69 def next_separated_line #:nodoc: line = next_line line ? separate_line(line) : nil end |
#parse ⇒ Object
:nodoc:
95 96 97 98 99 100 101 102 103 |
# File 'lib/ri_cal/parser.rb', line 95 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)
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 137 138 139 140 |
# File 'lib/ri_cal/parser.rb', line 106 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:
57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/ri_cal/parser.rb', line 57 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:
90 91 92 93 |
# File 'lib/ri_cal/parser.rb', line 90 def still_in(component, separated_line) #:nodoc: invalid unless separated_line separated_line[:value] != component || separated_line[:name] != "END" end |