Class: Icalendar::Parser

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

Defined Under Namespace

Classes: ParseError

Constant Summary collapse

CLEAN_BAD_WRAPPING_GSUB_REGEX =
/\r?\n[ \t]/.freeze
WRAP_PROPERTY_VALUE_DELIMETER_REGEX =
/(?<!\\)([,;])/.freeze
WRAP_PROPERTY_VALUE_SPLIT_REGEX =
/(?<!\\)[;,]/.freeze
WRAP_IN_ARRAY_REGEX_1 =
/(?<!\\)[,;]/.freeze
WRAP_IN_ARRAY_REGEX_2 =
/(?<!\\);/.freeze
GET_WRAPPER_CLASS_GSUB_REGEX =
/(?:\A|-)(.)/.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(source, strict = false, verbose = false) ⇒ Parser

Returns a new instance of Parser.



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# 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

Instance Attribute Details

#component_class=(value) ⇒ Object

Sets the attribute component_class

Parameters:

  • value

    the value to set the attribute component_class to.



9
10
11
# File 'lib/icalendar/parser.rb', line 9

def component_class=(value)
  @component_class = value
end

#sourceObject (readonly)

Returns the value of attribute source.



10
11
12
# File 'lib/icalendar/parser.rb', line 10

def source
  @source
end

#strictObject (readonly)

Returns the value of attribute strict.



10
11
12
# File 'lib/icalendar/parser.rb', line 10

def strict
  @strict
end

#timezone_storeObject (readonly)

Returns the value of attribute timezone_store.



10
11
12
# File 'lib/icalendar/parser.rb', line 10

def timezone_store
  @timezone_store
end

#verboseObject (readonly)

Returns the value of attribute verbose.



10
11
12
# File 'lib/icalendar/parser.rb', line 10

def verbose
  @verbose
end

Class Method Details

.clean_bad_wrapping(source) ⇒ Object



14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 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

Instance Method Details

#get_wrapper_class(component, fields) ⇒ Object



110
111
112
113
114
115
116
117
118
119
120
# 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

#parseObject



45
46
47
48
49
50
51
52
53
54
# 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) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# 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?Boolean

Returns:

  • (Boolean)


122
123
124
# File 'lib/icalendar/parser.rb', line 122

def strict?
  !!@strict
end

#verbose?Boolean

Returns:

  • (Boolean)


126
127
128
# File 'lib/icalendar/parser.rb', line 126

def verbose?
  @verbose
end

#wrap_in_array?(klass, value, multi_property) ⇒ Boolean

Returns:

  • (Boolean)


103
104
105
106
# 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) ⇒ Object



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# 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