class Icalendar::Parser
Constants
- BAD_LINE
- BAD_LINE_REGEX
- CLEAN_BAD_WRAPPING_GSUB_REGEX
- GET_WRAPPER_CLASS_GSUB_REGEX
- LINE
- LINE_REGEX
- NAME
- NEXT_FIELDS_TAB_REGEX
- NEXT_FIELDS_WHITESPACE_REGEX
- PARAM
- PARAM_REGEX
- PARSE_COMPONENT_KLASS_NAME_GSUB_REGEX
- PTEXT
- PVALUE
- PVALUE_GSUB_REGEX
- PVALUE_REGEX
- QSTR
- VALUE
- WRAP_IN_ARRAY_REGEX_1
- WRAP_IN_ARRAY_REGEX_2
- WRAP_PROPERTY_VALUE_DELIMETER_REGEX
- WRAP_PROPERTY_VALUE_SPLIT_REGEX
Attributes
component_class[W]
source[R]
strict[R]
timezone_store[R]
verbose[R]
Public Class Methods
clean_bad_wrapping(source)
click to toggle source
# File lib/icalendar/parser.rb, line 14 def self.clean_bad_wrapping(source) content = if source.respond_to? :read source.read elsif source.respond_to? :to_s source.to_s else msg = 'Icalendar::Parser.clean_bad_wrapping must be called with a String or IO object' Icalendar.fatal msg fail ArgumentError, msg end encoding = content.encoding content.force_encoding(Encoding::ASCII_8BIT) content.gsub(CLEAN_BAD_WRAPPING_GSUB_REGEX, "").force_encoding(encoding) end
new(source, strict = false, verbose = false)
click to toggle source
# File lib/icalendar/parser.rb, line 29 def initialize(source, strict = false, verbose = false) if source.respond_to? :gets @source = source elsif source.respond_to? :to_s @source = StringIO.new source.to_s, 'r' else msg = 'Icalendar::Parser.new must be called with a String or IO object' Icalendar.fatal msg fail ArgumentError, msg end read_in_data @strict = strict @verbose = verbose @timezone_store = TimezoneStore.new end
Public Instance Methods
get_wrapper_class(component, fields)
click to toggle source
# File lib/icalendar/parser.rb, line 110 def get_wrapper_class(component, fields) klass = component.class.default_property_types[fields[:name]] if !fields[:params]['value'].nil? klass_name = fields[:params].delete('value').first unless klass_name.upcase == klass.value_type klass_name = "Icalendar::Values::#{klass_name.downcase.gsub(GET_WRAPPER_CLASS_GSUB_REGEX) { |m| m[-1].upcase }}" klass = Object.const_get klass_name if Object.const_defined?(klass_name) end end klass end
parse()
click to toggle source
# File lib/icalendar/parser.rb, line 45 def parse components = [] while (fields = next_fields) component = component_class.new if fields[:name] == 'begin' && fields[:value].downcase == component.ical_name.downcase components << parse_component(component) end end components end
parse_property(component, fields = nil)
click to toggle source
# File lib/icalendar/parser.rb, line 56 def parse_property(component, fields = nil) fields = next_fields if fields.nil? prop_name = %w(class method name).include?(fields[:name]) ? "ip_#{fields[:name]}" : fields[:name] multi_property = component.class.multiple_properties.include? prop_name prop_value = wrap_property_value component, fields, multi_property begin method_name = if multi_property "append_#{prop_name}" else "#{prop_name}=" end component.send method_name, prop_value rescue NoMethodError => nme if strict? Icalendar.logger.error "No method \"#{method_name}\" for component #{component}" raise nme else Icalendar.logger.warn "No method \"#{method_name}\" for component #{component}. Appending to custom." if verbose? component.append_custom_property prop_name, prop_value end end end
strict?()
click to toggle source
# File lib/icalendar/parser.rb, line 122 def strict? !!@strict end
verbose?()
click to toggle source
# File lib/icalendar/parser.rb, line 126 def verbose? @verbose end
wrap_in_array?(klass, value, multi_property)
click to toggle source
# File lib/icalendar/parser.rb, line 103 def wrap_in_array?(klass, value, multi_property) klass.value_type != 'RECUR' && ((multi_property && value =~ WRAP_IN_ARRAY_REGEX_1) || value =~ WRAP_IN_ARRAY_REGEX_2) end
wrap_property_value(component, fields, multi_property)
click to toggle source
# File lib/icalendar/parser.rb, line 83 def wrap_property_value(component, fields, multi_property) klass = get_wrapper_class component, fields if wrap_in_array? klass, fields[:value], multi_property delimiter = fields[:value].match(WRAP_PROPERTY_VALUE_DELIMETER_REGEX)[1] Icalendar::Values::Helpers::Array.new fields[:value].split(WRAP_PROPERTY_VALUE_SPLIT_REGEX), klass, fields[:params], delimiter: delimiter else klass.new fields[:value], fields[:params] end rescue Icalendar::Values::DateTime::FormatError => fe raise fe if strict? fields[:params]['value'] = ['DATE'] retry end
Private Instance Methods
component_class()
click to toggle source
# File lib/icalendar/parser.rb, line 132 def component_class @component_class ||= Icalendar::Calendar end
next_fields()
click to toggle source
# File lib/icalendar/parser.rb, line 168 def next_fields line = @data or return nil loop do read_in_data if @data =~ NEXT_FIELDS_TAB_REGEX line << @data[1, @data.size] elsif @data !~ NEXT_FIELDS_WHITESPACE_REGEX break end end parse_fields line end
parse_component(component)
click to toggle source
# File lib/icalendar/parser.rb, line 138 def parse_component(component) while (fields = next_fields) if fields[:name] == 'end' klass_name = fields[:value].gsub(PARSE_COMPONENT_KLASS_NAME_GSUB_REGEX, '').downcase.capitalize timezone_store.store(component) if klass_name == 'Timezone' break elsif fields[:name] == 'begin' klass_name = fields[:value].gsub(PARSE_COMPONENT_KLASS_NAME_GSUB_REGEX, '').gsub("-", "_").downcase.capitalize Icalendar.logger.debug "Adding component #{klass_name}" if Object.const_defined? "Icalendar::#{klass_name}" component.add_component parse_component(Object.const_get("Icalendar::#{klass_name}").new) elsif Object.const_defined? "Icalendar::Timezone::#{klass_name}" component.add_component parse_component(Object.const_get("Icalendar::Timezone::#{klass_name}").new) else component.add_custom_component klass_name, parse_component(Component.new klass_name.downcase, fields[:value]) end else parse_property component, fields end end component end
parse_fields(input)
click to toggle source
# File lib/icalendar/parser.rb, line 195 def parse_fields(input) if parts = LINE_REGEX.match(input) value = parts[:value] else parts = BAD_LINE_REGEX.match(input) unless strict? parts or fail "Invalid iCalendar input line: #{input}" # Non-strict and bad line so use a value of empty string value = '' end params = {} parts[:params].scan PARAM_REGEX do |match| param_name = match[0].downcase params[param_name] ||= [] match[1].scan PVALUE_REGEX do |param_value| if param_value.size > 0 param_value = param_value.gsub(PVALUE_GSUB_REGEX, '') params[param_name] << param_value if param_name == 'tzid' params['x-tz-store'] = timezone_store end end end end # Building the string to send to the logger is expensive. # Only do it if the logger is at the right log level. if ::Logger::DEBUG >= Icalendar.logger.level Icalendar.logger.debug "Found fields: #{parts.inspect} with params: #{params.inspect}" end { name: parts[:name].downcase.gsub('-', '_'), params: params, value: value } end
read_in_data()
click to toggle source
# File lib/icalendar/parser.rb, line 161 def read_in_data @data = source.gets and @data.chomp! end