Class | Icalendar::Component |
In: |
lib/icalendar/component.rb
|
Parent: | Icalendar::Base |
The body of the iCalendar object consists of a sequence of calendar properties and one or more calendar components. The calendar properties are attributes that apply to the calendar as a whole. The calendar components are collections of properties that express a particular calendar semantic. For example, the calendar component can specify an Event, a Todo, a Journal entry, Timezone information, or Freebusy time information, or an Alarm.
name | [R] | |
properties | [RW] | |
property_params | [RW] |
# File lib/icalendar/component.rb, line 26 26: def initialize(name) 27: @name = name 28: @components = Hash.new([]) 29: @properties = {} 30: @property_params = {} 31: 32: @@logger.info("New #{@name[1,@name.size].capitalize}...") 33: end
Make it protected so we can monitor usage…
# File lib/icalendar/component.rb, line 129 129: def Component.ical_component(*syms) 130: hash_accessor :components, syms 131: end
Define a set of methods defining a new property, which supports multiple values for the same property name.
# File lib/icalendar/component.rb, line 201 201: def Component.ical_multi_property(property, singular, plural) 202: property = "#{property}".strip.upcase 203: singular = "#{singular}".strip.downcase 204: plural = "#{plural}".strip.downcase 205: 206: getter = "#{plural}" 207: setter = "#{plural}=" 208: adder = "add_#{singular}" 209: remover = "remove_#{singular}" 210: query = "#{plural}?" 211: 212: # Set this key so the parser knows to use an array for 213: # storing this property type. 214: @@multi_properties["#{property}"] = true 215: 216: # Getter for whole array 217: unless instance_methods.include? getter 218: code = "def \#{getter}(*a)\nif a.empty?\nif @properties.has_key?(\"\#{property}\")\n@properties[\"\#{property}\"]\nelse\n[]\nend\nelse\nself.\#{setter}(a.first)\nend\nend\n" 219: 220: class_eval code, "component.rb", 186 221: end 222: 223: # Setter for whole array 224: unless instance_methods.include? setter 225: code = "def \#{setter}(a)\nif a.respond_to?(:to_ary)\na.to_ary.each do |val|\nunless val.respond_to?(:to_ical)\nraise(NotImplementedError, \"Property values do not support to_ical method!\")\nend\nend\n\n@properties[\"\#{property}\"] = a.to_ary\n\nelse\nraise ArgumentError, \"\#{getter} is a multi-property that must be an array! Use the \#{adder} method to add single entries.\"\nend\nend\n" 226: 227: class_eval code, "component.rb", 198 228: end 229: 230: # Query for any of these properties 231: unless instance_methods.include? query 232: code = "def \#{query}\n@properties.has_key?(\"\#{property}\")\nend\n" 233: 234: class_eval code, "component.rb", 210 235: end 236: 237: # Add another item to this properties array 238: unless instance_methods.include? adder 239: code = "def \#{adder}(val, params = {})\nunless val.respond_to?(:to_ical)\nraise(NotImplementedError, \"Property value object does not support to_ical method!\")\nend\n\nif @properties.has_key?(\"\#{property}\")\n@properties[\"\#{property}\"] << val\nelse\n@properties[\"\#{property}\"] = [val]\nend\nend\n" 240: 241: class_eval code, "component.rb", 228 242: alias_method("add_#{property.downcase}", "#{adder}") 243: end 244: 245: # Remove an item from this properties array 246: unless instance_methods.include? remover 247: code = "def \#{remover}(a)\nif @properties.has_key?(\"\#{property}\")\n@properties[\"\#{property}\"].delete(a)\nend\nend\n" 248: 249: class_eval code, "component.rb", 241 250: alias_method("remove_#{property.downcase}", "#{remover}") 251: end 252: 253: end
Define a set of methods supporting a new property
# File lib/icalendar/component.rb, line 134 134: def Component.ical_property(property, alias_name = nil, prop_name = nil) 135: 136: property = "#{property}".strip.downcase 137: getter = "#{property}" 138: setter = "#{property}=" 139: query = "#{property}?" 140: alias_name = "#{alias_name}".strip.downcase unless alias_name.nil? 141: 142: # If a prop_name was given then we use that for the actual storage 143: property = "#{prop_name}".strip.upcase unless prop_name.nil? 144: 145: # Change underscores in property name to a dash 146: property[/_/] = '-' if property =~ /_/ 147: 148: # All properties names are stored in caps... 149: property = property.upcase 150: 151: unless instance_methods.include? getter 152: code = "def \#{getter}(val = nil, params = {})\nif val.nil?\n@properties[\"\#{property}\"]\nelse\n# Set the value just like normal\nself.\#{setter}(val)\nend\nend\n" 153: 154: class_eval code, "component.rb", 155 155: alias_method("#{alias_name}", "#{getter}") unless alias_name.nil? 156: end 157: 158: unless instance_methods.include? setter 159: code = "def \#{setter}(val)\nunless val.respond_to?(:to_ical)\nraise(NotImplementedError, \"Value of type (\" + val.class.to_s + \") does not support to_ical method!\")\nend\n\n@properties[\"\#{property}\"] = val\nend\n" 160: 161: class_eval code, "component.rb", 171 162: 163: alias_method("#{alias_name}=", "#{setter}") unless alias_name.nil? 164: end 165: 166: unless instance_methods.include? query 167: code = "def \#{query}\n@properties.has_key?(\"\#{property}\")\nend\n" 168: 169: class_eval code, "component.rb", 183 170: 171: alias_method("#{alias_name}\?", "#{query}") unless alias_name.nil? 172: end 173: end
Add a sub-component to the current component object.
# File lib/icalendar/component.rb, line 36 36: def add_component(component) 37: key = (component.class.to_s.downcase + 's').gsub('icalendar::', '').to_sym 38: 39: unless @components.has_key? key 40: @components[key] = [] 41: end 42: 43: @components[key] << component 44: end
TODO: Look into the x-property, x-param stuff…
# File lib/icalendar/component.rb, line 118 118: def custom_property(name, value) 119: @properties[name] = value 120: end
# File lib/icalendar/component.rb, line 122 122: def multi_property?(name) 123: @@multi_properties.has_key?(name.upcase) 124: end
Print this icalendar component
# File lib/icalendar/component.rb, line 57 57: def print_component 58: s = "" 59: 60: # Begin a new component 61: s << "BEGIN:#{@name.upcase}\r\n" 62: 63: # Then the properties 64: print_properties(s) 65: 66: # Any custom body of the derived component 67: yield(s) 68: 69: # End of this component 70: s << "END:#{@name.upcase}\r\n" 71: end
Print the parameters for a specific property
# File lib/icalendar/component.rb, line 94 94: def print_parameter(s, key, value) 95: if @property_params.has_key?(key) 96: params = @property_params[key] 97: params.each do |key,val| 98: s << ";#{key}" 99: val = [ val ] unless val.respond_to?(:to_ary) 100: 101: # Possible parameter values 102: unless val.empty? 103: s << "=" 104: sep = "" # First entry comes after = sign, but then we need commas 105: val.each do |pval| 106: if pval.respond_to? :to_ical 107: s << sep << pval.to_ical 108: sep = "," 109: end 110: end 111: end 112: 113: end 114: end 115: end
Print this components properties
# File lib/icalendar/component.rb, line 74 74: def print_properties(s) 75: @properties.each do |key,value| 76: # Take out underscore for property names that conflicted 77: # with built-in words. 78: if key =~ /ip_.*/ 79: key = key[3..-1] 80: end 81: 82: # Property name 83: s << "#{key.upcase}" 84: 85: # Possible parameters 86: print_parameter(s, key, value) 87: 88: # Property value 89: s << ":#{value.to_ical}\r\n" 90: end 91: end
# File lib/icalendar/component.rb, line 333 333: def respond_to?(method_name) 334: unless method_name.to_s.downcase =~ /x-.*/ 335: super 336: end 337: 338: true 339: end
# File lib/icalendar/component.rb, line 48 48: def to_ical 49: print_component do |s| 50: @components.each_value do |comps| 51: comps.each { |component| s << component.to_ical } 52: end 53: end 54: end
# File lib/icalendar/component.rb, line 309 309: def method_missing(method_name, *args) 310: method_name = method_name.to_s.downcase 311: 312: unless method_name =~ /x_.*/ 313: raise NoMethodError 314: end 315: 316: val = args.first 317: 318: unless val.respond_to?(:to_ical) 319: raise(NotImplementedError, "Value of type (" + val.class.to_s + ") does not support to_ical method!") 320: end 321: 322: if method_name =~ /(.*)(=)/ # Its a setter 323: @properties[$1] = val 324: @@logger.debug("Setting #{$1} => #{val}") 325: else # Or its a getter 326: @@logger.debug("Getting #{method_name} => #{@properties[method_name]}") 327: return @properties[method_name] 328: end 329: end