icalendar 0.96.4 → 0.97

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. data/README +66 -53
  2. data/Rakefile +33 -24
  3. data/docs/api/classes/Array.html +9 -11
  4. data/docs/api/classes/Array.src/M000002.html +18 -0
  5. data/docs/api/classes/Date.html +2 -22
  6. data/docs/api/classes/Date.src/M000004.html +29 -0
  7. data/docs/api/classes/DateTime.html +2 -43
  8. data/docs/api/classes/DateTime.src/M000005.html +50 -0
  9. data/docs/api/classes/Fixnum.html +2 -11
  10. data/docs/api/classes/Fixnum.src/M000011.html +18 -0
  11. data/docs/api/classes/Float.html +2 -11
  12. data/docs/api/classes/Float.src/M000003.html +18 -0
  13. data/docs/api/classes/HashAttrs.html +15 -60
  14. data/docs/api/classes/HashAttrs.src/M000068.html +26 -0
  15. data/docs/api/classes/HashAttrs.src/M000069.html +27 -0
  16. data/docs/api/classes/HashAttrs.src/M000070.html +19 -0
  17. data/docs/api/classes/Icalendar/Alarm.html +5 -15
  18. data/docs/api/classes/Icalendar/Alarm.src/M000020.html +22 -0
  19. data/docs/api/classes/Icalendar/Base.html +41 -0
  20. data/docs/api/classes/Icalendar/Base.src/M000022.html +18 -0
  21. data/docs/api/classes/Icalendar/Base.src/M000023.html +18 -0
  22. data/docs/api/classes/Icalendar/Calendar.html +116 -116
  23. data/docs/api/classes/Icalendar/Calendar.src/M000054.html +23 -0
  24. data/docs/api/classes/Icalendar/Calendar.src/M000055.html +23 -0
  25. data/docs/api/classes/Icalendar/Calendar.src/M000056.html +18 -0
  26. data/docs/api/classes/Icalendar/Calendar.src/M000057.html +23 -0
  27. data/docs/api/classes/Icalendar/Calendar.src/M000058.html +18 -0
  28. data/docs/api/classes/Icalendar/Calendar.src/M000059.html +23 -0
  29. data/docs/api/classes/Icalendar/Calendar.src/M000060.html +18 -0
  30. data/docs/api/classes/Icalendar/Calendar.src/M000061.html +23 -0
  31. data/docs/api/classes/Icalendar/Calendar.src/M000062.html +18 -0
  32. data/docs/api/classes/Icalendar/Calendar.src/M000063.html +23 -0
  33. data/docs/api/classes/Icalendar/Calendar.src/M000064.html +19 -0
  34. data/docs/api/classes/Icalendar/Component.html +200 -367
  35. data/docs/api/classes/Icalendar/Component.src/M000029.html +22 -0
  36. data/docs/api/classes/Icalendar/Component.src/M000030.html +24 -0
  37. data/docs/api/classes/Icalendar/Component.src/M000035.html +22 -0
  38. data/docs/api/classes/Icalendar/Component.src/M000040.html +18 -0
  39. data/docs/api/classes/Icalendar/Component.src/M000041.html +24 -0
  40. data/docs/api/classes/Icalendar/Component.src/M000042.html +28 -0
  41. data/docs/api/classes/Icalendar/Component.src/M000043.html +37 -0
  42. data/docs/api/classes/Icalendar/Component.src/M000044.html +37 -0
  43. data/docs/api/classes/Icalendar/Component.src/M000045.html +18 -0
  44. data/docs/api/classes/Icalendar/Component.src/M000046.html +18 -0
  45. data/docs/api/classes/Icalendar/Component.src/M000047.html +18 -0
  46. data/docs/api/classes/Icalendar/Component.src/M000048.html +26 -0
  47. data/docs/api/classes/Icalendar/Component.src/M000049.html +29 -0
  48. data/docs/api/classes/Icalendar/Component.src/M000050.html +22 -0
  49. data/docs/api/classes/Icalendar/DateProp.html +2 -12
  50. data/docs/api/classes/Icalendar/DateProp.src/M000013.html +19 -0
  51. data/docs/api/classes/Icalendar/DateProp/ClassMethods.html +2 -59
  52. data/docs/api/classes/Icalendar/DateProp/ClassMethods.src/M000014.html +66 -0
  53. data/docs/api/classes/Icalendar/Daylight.html +5 -14
  54. data/docs/api/classes/Icalendar/Daylight.src/M000051.html +18 -0
  55. data/docs/api/classes/Icalendar/Event.html +30 -37
  56. data/docs/api/classes/Icalendar/Event.src/M000052.html +23 -0
  57. data/docs/api/classes/Icalendar/Event.src/M000053.html +23 -0
  58. data/docs/api/classes/Icalendar/Freebusy.html +5 -14
  59. data/docs/api/classes/Icalendar/Freebusy.src/M000065.html +21 -0
  60. data/docs/api/classes/Icalendar/Geo.html +192 -0
  61. data/docs/api/classes/Icalendar/Geo.src/M000024.html +19 -0
  62. data/docs/api/classes/Icalendar/Geo.src/M000025.html +18 -0
  63. data/docs/api/classes/Icalendar/Journal.html +2 -11
  64. data/docs/api/classes/Icalendar/Journal.src/M000016.html +22 -0
  65. data/docs/api/classes/Icalendar/Parameter.html +5 -23
  66. data/docs/api/classes/Icalendar/Parameter.src/M000066.html +27 -0
  67. data/docs/api/classes/Icalendar/Parser.html +36 -212
  68. data/docs/api/classes/Icalendar/Parser.src/M000017.html +32 -0
  69. data/docs/api/classes/Icalendar/Parser.src/M000018.html +43 -0
  70. data/docs/api/classes/Icalendar/Parser.src/M000019.html +33 -0
  71. data/docs/api/classes/Icalendar/Standard.html +2 -11
  72. data/docs/api/classes/Icalendar/Standard.src/M000015.html +18 -0
  73. data/docs/api/classes/Icalendar/Timezone.html +16 -48
  74. data/docs/api/classes/Icalendar/Timezone.src/M000026.html +19 -0
  75. data/docs/api/classes/Icalendar/Timezone.src/M000027.html +22 -0
  76. data/docs/api/classes/Icalendar/Timezone.src/M000028.html +18 -0
  77. data/docs/api/classes/Icalendar/Todo.html +5 -14
  78. data/docs/api/classes/Icalendar/Todo.src/M000021.html +22 -0
  79. data/docs/api/classes/Object.html +10 -59
  80. data/docs/api/classes/Object.src/M000006.html +20 -0
  81. data/docs/api/classes/Object.src/M000007.html +18 -0
  82. data/docs/api/classes/Object.src/M000008.html +20 -0
  83. data/docs/api/classes/Object.src/M000009.html +18 -0
  84. data/docs/api/classes/Object.src/M000010.html +18 -0
  85. data/docs/api/classes/String.html +2 -11
  86. data/docs/api/classes/String.src/M000012.html +18 -0
  87. data/docs/api/classes/Time.html +2 -26
  88. data/docs/api/classes/Time.src/M000001.html +37 -0
  89. data/docs/api/classes/URI/Generic.html +5 -14
  90. data/docs/api/classes/URI/Generic.src/M000067.html +18 -0
  91. data/docs/api/created.rid +1 -1
  92. data/docs/api/files/COPYING.html +1 -1
  93. data/docs/api/files/GPL.html +1 -1
  94. data/docs/api/files/README.html +76 -64
  95. data/docs/api/files/lib/hash_attrs_rb.html +1 -1
  96. data/docs/api/files/lib/icalendar/base_rb.html +1 -1
  97. data/docs/api/files/lib/icalendar/calendar_rb.html +1 -1
  98. data/docs/api/files/lib/icalendar/component/alarm_rb.html +1 -1
  99. data/docs/api/files/lib/icalendar/component/event_rb.html +1 -1
  100. data/docs/api/files/lib/icalendar/component/freebusy_rb.html +1 -1
  101. data/docs/api/files/lib/icalendar/component/journal_rb.html +1 -1
  102. data/docs/api/files/lib/icalendar/component/timezone_rb.html +1 -1
  103. data/docs/api/files/lib/icalendar/component/todo_rb.html +1 -1
  104. data/docs/api/files/lib/icalendar/component_rb.html +8 -1
  105. data/docs/api/files/lib/icalendar/conversions_rb.html +1 -1
  106. data/docs/api/files/lib/icalendar/helpers_rb.html +1 -1
  107. data/docs/api/files/lib/icalendar/parameter_rb.html +1 -1
  108. data/docs/api/files/lib/icalendar/parser_rb.html +2 -1
  109. data/docs/api/files/lib/icalendar_rb.html +1 -1
  110. data/docs/api/files/lib/meta_rb.html +1 -1
  111. data/docs/api/fr_class_index.html +1 -0
  112. data/docs/api/fr_method_index.html +57 -41
  113. data/docs/rfcs/itip_notes.txt +69 -0
  114. data/examples/create_cal.rb +33 -32
  115. data/examples/parse_cal.rb +2 -2
  116. data/lib/icalendar/base.rb +8 -0
  117. data/lib/icalendar/calendar.rb +32 -3
  118. data/lib/icalendar/component.rb +187 -113
  119. data/lib/icalendar/component/alarm.rb +3 -0
  120. data/lib/icalendar/component/event.rb +9 -3
  121. data/lib/icalendar/component/freebusy.rb +3 -0
  122. data/lib/icalendar/component/journal.rb +4 -0
  123. data/lib/icalendar/component/todo.rb +4 -0
  124. data/lib/icalendar/conversions.rb +7 -1
  125. data/lib/icalendar/parser.rb +68 -90
  126. data/test/calendar_test.rb +32 -8
  127. data/test/component/event_test.rb +4 -7
  128. data/test/component/todo_test.rb +13 -0
  129. data/test/component_test.rb +21 -34
  130. data/test/conversions_test.rb +66 -0
  131. data/test/coverage/-home-rosejn-projects-icalendar-lib-hash_attrs_rb.html +574 -0
  132. data/test/coverage/-home-rosejn-projects-icalendar-lib-icalendar-base_rb.html +575 -0
  133. data/test/coverage/-home-rosejn-projects-icalendar-lib-icalendar-calendar_rb.html +629 -0
  134. data/test/coverage/-home-rosejn-projects-icalendar-lib-icalendar-component-alarm_rb.html +581 -0
  135. data/test/coverage/-home-rosejn-projects-icalendar-lib-icalendar-component-event_rb.html +658 -0
  136. data/test/coverage/-home-rosejn-projects-icalendar-lib-icalendar-component-freebusy_rb.html +574 -0
  137. data/test/coverage/-home-rosejn-projects-icalendar-lib-icalendar-component-journal_rb.html +597 -0
  138. data/test/coverage/-home-rosejn-projects-icalendar-lib-icalendar-component-timezone_rb.html +625 -0
  139. data/test/coverage/-home-rosejn-projects-icalendar-lib-icalendar-component-todo_rb.html +600 -0
  140. data/test/coverage/-home-rosejn-projects-icalendar-lib-icalendar-component_rb.html +924 -0
  141. data/test/coverage/-home-rosejn-projects-icalendar-lib-icalendar-conversions_rb.html +667 -0
  142. data/test/coverage/-home-rosejn-projects-icalendar-lib-icalendar-parser_rb.html +938 -0
  143. data/test/coverage/-home-rosejn-projects-icalendar-lib-icalendar_rb.html +576 -0
  144. data/test/coverage/-home-rosejn-projects-icalendar-lib-meta_rb.html +572 -0
  145. data/test/coverage/calendar_test_rb.html +590 -0
  146. data/test/coverage/component_test_rb.html +602 -0
  147. data/test/coverage/index.html +1009 -0
  148. data/test/coverage/lib-hash_attrs_rb.html +574 -0
  149. data/test/coverage/lib-icalendar-base_rb.html +583 -0
  150. data/test/coverage/lib-icalendar-calendar_rb.html +631 -0
  151. data/test/coverage/lib-icalendar-component-alarm_rb.html +581 -0
  152. data/test/coverage/lib-icalendar-component-event_rb.html +661 -0
  153. data/test/coverage/lib-icalendar-component-freebusy_rb.html +576 -0
  154. data/test/coverage/lib-icalendar-component-journal_rb.html +599 -0
  155. data/test/coverage/lib-icalendar-component-timezone_rb.html +625 -0
  156. data/test/coverage/lib-icalendar-component-todo_rb.html +602 -0
  157. data/test/coverage/lib-icalendar-component_rb.html +941 -0
  158. data/test/coverage/lib-icalendar-conversions_rb.html +673 -0
  159. data/test/coverage/lib-icalendar-parser_rb.html +916 -0
  160. data/test/coverage/lib-icalendar_rb.html +576 -0
  161. data/test/coverage/lib-meta_rb.html +572 -0
  162. data/test/coverage/parameter_test_rb.html +569 -0
  163. data/test/coverage/parser_test_rb.html +623 -0
  164. data/test/coverage/test-calendar_test_rb.html +590 -0
  165. data/test/coverage/test-component-event_test_rb.html +584 -0
  166. data/test/coverage/test-component_test_rb.html +606 -0
  167. data/test/coverage/test-conversions_test_rb.html +603 -0
  168. data/test/coverage/test-parameter_test_rb.html +569 -0
  169. data/test/coverage/test-parser_test_rb.html +624 -0
  170. data/test/interactive.rb +3 -1
  171. data/test/life.ics +46 -1092
  172. data/test/parameter_test.rb +11 -2
  173. data/test/parser_test.rb +12 -11
  174. metadata +259 -126
  175. data/test/old_life.ics +0 -46
  176. data/test/rw.ics +0 -947
@@ -10,11 +10,11 @@ cal_file = File.open("../test/life.ics")
10
10
 
11
11
  # Parser returns an array of calendars because a single file
12
12
  # can have multiple calendar objects.
13
- cals = Icalendar::Parser.new(cal_file).parse
13
+ cals = Icalendar::parse(cal_file)
14
14
  cal = cals.first
15
15
 
16
16
  # Now you can access the cal object in just the same way I created it
17
17
  event = cal.events.first
18
18
 
19
- puts "user_id: " + event.user_id
19
+ puts "start date-time: " + event.dtstart.to_s
20
20
  puts "summary: " + event.summary
@@ -31,5 +31,13 @@ module Icalendar #:nodoc:
31
31
  class Base
32
32
  @@logger = Logger.new(STDERR)
33
33
  @@logger.level = Logger::FATAL
34
+
35
+ def self.debug
36
+ @@logger.level = Logger::DEBUG
37
+ end
38
+
39
+ def self.quiet
40
+ @@logger.level = Logger::FATAL
41
+ end
34
42
  end
35
43
  end
@@ -18,12 +18,10 @@ module Icalendar
18
18
 
19
19
  def initialize()
20
20
  super("VCALENDAR")
21
- @properties = {}
22
- @property_params = {}
23
21
 
24
22
  # Set some defaults
25
23
  self.calscale = "GREGORIAN" # Who knows, but this is the only one in the spec.
26
- self.prodid = "iCalendar-Ruby" # Current product... Should be overwritten
24
+ self.prodid = "iCalendar-Ruby" # Current product... Should be overwritten by apps that use the library
27
25
  self.version = "2.0" # Version of the specification
28
26
  end
29
27
 
@@ -35,6 +33,10 @@ module Icalendar
35
33
 
36
34
  e
37
35
  end
36
+
37
+ def find_event(uid)
38
+ self.events.find {|e| e.uid == uid}
39
+ end
38
40
 
39
41
  def todo(&block)
40
42
  e = Todo.new
@@ -45,6 +47,10 @@ module Icalendar
45
47
  e
46
48
  end
47
49
 
50
+ def find_todo(uid)
51
+ self.todos.find {|t| t.uid == uid}
52
+ end
53
+
48
54
  def journal(&block)
49
55
  e = Journal.new
50
56
  self.add_component e
@@ -54,6 +60,10 @@ module Icalendar
54
60
  e
55
61
  end
56
62
 
63
+ def find_journal(uid)
64
+ self.journals.find {|j| j.uid == uid}
65
+ end
66
+
57
67
  def freebusy(&block)
58
68
  e = Freebusy.new
59
69
  self.add_component e
@@ -63,6 +73,10 @@ module Icalendar
63
73
  e
64
74
  end
65
75
 
76
+ def find_freebusy(uid)
77
+ self.freebusys.find {|f| f.uid == uid}
78
+ end
79
+
66
80
  def timezone(&block)
67
81
  e = Timezone.new
68
82
  self.add_component e
@@ -71,6 +85,21 @@ module Icalendar
71
85
 
72
86
  e
73
87
  end
88
+
89
+ # The "PUBLISH" method in a "VEVENT" calendar component is an
90
+ # unsolicited posting of an iCalendar object. Any CU may add published
91
+ # components to their calendar. The "Organizer" MUST be present in a
92
+ # published iCalendar component. "Attendees" MUST NOT be present. Its
93
+ # expected usage is for encapsulating an arbitrary event as an
94
+ # iCalendar object. The "Organizer" may subsequently update (with
95
+ # another "PUBLISH" method), add instances to (with an "ADD" method),
96
+ # or cancel (with a "CANCEL" method) a previously published "VEVENT"
97
+ # calendar component.
98
+ def publish
99
+ ip_method = "PUBLISH"
100
+
101
+ end
102
+
74
103
  end # class Calendar
75
104
 
76
105
  end # module Icalendar
@@ -7,6 +7,23 @@
7
7
  =end
8
8
 
9
9
  module Icalendar
10
+ require 'socket'
11
+
12
+ class Geo < Icalendar::Base
13
+ attr_accessor :latitude, :longitude
14
+ alias :lat :latitude
15
+ alias :long :longitude
16
+
17
+ def initialize(lat, long)
18
+ @lat = lat
19
+ @long = long
20
+ end
21
+
22
+ def to_ical
23
+ "#{@lat.to_ical};#{@long.to_ical}"
24
+ end
25
+ end
26
+
10
27
  # The body of the iCalendar object consists of a sequence of calendar
11
28
  # properties and one or more calendar components. The calendar
12
29
  # properties are attributes that apply to the calendar as a whole. The
@@ -19,7 +36,7 @@ module Icalendar
19
36
  meta_include HashAttrs
20
37
 
21
38
  attr_reader :name
22
- attr_accessor :properties, :property_params
39
+ attr_accessor :properties
23
40
 
24
41
  @@multi_properties = {}
25
42
 
@@ -27,7 +44,6 @@ module Icalendar
27
44
  @name = name
28
45
  @components = Hash.new([])
29
46
  @properties = {}
30
- @property_params = {}
31
47
 
32
48
  @@logger.info("New #{@name[1,@name.size].capitalize}...")
33
49
  end
@@ -43,37 +59,74 @@ module Icalendar
43
59
  @components[key] << component
44
60
  end
45
61
 
62
+ # Add a component to the calendar.
46
63
  alias add add_component
47
64
 
65
+ # Add an event to the calendar.
66
+ alias add_event add_component
67
+
68
+ # Add a todo item to the calendar.
69
+ alias add_todo add_component
70
+
71
+ # Add a journal item to the calendar.
72
+ alias add_journal add_component
73
+
74
+ def remove_component(component)
75
+ key = (component.class.to_s.downcase + 's').gsub('icalendar::', '').to_sym
76
+
77
+ if @components.has_key? key
78
+ @components[key].delete(component)
79
+ end
80
+ end
81
+
82
+ # Remove a component from the calendar.
83
+ alias remove remove_component
84
+
85
+ # Remove an event from the calendar.
86
+ alias remove_event remove_component
87
+
88
+ # Remove a todo item from the calendar.
89
+ alias remove_todo remove_component
90
+
91
+ # Remove a journal item from the calendar.
92
+ alias remove_journal remove_component
93
+
94
+ # Used to generate unique component ids
95
+ def new_uid
96
+ "#{DateTime.now}_#{rand(999999999)}@#{Socket.gethostname}"
97
+ end
98
+
99
+ # Output in the icalendar format
48
100
  def to_ical
49
- print_component do |s|
101
+ print_component do
102
+ s = ""
50
103
  @components.each_value do |comps|
51
104
  comps.each { |component| s << component.to_ical }
52
105
  end
106
+ s
53
107
  end
54
108
  end
55
109
 
56
110
  # Print this icalendar component
57
111
  def print_component
58
- s = ""
59
-
60
112
  # Begin a new component
61
- s << "BEGIN:#{@name.upcase}\r\n"
113
+ "BEGIN:#{@name.upcase}\r\n" +
62
114
 
63
115
  # Then the properties
64
- print_properties(s)
116
+ print_properties +
65
117
 
66
- # Any custom body of the derived component
67
- yield(s)
118
+ # sub components
119
+ yield +
68
120
 
69
121
  # End of this component
70
- s << "END:#{@name.upcase}\r\n"
122
+ "END:#{@name.upcase}\r\n"
71
123
  end
72
124
 
73
125
  # Print this components properties
74
- def print_properties(s)
75
- @properties.each do |key,value|
126
+ def print_properties
127
+ s = ""
76
128
 
129
+ @properties.each do |key,val|
77
130
  # Take out underscore for property names that conflicted
78
131
  # with built-in words.
79
132
  if key =~ /ip_.*/
@@ -81,47 +134,51 @@ module Icalendar
81
134
  end
82
135
 
83
136
  # Property name
84
- s << "#{key.upcase}"
137
+ s << "#{key.upcase}" +
85
138
 
86
139
  # Possible parameters
87
- print_parameter(s, key, value)
140
+ print_parameters(val) +
88
141
 
89
142
  # Property value
90
- s << ":#{value.to_ical}\r\n"
143
+ ":#{val.to_ical}\r\n"
91
144
  end
145
+
146
+ s
92
147
  end
93
148
 
94
149
  # Print the parameters for a specific property
95
- def print_parameter(s, key, value)
96
- if @property_params.has_key?(key)
97
- params = @property_params[key]
98
- params.each do |key,val|
99
- s << ";#{key}"
100
- val = [ val ] unless val.respond_to?(:to_ary)
101
-
102
- # Possible parameter values
103
- unless val.empty?
104
- s << "="
105
- sep = "" # First entry comes after = sign, but then we need commas
106
- val.each do |pval|
107
- if pval.respond_to? :to_ical
108
- s << sep << pval.to_ical
109
- sep = ","
110
- end
150
+ def print_parameters(val)
151
+ s = ""
152
+ return s unless val.respond_to?(:ical_params) and not val.ical_params.nil?
153
+
154
+ val.ical_params.each do |key,val|
155
+ s << ";#{key}"
156
+ val = [ val ] unless val.is_a?(Array)
157
+
158
+ # Possible parameter values
159
+ unless val.empty?
160
+ s << "="
161
+ sep = "" # First entry comes after = sign, but then we need commas
162
+ val.each do |pval|
163
+ if pval.respond_to? :to_ical
164
+ s << sep << pval.to_ical
165
+ sep = ","
111
166
  end
112
167
  end
113
-
114
168
  end
115
169
  end
170
+ s
116
171
  end
117
172
 
118
173
  # TODO: Look into the x-property, x-param stuff...
174
+ # This would really only be needed for subclassing to add additional
175
+ # properties to an application using the API.
119
176
  def custom_property(name, value)
120
177
  @properties[name] = value
121
178
  end
122
179
 
123
180
  def multi_property?(name)
124
- @@multi_properties.has_key?(name.upcase)
181
+ @@multi_properties.has_key?(name.downcase)
125
182
  end
126
183
 
127
184
  # Make it protected so we can monitor usage...
@@ -133,107 +190,114 @@ module Icalendar
133
190
 
134
191
  # Define a set of methods supporting a new property
135
192
  def Component.ical_property(property, alias_name = nil, prop_name = nil)
136
-
137
193
  property = "#{property}".strip.downcase
138
- getter = "#{property}"
139
- setter = "#{property}="
140
- query = "#{property}?"
141
194
  alias_name = "#{alias_name}".strip.downcase unless alias_name.nil?
142
195
 
143
196
  # If a prop_name was given then we use that for the actual storage
144
- property = "#{prop_name}".strip.upcase unless prop_name.nil?
197
+ property = "#{prop_name}".strip.downcase unless prop_name.nil?
145
198
 
146
- # Change underscores in property name to a dash
147
- property[/_/] = '-' if property =~ /_/
199
+ generate_getter(property, alias_name)
200
+ generate_setter(property, alias_name)
201
+ generate_query(property, alias_name)
202
+ end
203
+
204
+ # Define a set of methods defining a new property, which
205
+ # supports multiple values for the same property name.
206
+ def Component.ical_multi_property(property, singular, plural)
207
+ property = "#{property}".strip.downcase.gsub(/-/, '_')
208
+ plural = "#{plural}".strip.downcase
148
209
 
149
- # All properties names are stored in caps...
150
- property = property.upcase
210
+ # Set this key so the parser knows to use an array for
211
+ # storing this property type.
212
+ @@multi_properties["#{property}"] = true
151
213
 
152
- unless instance_methods.include? getter
153
- code = <<-code
154
- def #{getter}(val = nil, params = {})
155
- if val.nil?
156
- @properties["#{property}"]
157
- else
158
- # Set the value just like normal
159
- self.#{setter}(val)
160
- end
161
- end
162
- code
214
+ generate_multi_getter(property, plural)
215
+ generate_multi_setter(property, plural)
216
+ generate_multi_query(property, plural)
217
+ generate_multi_adder(property, singular)
218
+ generate_multi_remover(property, singular)
219
+ end
163
220
 
164
- class_eval code, "component.rb", 155
165
- alias_method("#{alias_name}", "#{getter}") unless alias_name.nil?
166
- end
221
+ private
167
222
 
168
- unless instance_methods.include? setter
223
+ def Component.generate_getter(property, alias_name)
224
+ unless instance_methods.include? property
169
225
  code = <<-code
170
- def #{setter}(val)
226
+ def #{property}(val = nil, params = nil)
227
+ return @properties["#{property}"] if val.nil?
228
+
171
229
  unless val.respond_to?(:to_ical)
172
230
  raise(NotImplementedError, "Value of type (" + val.class.to_s + ") does not support to_ical method!")
173
231
  end
174
232
 
233
+ unless params.nil?
234
+ # Extend with the parameter methods only if we have to...
235
+ unless val.respond_to?(:ical_params)
236
+ val.class.class_eval { attr_accessor :ical_params }
237
+ end
238
+ val.ical_params = params
239
+ end
240
+
175
241
  @properties["#{property}"] = val
176
242
  end
177
243
  code
178
244
 
179
- class_eval code, "component.rb", 171
245
+ class_eval code, "component.rb", 219
246
+ alias_method("#{alias_name}", "#{property}") unless alias_name.nil?
247
+ end
248
+ end
249
+
250
+ def Component.generate_setter(property, alias_name)
251
+ setter = property + '='
252
+ unless instance_methods.include? setter
253
+ code = <<-code
254
+ def #{setter}(val)
255
+ #{property}(val)
256
+ end
257
+ code
180
258
 
181
- alias_method("#{alias_name}=", "#{setter}") unless alias_name.nil?
259
+ class_eval code, "component.rb", 233
260
+ alias_method("#{alias_name}=", "#{property+'='}") unless alias_name.nil?
182
261
  end
262
+ end
183
263
 
264
+ def Component.generate_query(property, alias_name)
265
+ query = "#{property}?"
184
266
  unless instance_methods.include? query
185
267
  code = <<-code
186
268
  def #{query}
187
- @properties.has_key?("#{property}")
269
+ @properties.has_key?("#{property.downcase}")
188
270
  end
189
271
  code
190
272
 
191
- class_eval code, "component.rb", 183
273
+ class_eval code, "component.rb", 226
192
274
 
193
275
  alias_method("#{alias_name}\?", "#{query}") unless alias_name.nil?
194
276
  end
195
277
  end
196
278
 
197
- # Define a set of methods defining a new property, which
198
- # supports multiple values for the same property name.
199
- def Component.ical_multi_property(property, singular, plural)
200
- property = "#{property}".strip.upcase
201
- singular = "#{singular}".strip.downcase
202
- plural = "#{plural}".strip.downcase
203
-
204
- getter = "#{plural}"
205
- setter = "#{plural}="
206
- adder = "add_#{singular}"
207
- remover = "remove_#{singular}"
208
- query = "#{plural}?"
209
-
210
- # Set this key so the parser knows to use an array for
211
- # storing this property type.
212
- @@multi_properties["#{property}"] = true
213
-
279
+ def Component.generate_multi_getter(property, plural)
214
280
  # Getter for whole array
215
- unless instance_methods.include? getter
281
+ unless instance_methods.include? plural
216
282
  code = <<-code
217
- def #{getter}(*a)
218
- if a.empty?
219
- if @properties.has_key?("#{property}")
220
- @properties["#{property}"]
221
- else
222
- []
223
- end
283
+ def #{plural}(a = nil)
284
+ if a.nil?
285
+ @properties["#{property}"] || []
224
286
  else
225
- self.#{setter}(a.first)
287
+ self.#{plural}=(a)
226
288
  end
227
289
  end
228
290
  code
229
291
 
230
292
  class_eval code, "component.rb", 186
231
293
  end
294
+ end
232
295
 
296
+ def Component.generate_multi_setter(property, plural)
233
297
  # Setter for whole array
234
- unless instance_methods.include? setter
298
+ unless instance_methods.include? plural+'+'
235
299
  code = <<-code
236
- def #{setter}(a)
300
+ def #{plural}=(a)
237
301
  if a.respond_to?(:to_ary)
238
302
  a.to_ary.each do |val|
239
303
  unless val.respond_to?(:to_ical)
@@ -242,27 +306,31 @@ module Icalendar
242
306
  end
243
307
 
244
308
  @properties["#{property}"] = a.to_ary
245
-
246
309
  else
247
- raise ArgumentError, "#{getter} is a multi-property that must be an array! Use the #{adder} method to add single entries."
310
+ raise ArgumentError, "#{plural} is a multi-property that must be an array! Use the add_[property] method to add single entries."
248
311
  end
249
312
  end
250
313
  code
251
314
 
252
315
  class_eval code, "component.rb", 198
253
316
  end
317
+ end
254
318
 
319
+ def Component.generate_multi_query(property, plural)
255
320
  # Query for any of these properties
256
- unless instance_methods.include? query
321
+ unless instance_methods.include? plural+'?'
257
322
  code = <<-code
258
- def #{query}
323
+ def #{plural}?
259
324
  @properties.has_key?("#{property}")
260
325
  end
261
326
  code
262
327
 
263
328
  class_eval code, "component.rb", 210
264
329
  end
330
+ end
265
331
 
332
+ def Component.generate_multi_adder(property, singular)
333
+ adder = "add_"+singular.to_s
266
334
  # Add another item to this properties array
267
335
  unless instance_methods.include? adder
268
336
  code = <<-code
@@ -271,6 +339,14 @@ module Icalendar
271
339
  raise(NotImplementedError, "Property value object does not support to_ical method!")
272
340
  end
273
341
 
342
+ unless params.nil?
343
+ # Extend with the parameter methods only if we have to...
344
+ unless val.respond_to?(:ical_params)
345
+ val.class.class_eval { attr_accessor :ical_params }
346
+ end
347
+ val.ical_params = params
348
+ end
349
+
274
350
  if @properties.has_key?("#{property}")
275
351
  @properties["#{property}"] << val
276
352
  else
@@ -279,52 +355,50 @@ module Icalendar
279
355
  end
280
356
  code
281
357
 
282
- class_eval code, "component.rb", 228
358
+ class_eval code, "component.rb", 289
283
359
  alias_method("add_#{property.downcase}", "#{adder}")
284
360
  end
361
+ end
285
362
 
363
+ def Component.generate_multi_remover(property, singular)
286
364
  # Remove an item from this properties array
287
- unless instance_methods.include? remover
365
+ unless instance_methods.include? "remove_#{singular}"
288
366
  code = <<-code
289
- def #{remover}(a)
367
+ def remove_#{singular}(a)
290
368
  if @properties.has_key?("#{property}")
291
369
  @properties["#{property}"].delete(a)
292
370
  end
293
371
  end
294
372
  code
295
373
 
296
- class_eval code, "component.rb", 241
297
- alias_method("remove_#{property.downcase}", "#{remover}")
374
+ class_eval code, "component.rb", 303
375
+ alias_method("remove_#{property.downcase}", "remove_#{singular}")
298
376
  end
299
-
300
377
  end
301
378
 
302
379
  def method_missing(method_name, *args)
380
+ @@logger.debug("Inside method_missing...")
303
381
  method_name = method_name.to_s.downcase
304
382
 
305
383
  unless method_name =~ /x_.*/
306
- raise NoMethodError
307
- end
308
-
309
- val = args.first
310
-
311
- unless val.respond_to?(:to_ical)
312
- raise(NotImplementedError, "Value of type (" + val.class.to_s + ") does not support to_ical method!")
384
+ raise NoMethodError, "Method Name: #{method_name}"
313
385
  end
314
386
 
315
- if method_name =~ /(.*)(=)/ # Its a setter
316
- @properties[$1] = val
317
- @@logger.debug("Setting #{$1} => #{val}")
387
+ # x-properties are accessed with underscore but stored with a dash so
388
+ # they output correctly and we don't have to special case the
389
+ # output code, which would require checking every property.
390
+ if args.size > 0 # Its a setter
391
+ # Pull off the possible equals
392
+ @properties[method_name[/x_[^=]*/].gsub('x_', 'x-')] = args.first
318
393
  else # Or its a getter
319
- @@logger.debug("Getting #{method_name} => #{@properties[method_name]}")
320
- return @properties[method_name]
394
+ return @properties[method_name.gsub('x_', 'x-')]
321
395
  end
322
396
  end
323
397
 
324
398
  public
325
399
 
326
400
  def respond_to?(method_name)
327
- unless method_name.to_s.downcase =~ /x-.*/
401
+ unless method_name.to_s.downcase =~ /x_.*/
328
402
  super
329
403
  end
330
404