ri_cal 0.5.0

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 (130) hide show
  1. data/History.txt +45 -0
  2. data/Manifest.txt +129 -0
  3. data/README.txt +394 -0
  4. data/Rakefile +31 -0
  5. data/bin/ri_cal +8 -0
  6. data/component_attributes/alarm.yml +10 -0
  7. data/component_attributes/calendar.yml +4 -0
  8. data/component_attributes/component_property_defs.yml +180 -0
  9. data/component_attributes/event.yml +45 -0
  10. data/component_attributes/freebusy.yml +16 -0
  11. data/component_attributes/journal.yml +35 -0
  12. data/component_attributes/timezone.yml +3 -0
  13. data/component_attributes/timezone_period.yml +11 -0
  14. data/component_attributes/todo.yml +46 -0
  15. data/copyrights.txt +1 -0
  16. data/docs/draft-ietf-calsify-2446bis-08.txt +7280 -0
  17. data/docs/draft-ietf-calsify-rfc2445bis-09.txt +10416 -0
  18. data/docs/incrementers.txt +7 -0
  19. data/docs/rfc2445.pdf +0 -0
  20. data/lib/ri_cal.rb +144 -0
  21. data/lib/ri_cal/component.rb +247 -0
  22. data/lib/ri_cal/component/alarm.rb +21 -0
  23. data/lib/ri_cal/component/calendar.rb +219 -0
  24. data/lib/ri_cal/component/event.rb +60 -0
  25. data/lib/ri_cal/component/freebusy.rb +18 -0
  26. data/lib/ri_cal/component/journal.rb +30 -0
  27. data/lib/ri_cal/component/t_z_info_timezone.rb +123 -0
  28. data/lib/ri_cal/component/timezone.rb +196 -0
  29. data/lib/ri_cal/component/timezone/daylight_period.rb +25 -0
  30. data/lib/ri_cal/component/timezone/standard_period.rb +23 -0
  31. data/lib/ri_cal/component/timezone/timezone_period.rb +53 -0
  32. data/lib/ri_cal/component/todo.rb +43 -0
  33. data/lib/ri_cal/core_extensions.rb +6 -0
  34. data/lib/ri_cal/core_extensions/array.rb +7 -0
  35. data/lib/ri_cal/core_extensions/array/conversions.rb +15 -0
  36. data/lib/ri_cal/core_extensions/date.rb +13 -0
  37. data/lib/ri_cal/core_extensions/date/conversions.rb +61 -0
  38. data/lib/ri_cal/core_extensions/date_time.rb +15 -0
  39. data/lib/ri_cal/core_extensions/date_time/conversions.rb +50 -0
  40. data/lib/ri_cal/core_extensions/object.rb +8 -0
  41. data/lib/ri_cal/core_extensions/object/conversions.rb +20 -0
  42. data/lib/ri_cal/core_extensions/string.rb +8 -0
  43. data/lib/ri_cal/core_extensions/string/conversions.rb +63 -0
  44. data/lib/ri_cal/core_extensions/time.rb +13 -0
  45. data/lib/ri_cal/core_extensions/time/calculations.rb +153 -0
  46. data/lib/ri_cal/core_extensions/time/conversions.rb +61 -0
  47. data/lib/ri_cal/core_extensions/time/tzid_access.rb +50 -0
  48. data/lib/ri_cal/core_extensions/time/week_day_predicates.rb +88 -0
  49. data/lib/ri_cal/floating_timezone.rb +32 -0
  50. data/lib/ri_cal/invalid_property_value.rb +8 -0
  51. data/lib/ri_cal/invalid_timezone_identifer.rb +20 -0
  52. data/lib/ri_cal/occurrence_enumerator.rb +206 -0
  53. data/lib/ri_cal/occurrence_period.rb +17 -0
  54. data/lib/ri_cal/parser.rb +138 -0
  55. data/lib/ri_cal/properties/alarm.rb +390 -0
  56. data/lib/ri_cal/properties/calendar.rb +164 -0
  57. data/lib/ri_cal/properties/event.rb +1526 -0
  58. data/lib/ri_cal/properties/freebusy.rb +594 -0
  59. data/lib/ri_cal/properties/journal.rb +1240 -0
  60. data/lib/ri_cal/properties/timezone.rb +151 -0
  61. data/lib/ri_cal/properties/timezone_period.rb +416 -0
  62. data/lib/ri_cal/properties/todo.rb +1562 -0
  63. data/lib/ri_cal/property_value.rb +149 -0
  64. data/lib/ri_cal/property_value/array.rb +27 -0
  65. data/lib/ri_cal/property_value/cal_address.rb +11 -0
  66. data/lib/ri_cal/property_value/date.rb +175 -0
  67. data/lib/ri_cal/property_value/date_time.rb +335 -0
  68. data/lib/ri_cal/property_value/date_time/additive_methods.rb +44 -0
  69. data/lib/ri_cal/property_value/date_time/time_machine.rb +181 -0
  70. data/lib/ri_cal/property_value/date_time/timezone_support.rb +96 -0
  71. data/lib/ri_cal/property_value/duration.rb +110 -0
  72. data/lib/ri_cal/property_value/geo.rb +11 -0
  73. data/lib/ri_cal/property_value/integer.rb +12 -0
  74. data/lib/ri_cal/property_value/occurrence_list.rb +144 -0
  75. data/lib/ri_cal/property_value/period.rb +82 -0
  76. data/lib/ri_cal/property_value/recurrence_rule.rb +145 -0
  77. data/lib/ri_cal/property_value/recurrence_rule/enumeration_support_methods.rb +97 -0
  78. data/lib/ri_cal/property_value/recurrence_rule/enumerator.rb +79 -0
  79. data/lib/ri_cal/property_value/recurrence_rule/initialization_methods.rb +148 -0
  80. data/lib/ri_cal/property_value/recurrence_rule/negative_setpos_enumerator.rb +53 -0
  81. data/lib/ri_cal/property_value/recurrence_rule/numbered_span.rb +31 -0
  82. data/lib/ri_cal/property_value/recurrence_rule/occurence_incrementer.rb +793 -0
  83. data/lib/ri_cal/property_value/recurrence_rule/recurring_day.rb +131 -0
  84. data/lib/ri_cal/property_value/recurrence_rule/recurring_month_day.rb +60 -0
  85. data/lib/ri_cal/property_value/recurrence_rule/recurring_numbered_week.rb +33 -0
  86. data/lib/ri_cal/property_value/recurrence_rule/recurring_year_day.rb +49 -0
  87. data/lib/ri_cal/property_value/recurrence_rule/validations.rb +125 -0
  88. data/lib/ri_cal/property_value/text.rb +40 -0
  89. data/lib/ri_cal/property_value/uri.rb +11 -0
  90. data/lib/ri_cal/property_value/utc_offset.rb +33 -0
  91. data/lib/ri_cal/required_timezones.rb +55 -0
  92. data/ri_cal.gemspec +49 -0
  93. data/sample_ical_files/from_ical_dot_app/test1.ics +38 -0
  94. data/script/console +10 -0
  95. data/script/destroy +14 -0
  96. data/script/generate +14 -0
  97. data/script/txt2html +71 -0
  98. data/spec/ri_cal/component/alarm_spec.rb +12 -0
  99. data/spec/ri_cal/component/calendar_spec.rb +54 -0
  100. data/spec/ri_cal/component/event_spec.rb +601 -0
  101. data/spec/ri_cal/component/freebusy_spec.rb +12 -0
  102. data/spec/ri_cal/component/journal_spec.rb +37 -0
  103. data/spec/ri_cal/component/t_z_info_timezone_spec.rb +36 -0
  104. data/spec/ri_cal/component/timezone_spec.rb +218 -0
  105. data/spec/ri_cal/component/todo_spec.rb +112 -0
  106. data/spec/ri_cal/component_spec.rb +224 -0
  107. data/spec/ri_cal/core_extensions/string/conversions_spec.rb +78 -0
  108. data/spec/ri_cal/core_extensions/time/calculations_spec.rb +188 -0
  109. data/spec/ri_cal/core_extensions/time/week_day_predicates_spec.rb +45 -0
  110. data/spec/ri_cal/occurrence_enumerator_spec.rb +573 -0
  111. data/spec/ri_cal/parser_spec.rb +303 -0
  112. data/spec/ri_cal/property_value/date_spec.rb +53 -0
  113. data/spec/ri_cal/property_value/date_time_spec.rb +383 -0
  114. data/spec/ri_cal/property_value/duration_spec.rb +126 -0
  115. data/spec/ri_cal/property_value/occurrence_list_spec.rb +72 -0
  116. data/spec/ri_cal/property_value/period_spec.rb +49 -0
  117. data/spec/ri_cal/property_value/recurrence_rule/recurring_year_day_spec.rb +21 -0
  118. data/spec/ri_cal/property_value/recurrence_rule_spec.rb +1814 -0
  119. data/spec/ri_cal/property_value/text_spec.rb +25 -0
  120. data/spec/ri_cal/property_value/utc_offset_spec.rb +48 -0
  121. data/spec/ri_cal/property_value_spec.rb +125 -0
  122. data/spec/ri_cal/required_timezones_spec.rb +67 -0
  123. data/spec/ri_cal_spec.rb +53 -0
  124. data/spec/spec.opts +4 -0
  125. data/spec/spec_helper.rb +46 -0
  126. data/tasks/gem_loader/load_active_support.rb +3 -0
  127. data/tasks/gem_loader/load_tzinfo_gem.rb +2 -0
  128. data/tasks/ri_cal.rake +410 -0
  129. data/tasks/spec.rake +50 -0
  130. metadata +221 -0
@@ -0,0 +1,33 @@
1
+ module RiCal
2
+ class PropertyValue
3
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
4
+ #
5
+ class UtcOffset < PropertyValue # :nodoc:
6
+ attr_accessor :sign, :hours, :minutes, :seconds
7
+
8
+ def value=(string)
9
+ @value = string
10
+ parse_match = /([+-])(\d\d)(\d\d)(\d\d)?/.match(string)
11
+ if parse_match
12
+ @sign = parse_match[1] == "+" ? 1 : -1
13
+ @hours = parse_match[2].to_i
14
+ @minutes = parse_match[3].to_i
15
+ @seconds = parse_match[4].to_i || 0
16
+ end
17
+ end
18
+
19
+ def to_seconds
20
+ @sign * ((((hours*60) + minutes) * 60) + seconds)
21
+ end
22
+
23
+ def add_to_date_time_value(date_time_value)
24
+ date_time_value.advance(:hours => sign * hours, :minutes => sign * minutes, :seconds => sign * minutes)
25
+ end
26
+
27
+ def subtract_from_date_time_value(date_time_value)
28
+ signum = -1 * sign
29
+ date_time_value.advance(:hours => signum * hours, :minutes => signum * minutes, :seconds => signum * minutes)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,55 @@
1
+ module RiCal
2
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
3
+ #
4
+ # RequireTimezones collects the timezones used by a given calendar component or set of calendar components
5
+ # For each timezone we collect it's id, and the earliest and latest times which reference the zone
6
+ class RequiredTimezones #:nodoc:
7
+
8
+
9
+ # A required timezone represents a single timezone and the earliest and latest times which reference it.
10
+ class RequiredTimezone #:nodoc:
11
+
12
+ attr_reader :first_time, :last_time, :timezone
13
+
14
+ def initialize(tzid)
15
+ @timezone = RiCal::Component::TZInfoTimezone.new(TZInfo::Timezone.get(tzid))
16
+ end
17
+
18
+ def tzid
19
+ @timezone.identifier
20
+ end
21
+
22
+ def add_datetime(date_time)
23
+ if @first_time
24
+ @first_time = date_time if date_time < @first_time
25
+ else
26
+ @first_time = date_time
27
+ end
28
+ if @last_time
29
+ @last_time = date_time if date_time > @last_time
30
+ else
31
+ @last_time = date_time
32
+ end
33
+ end
34
+ end
35
+
36
+ def required_timezones
37
+ @required_zones ||= {}
38
+ end
39
+
40
+ def required_zones
41
+ required_timezones.values
42
+ end
43
+
44
+ def export_to(export_stream)
45
+ required_zones.each do |z|
46
+ tzinfo_timezone =z.timezone
47
+ tzinfo_timezone.export_local_to(export_stream, z.first_time, z.last_time)
48
+ end
49
+ end
50
+
51
+ def add_datetime(date_time, tzid)
52
+ (required_timezones[tzid] ||= RequiredTimezone.new(tzid)).add_datetime(date_time)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,49 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{ri_cal}
5
+ s.version = "0.5.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["author=Rick DeNatale"]
9
+ s.date = %q{2009-05-26}
10
+ s.default_executable = %q{ri_cal}
11
+ s.description = %q{This is an UNOFFICIAL version. The public official version will be released on RubyForge. Github will be used
12
+ for interim versions. USE THIS VERSION AT YOUR OWN RISK.
13
+
14
+ A new Ruby implementation of RFC2445 iCalendar.
15
+
16
+ The existing Ruby iCalendar libraries (e.g. icalendar, vpim) provide for parsing and generating icalendar files,
17
+ but do not support important things like enumerating occurrences of repeating events.
18
+
19
+ This is a clean-slate implementation of RFC2445.
20
+
21
+ A Google group for discussion of this library has been set up http://groups.google.com/group/rical_gem}
22
+ s.email = ["rick.denatale@gmail.com"]
23
+ s.executables = ["ri_cal"]
24
+ s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt", "copyrights.txt", "docs/draft-ietf-calsify-2446bis-08.txt", "docs/draft-ietf-calsify-rfc2445bis-09.txt", "docs/incrementers.txt"]
25
+ s.files = ["History.txt", "Manifest.txt", "README.txt", "Rakefile", "bin/ri_cal", "component_attributes/alarm.yml", "component_attributes/calendar.yml", "component_attributes/component_property_defs.yml", "component_attributes/event.yml", "component_attributes/freebusy.yml", "component_attributes/journal.yml", "component_attributes/timezone.yml", "component_attributes/timezone_period.yml", "component_attributes/todo.yml", "copyrights.txt", "docs/draft-ietf-calsify-2446bis-08.txt", "docs/draft-ietf-calsify-rfc2445bis-09.txt", "docs/incrementers.txt", "docs/rfc2445.pdf", "lib/ri_cal.rb", "lib/ri_cal/component.rb", "lib/ri_cal/component/alarm.rb", "lib/ri_cal/component/calendar.rb", "lib/ri_cal/component/event.rb", "lib/ri_cal/component/freebusy.rb", "lib/ri_cal/component/journal.rb", "lib/ri_cal/component/t_z_info_timezone.rb", "lib/ri_cal/component/timezone.rb", "lib/ri_cal/component/timezone/daylight_period.rb", "lib/ri_cal/component/timezone/standard_period.rb", "lib/ri_cal/component/timezone/timezone_period.rb", "lib/ri_cal/component/todo.rb", "lib/ri_cal/core_extensions.rb", "lib/ri_cal/core_extensions/array.rb", "lib/ri_cal/core_extensions/array/conversions.rb", "lib/ri_cal/core_extensions/date.rb", "lib/ri_cal/core_extensions/date/conversions.rb", "lib/ri_cal/core_extensions/date_time.rb", "lib/ri_cal/core_extensions/date_time/conversions.rb", "lib/ri_cal/core_extensions/object.rb", "lib/ri_cal/core_extensions/object/conversions.rb", "lib/ri_cal/core_extensions/string.rb", "lib/ri_cal/core_extensions/string/conversions.rb", "lib/ri_cal/core_extensions/time.rb", "lib/ri_cal/core_extensions/time/calculations.rb", "lib/ri_cal/core_extensions/time/conversions.rb", "lib/ri_cal/core_extensions/time/tzid_access.rb", "lib/ri_cal/core_extensions/time/week_day_predicates.rb", "lib/ri_cal/floating_timezone.rb", "lib/ri_cal/invalid_property_value.rb", "lib/ri_cal/invalid_timezone_identifer.rb", "lib/ri_cal/occurrence_enumerator.rb", "lib/ri_cal/occurrence_period.rb", "lib/ri_cal/parser.rb", "lib/ri_cal/properties/alarm.rb", "lib/ri_cal/properties/calendar.rb", "lib/ri_cal/properties/event.rb", "lib/ri_cal/properties/freebusy.rb", "lib/ri_cal/properties/journal.rb", "lib/ri_cal/properties/timezone.rb", "lib/ri_cal/properties/timezone_period.rb", "lib/ri_cal/properties/todo.rb", "lib/ri_cal/property_value.rb", "lib/ri_cal/property_value/array.rb", "lib/ri_cal/property_value/cal_address.rb", "lib/ri_cal/property_value/date.rb", "lib/ri_cal/property_value/date_time.rb", "lib/ri_cal/property_value/date_time/additive_methods.rb", "lib/ri_cal/property_value/date_time/time_machine.rb", "lib/ri_cal/property_value/date_time/timezone_support.rb", "lib/ri_cal/property_value/duration.rb", "lib/ri_cal/property_value/geo.rb", "lib/ri_cal/property_value/integer.rb", "lib/ri_cal/property_value/occurrence_list.rb", "lib/ri_cal/property_value/period.rb", "lib/ri_cal/property_value/recurrence_rule.rb", "lib/ri_cal/property_value/recurrence_rule/enumeration_support_methods.rb", "lib/ri_cal/property_value/recurrence_rule/enumerator.rb", "lib/ri_cal/property_value/recurrence_rule/initialization_methods.rb", "lib/ri_cal/property_value/recurrence_rule/negative_setpos_enumerator.rb", "lib/ri_cal/property_value/recurrence_rule/numbered_span.rb", "lib/ri_cal/property_value/recurrence_rule/occurence_incrementer.rb", "lib/ri_cal/property_value/recurrence_rule/recurring_day.rb", "lib/ri_cal/property_value/recurrence_rule/recurring_month_day.rb", "lib/ri_cal/property_value/recurrence_rule/recurring_numbered_week.rb", "lib/ri_cal/property_value/recurrence_rule/recurring_year_day.rb", "lib/ri_cal/property_value/recurrence_rule/validations.rb", "lib/ri_cal/property_value/text.rb", "lib/ri_cal/property_value/uri.rb", "lib/ri_cal/property_value/utc_offset.rb", "lib/ri_cal/required_timezones.rb", "ri_cal.gemspec", "sample_ical_files/from_ical_dot_app/test1.ics", "script/console", "script/destroy", "script/generate", "script/txt2html", "spec/ri_cal/component/alarm_spec.rb", "spec/ri_cal/component/calendar_spec.rb", "spec/ri_cal/component/event_spec.rb", "spec/ri_cal/component/freebusy_spec.rb", "spec/ri_cal/component/journal_spec.rb", "spec/ri_cal/component/t_z_info_timezone_spec.rb", "spec/ri_cal/component/timezone_spec.rb", "spec/ri_cal/component/todo_spec.rb", "spec/ri_cal/component_spec.rb", "spec/ri_cal/core_extensions/string/conversions_spec.rb", "spec/ri_cal/core_extensions/time/calculations_spec.rb", "spec/ri_cal/core_extensions/time/week_day_predicates_spec.rb", "spec/ri_cal/occurrence_enumerator_spec.rb", "spec/ri_cal/parser_spec.rb", "spec/ri_cal/property_value/date_spec.rb", "spec/ri_cal/property_value/date_time_spec.rb", "spec/ri_cal/property_value/duration_spec.rb", "spec/ri_cal/property_value/occurrence_list_spec.rb", "spec/ri_cal/property_value/period_spec.rb", "spec/ri_cal/property_value/recurrence_rule/recurring_year_day_spec.rb", "spec/ri_cal/property_value/recurrence_rule_spec.rb", "spec/ri_cal/property_value/text_spec.rb", "spec/ri_cal/property_value/utc_offset_spec.rb", "spec/ri_cal/property_value_spec.rb", "spec/ri_cal/required_timezones_spec.rb", "spec/ri_cal_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "tasks/gem_loader/load_active_support.rb", "tasks/gem_loader/load_tzinfo_gem.rb", "tasks/ri_cal.rake", "tasks/spec.rake"]
26
+ s.has_rdoc = true
27
+ s.homepage = %q{http://rical.rubyforge.org/}
28
+ s.rdoc_options = ["--main", "README.txt"]
29
+ s.require_paths = ["lib"]
30
+ s.rubyforge_project = %q{rical}
31
+ s.rubygems_version = %q{1.3.2}
32
+ s.summary = %q{This is an UNOFFICIAL version}
33
+
34
+ if s.respond_to? :specification_version then
35
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
36
+ s.specification_version = 3
37
+
38
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
39
+ s.add_development_dependency(%q<newgem>, [">= 1.3.0"])
40
+ s.add_development_dependency(%q<hoe>, [">= 1.8.0"])
41
+ else
42
+ s.add_dependency(%q<newgem>, [">= 1.3.0"])
43
+ s.add_dependency(%q<hoe>, [">= 1.8.0"])
44
+ end
45
+ else
46
+ s.add_dependency(%q<newgem>, [">= 1.3.0"])
47
+ s.add_dependency(%q<hoe>, [">= 1.8.0"])
48
+ end
49
+ end
@@ -0,0 +1,38 @@
1
+ BEGIN:VCALENDAR
2
+ METHOD:PUBLISH
3
+ X-WR-TIMEZONE:America/New_York
4
+ PRODID:-//Apple Inc.//iCal 3.0//EN
5
+ CALSCALE:GREGORIAN
6
+ X-WR-CALNAME:test
7
+ VERSION:2.0
8
+ X-WR-RELCALID:1884C7F8-BC8E-457F-94AC-297871967D5E
9
+ X-APPLE-CALENDAR-COLOR:#2CA10B
10
+ BEGIN:VTIMEZONE
11
+ TZID:US/Eastern
12
+ BEGIN:DAYLIGHT
13
+ TZOFFSETFROM:-0500
14
+ TZOFFSETTO:-0400
15
+ DTSTART:20070311T020000
16
+ RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
17
+ TZNAME:EDT
18
+ END:DAYLIGHT
19
+ BEGIN:STANDARD
20
+ TZOFFSETFROM:-0400
21
+ TZOFFSETTO:-0500
22
+ DTSTART:20071104T020000
23
+ RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
24
+ TZNAME:EST
25
+ END:STANDARD
26
+ END:VTIMEZONE
27
+ BEGIN:VEVENT
28
+ SEQUENCE:5
29
+ TRANSP:OPAQUE
30
+ UID:00481E53-9258-4EA7-9F8D-947D3041A3F2
31
+ DTSTART;TZID=US/Eastern:20090224T090000
32
+ DTSTAMP:20090225T000908Z
33
+ SUMMARY:Test Event
34
+ CREATED:20090225T000839Z
35
+ DTEND;TZID=US/Eastern:20090224T100000
36
+ RRULE:FREQ=DAILY;INTERVAL=1;UNTIL=20090228T045959Z
37
+ END:VEVENT
38
+ END:VCALENDAR
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/ri_cal_newgem.rb'}"
9
+ puts "Loading ri_cal_newgem gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ load File.dirname(__FILE__) + "/../Rakefile"
4
+ require 'rubyforge'
5
+ require 'redcloth'
6
+ require 'syntax/convertors/html'
7
+ require 'erb'
8
+
9
+ download = "http://rubyforge.org/projects/#{$hoe.rubyforge_name}"
10
+ version = $hoe.version
11
+
12
+ def rubyforge_project_id
13
+ RubyForge.new.configure.autoconfig["group_ids"][$hoe.rubyforge_name]
14
+ end
15
+
16
+ class Fixnum #:nodoc:
17
+ def ordinal
18
+ # teens
19
+ return 'th' if (10..19).include?(self % 100)
20
+ # others
21
+ case self % 10
22
+ when 1: return 'st'
23
+ when 2: return 'nd'
24
+ when 3: return 'rd'
25
+ else return 'th'
26
+ end
27
+ end
28
+ end
29
+
30
+ class Time
31
+ def pretty
32
+ return "#{mday}#{mday.ordinal} #{strftime('%B')} #{year}"
33
+ end
34
+ end
35
+
36
+ def convert_syntax(syntax, source)
37
+ return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^<pre>|</pre>$!,'')
38
+ end
39
+
40
+ if ARGV.length >= 1
41
+ src, template = ARGV
42
+ template ||= File.join(File.dirname(__FILE__), '/../website/template.html.erb')
43
+ else
44
+ puts("Usage: #{File.split($0).last} source.txt [template.html.erb] > output.html")
45
+ exit!
46
+ end
47
+
48
+ template = ERB.new(File.open(template).read)
49
+
50
+ title = nil
51
+ body = nil
52
+ File.open(src) do |fsrc|
53
+ title_text = fsrc.readline
54
+ body_text_template = fsrc.read
55
+ body_text = ERB.new(body_text_template).result(binding)
56
+ syntax_items = []
57
+ body_text.gsub!(%r!<(pre|code)[^>]*?syntax=['"]([^'"]+)[^>]*>(.*?)</\1>!m){
58
+ ident = syntax_items.length
59
+ element, syntax, source = $1, $2, $3
60
+ syntax_items << "<#{element} class='syntax'>#{convert_syntax(syntax, source)}</#{element}>"
61
+ "syntax-temp-#{ident}"
62
+ }
63
+ title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip
64
+ body = RedCloth.new(body_text).to_html
65
+ body.gsub!(%r!(?:<pre><code>)?syntax-temp-(\d+)(?:</code></pre>)?!){ syntax_items[$1.to_i] }
66
+ end
67
+ stat = File.stat(src)
68
+ created = stat.ctime
69
+ modified = stat.mtime
70
+
71
+ $stdout << template.result(binding)
@@ -0,0 +1,12 @@
1
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
2
+
3
+ require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
4
+
5
+ describe RiCal::Component::Alarm do
6
+
7
+ describe ".entity_name" do
8
+ it "should be VALARM" do
9
+ RiCal::Component::Alarm.entity_name.should == "VALARM"
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,54 @@
1
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
2
+
3
+ require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
4
+
5
+ describe RiCal::Component::Calendar do
6
+
7
+ context ".entity_name" do
8
+ it "should be VCALENDAR" do
9
+ RiCal::Component::Calendar.entity_name.should == "VCALENDAR"
10
+ end
11
+ end
12
+
13
+ context "a new instance" do
14
+ before(:each) do
15
+ @it = RiCal.Calendar
16
+ end
17
+
18
+ it "should have a tz_source of 'TZ_INFO" do
19
+ @it.tz_source.should == "TZINFO"
20
+ end
21
+
22
+ it "should export a product id with an X-RICAL-TZSOURCE parameter of TZINFO" do
23
+ @it.export.should match(%r{\nPRODID;X-RICAL-TZSOURCE=TZINFO:-//com.denhaven2/NONSGML ri_cal gem//EN\n})
24
+ end
25
+ end
26
+
27
+ context "an imported instance with a tzinfo source" do
28
+ before(:each) do
29
+ @it = RiCal.parse_string("BEGIN:VCALENDAR\nPRODID;X-RICAL-TZSOURCE=TZINFO:-\/\/com.denhaven2\/NONSGML ri_cal gem\/\/EN\nCALSCALE:GREGORIAN\nVERSION:2.0\nEND:VCALENDAR\n").first
30
+ end
31
+
32
+ it "should have a tz_source of 'TZ_INFO" do
33
+ @it.tz_source.should == "TZINFO"
34
+ end
35
+
36
+ it "should export a product id with an X-RICAL-TZSOURCE parameter of TZINFO" do
37
+ @it.export.should match(%r{\nPRODID;X-RICAL-TZSOURCE=TZINFO:-//com.denhaven2/NONSGML ri_cal gem//EN\n})
38
+ end
39
+ end
40
+
41
+ context "an imported instance without a tzinfo source" do
42
+ before(:each) do
43
+ @it = RiCal.parse_string("BEGIN:VCALENDAR\nPRODID:-//Apple Inc.//iCal 3.0//EN\nEND:VCALENDAR\n").first
44
+ end
45
+
46
+ it "should have a tz_source of nil" do
47
+ @it.tz_source.should be_nil
48
+ end
49
+
50
+ it "should export not export a product id with an X-RICAL-TZSOURCE parameter of TZINFO" do
51
+ @it.export.should_not match(%r{X-RICAL-TZSOURCE=TZINFO:})
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,601 @@
1
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
2
+
3
+ require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
4
+
5
+ describe RiCal::Component::Event do
6
+
7
+ context "rdate property methods" do
8
+ before(:each) do
9
+ @event = RiCal.Event do
10
+ rdate "20090101"
11
+ end
12
+ end
13
+
14
+ context "#rdate=" do
15
+
16
+ it "should accept a single Date and replace the existing rdate" do
17
+ @event.rdate = Date.parse("20090102")
18
+ @event.rdate.should == [[Date.parse("20090102")]]
19
+ end
20
+
21
+ it "should accept a single rfc2445 date format string and replace the existing rdate" do
22
+ @event.rdate = "20090102"
23
+ @event.rdate.should == [[Date.parse("20090102")]]
24
+ end
25
+
26
+ it "should accept a single DateTime and replace the existing rdate" do
27
+ @event.rdate = DateTime.parse("20090102T012345")
28
+ @event.rdate.should == [[DateTime.parse("20090102T012345")]]
29
+ end
30
+
31
+ it "should accept a single Time and replace the existing rdate" do
32
+ ::RiCal::PropertyValue::DateTime.default_tzid = 'UTC'
33
+ @event.rdate = Time.local(2009, 1, 2, 1, 23, 45)
34
+ @event.rdate.should == [[result_time_in_zone(2009, 1, 2, 1, 23, 45, "UTC")]]
35
+ end
36
+
37
+ it "should accept a single rfc2445 date-time format string and replace the existing rdate" do
38
+ @event.rdate = "20090102T012345"
39
+ @event.rdate.should == [[DateTime.parse("20090102T012345")]]
40
+ end
41
+
42
+ it "should accept a tzid prefixed rfc2445 date-time format string and replace the existing rdate" do
43
+ @event.rdate = "TZID=America/New_York:20090102T012345"
44
+ @event.rdate.should == [[result_time_in_zone(2009, 1, 2, 1, 23, 45, "America/New_York")]]
45
+ end
46
+
47
+ end
48
+
49
+ end
50
+
51
+ context "comment property methods" do
52
+ before(:each) do
53
+ @event = RiCal.Event
54
+ @event.comment = "Comment"
55
+ end
56
+
57
+ context "#comment=" do
58
+ it "should result in a single comment for the event" do
59
+ @event.comment.should == ["Comment"]
60
+ end
61
+
62
+ it "should replace existing comments" do
63
+ @event.comment = "Replacement"
64
+ @event.comment.should == ["Replacement"]
65
+ end
66
+ end
67
+
68
+ context "#comments=" do
69
+ it "should result in a multiple comments for the event replacing existing comments" do
70
+ @event.comments = "New1", "New2"
71
+ @event.comment.should == ["New1", "New2"]
72
+ end
73
+ end
74
+
75
+ context "#add_comment" do
76
+ it "should add a single comment" do
77
+ @event.add_comment "New1"
78
+ @event.comment.should == ["Comment", "New1"]
79
+ end
80
+ end
81
+
82
+ context "#add_comments" do
83
+ it "should add multiple comments" do
84
+ @event.add_comments "New1", "New2"
85
+ @event.comment.should == ["Comment", "New1", "New2"]
86
+ end
87
+ end
88
+
89
+ context "#remove_comment" do
90
+ it "should remove a single comment" do
91
+ @event.add_comment "New1"
92
+ @event.remove_comment "Comment"
93
+ @event.comment.should == ["New1"]
94
+ end
95
+ end
96
+
97
+ context "#remove_comments" do
98
+ it "should remove multiple comments" do
99
+ @event.add_comments "New1", "New2", "New3"
100
+ @event.remove_comments "New2", "Comment"
101
+ @event.comment.should == ["New1", "New3"]
102
+ end
103
+ end
104
+ end
105
+
106
+ context ".dtstart=" do
107
+ before(:each) do
108
+ @event = RiCal.Event
109
+ end
110
+
111
+ context "with a datetime only string" do
112
+ before(:each) do
113
+ @event.dtstart = "20090514T202400"
114
+ @it = @event.dtstart
115
+ end
116
+
117
+ it "should interpret it as the correct date-time" do
118
+ @it.should == DateTime.civil(2009, 5, 14, 20, 24, 00, Rational(0,24))
119
+ end
120
+
121
+ it "should interpret it as a floating date" do
122
+ @it.tzid.should == :floating
123
+ end
124
+ end
125
+
126
+ context "with a TZID and datetime string" do
127
+ before(:each) do
128
+ @event.dtstart = "TZID=America/New_York:20090514T202400"
129
+ @it = @event.dtstart
130
+ end
131
+
132
+ it "should interpret it as the correct date-time" do
133
+ @it.should == result_time_in_zone(2009, 5, 14, 20, 24, 00, "America/New_York")
134
+ end
135
+
136
+ it "should set the tzid to America/New_York" do
137
+ @it.tzid.should == "America/New_York"
138
+ end
139
+ end
140
+
141
+ context "with a zulu datetime only string" do
142
+ before(:each) do
143
+ @event.dtstart = "20090514T202400Z"
144
+ @it = @event.dtstart
145
+ end
146
+
147
+ it "should interpret it as the correct date-time" do
148
+ @it.should == DateTime.civil(2009, 5, 14, 20, 24, 00, Rational(0,24))
149
+ end
150
+
151
+ it "should set the tzid to UTC" do
152
+ @it.tzid.should == "UTC"
153
+ end
154
+ end
155
+
156
+ context "with a date string" do
157
+ before(:each) do
158
+ @event.dtstart = "20090514"
159
+ @it = @event.dtstart
160
+ end
161
+
162
+ it "should interpret it as the correct date-time" do
163
+ @it.should == Date.parse("14 May 2009")
164
+ end
165
+ end
166
+ end
167
+
168
+ context ".entity_name" do
169
+ it "should be VEVENT" do
170
+ RiCal::Component::Event.entity_name.should == "VEVENT"
171
+ end
172
+ end
173
+
174
+ context "with an rrule" do
175
+ before(:each) do
176
+ @it = RiCal::Component::Event.parse_string("BEGIN:VEVENT\nRRULE:FREQ=DAILY\nEND:VEVENT").first
177
+ end
178
+
179
+ it "should have an array of rrules" do
180
+ @it.rrule.should be_kind_of(Array)
181
+ end
182
+ end
183
+
184
+ context ".start_time" do
185
+
186
+ it "should be nil if there is no dtstart property" do
187
+ RiCal.Event.start_time.should be_nil
188
+ end
189
+
190
+ it "should be the same as dtstart for a date time" do
191
+ event = RiCal.Event {|e| e.dtstart = "20090525T151900"}
192
+ event.start_time.should == DateTime.civil(2009,05,25,15,19,0,0)
193
+ end
194
+
195
+ it "should be the start of the day of dtstart for a date" do
196
+ event = RiCal.Event {|e| e.dtstart = "20090525"}
197
+ event.start_time.should == DateTime.civil(2009,05,25,0,0,0,0)
198
+ end
199
+ end
200
+
201
+ context ".finish_time" do
202
+ before(:each) do
203
+ @event = RiCal.Event {|e| e.dtstart = "20090525T151900"}
204
+ end
205
+
206
+ context "with a given dtend" do
207
+ it "should be the same as dtend for a date time" do
208
+ @event.dtend = "20090525T161900"
209
+ @event.finish_time.should == DateTime.civil(2009,05,25,16,19,0,0)
210
+ end
211
+
212
+
213
+ end
214
+
215
+ context "with no dtend" do
216
+ context "and a duration" do
217
+ it "should be the dtstart plus the duration" do
218
+ @event.duration = "+P1H"
219
+ @event.finish_time.should == DateTime.civil(2009,5,25,16,19,0,0)
220
+ end
221
+ end
222
+
223
+ context "and no duration" do
224
+ context "when the dtstart is not set" do
225
+ before(:each) do
226
+ @event.dtstart_property = nil
227
+ end
228
+
229
+ it "should be nil" do
230
+ @event.finish_time.should be_nil
231
+ end
232
+ end
233
+ context "when the dstart is a datetime" do
234
+ # For cases where a "VEVENT" calendar component
235
+ # specifies a "DTSTART" property with a DATE-TIME data type but no
236
+ # "DTEND" property, the event ends on the same calendar date and time
237
+ # of day specified by the "DTSTART" property. RFC 2445 p 53
238
+ it "should be the same as start_time" do
239
+ @event.finish_time.should == @event.start_time
240
+ end
241
+ end
242
+ context "when the dtstart is a date" do
243
+ # For cases where a "VEVENT" calendar component specifies a "DTSTART" property with a DATE data type
244
+ # but no "DTEND" property, the events non-inclusive end is the end of the calendar date specified by
245
+ # the "DTSTART" property. RFC 2445 p 53
246
+
247
+ it "should be the end of the same day as start_time" do
248
+ @event.dtstart = "20090525"
249
+ @event.finish_time.should == DateTime.civil(2009,5,25,23,59,59,0)
250
+ end
251
+ end
252
+ end
253
+ end
254
+
255
+ end
256
+
257
+ context ".zulu_occurrence_range_start_time" do
258
+
259
+ it "should be nil if there is no dtstart property" do
260
+ RiCal.Event.zulu_occurrence_range_start_time.should be_nil
261
+ end
262
+
263
+ it "should be the utc equivalent of dtstart for a date time" do
264
+ event = RiCal.Event {|e| e.dtstart = "TZID=America/New_York:20090525T151900"}
265
+ event.zulu_occurrence_range_start_time.should == DateTime.civil(2009,05,25,19,19,0,0)
266
+ end
267
+
268
+ it "should be the utc time of the start of the day of dtstart in the earliest timezone for a date" do
269
+ event = RiCal.Event {|e| e.dtstart = "20090525"}
270
+ event.zulu_occurrence_range_start_time.should == DateTime.civil(2009,05,24,12,0,0,0)
271
+ end
272
+
273
+ it "should be the utc time of the dtstart in the earliest timezone if dtstart is a floating datetime" do
274
+ event = RiCal.Event {|e| e.dtstart = "20090525T151900"}
275
+ event.zulu_occurrence_range_start_time.should == DateTime.civil(2009,05,25,3,19,0,0)
276
+ end
277
+ end
278
+
279
+ context ".zulu_occurrence_range_finish_time" do
280
+ before(:each) do
281
+ @event = RiCal.Event {|e| e.dtstart = "TZID=America/New_York:20090525T151900"}
282
+ end
283
+
284
+ context "with a given dtend" do
285
+ it "should be the utc equivalent of dtend if dtend is a date time" do
286
+ @event.dtend = "TZID=America/New_York:20090525T161900"
287
+ @event.zulu_occurrence_range_finish_time.should == DateTime.civil(2009,05,25, 20,19,0,0)
288
+ end
289
+ end
290
+
291
+ context "with no dtend" do
292
+ context "and a duration" do
293
+ it "should be the dtstart plus the duration" do
294
+ @event.duration = "+P1H"
295
+ @event.zulu_occurrence_range_finish_time.should == DateTime.civil(2009,5,25,20 ,19,0,0)
296
+ end
297
+ end
298
+
299
+ context "and no duration" do
300
+ context "when the dtstart is not set" do
301
+ before(:each) do
302
+ @event.dtstart_property = nil
303
+ end
304
+
305
+ it "should be nil" do
306
+ @event.zulu_occurrence_range_finish_time.should be_nil
307
+ end
308
+ end
309
+
310
+ context "when the dstart is a datetime" do
311
+
312
+ it "should be the same as start_time" do
313
+ @event.zulu_occurrence_range_finish_time.should == @event.zulu_occurrence_range_start_time
314
+ end
315
+ end
316
+
317
+ context "when the dtstart is a date" do
318
+ it "should be the utc of end of the same day as start_time in the westermost time zone" do
319
+ @event.dtstart = "20090525"
320
+ @event.zulu_occurrence_range_finish_time.should == DateTime.civil(2009,5,26,11,59,59,0)
321
+ end
322
+ end
323
+ end
324
+ end
325
+ end
326
+
327
+ context "description property" do
328
+ before(:each) do
329
+ @ical_desc = "posted by Joyce per Zan\\nASheville\\, Rayan's Restauratn\\, Biltm\n ore Square"
330
+ @ruby_desc = "posted by Joyce per Zan\nASheville, Rayan's Restauratn, Biltmore Square"
331
+ @it = RiCal::Component::Event.parse_string("BEGIN:VEVENT\nDESCRIPTION:#{@ical_desc}\nEND:VEVENT").first
332
+ end
333
+
334
+ it "should product the converted ruby value" do
335
+ @it.description.should == @ruby_desc
336
+ end
337
+
338
+ it "should produce escaped text for ical" do
339
+ @it.description = "This is a\nnew description, yes; it is"
340
+ @it.description_property.value.should == 'This is a\nnew description\, yes\; it is'
341
+ end
342
+
343
+ end
344
+
345
+ context "with both dtend and duration specified" do
346
+ before(:each) do
347
+ @it = RiCal::Component::Event.parse_string("BEGIN:VEVENT\nDTEND:19970903T190000Z\nDURATION:H1\nEND:VEVENT").first
348
+ end
349
+
350
+ it "should be invalid" do
351
+ @it.should_not be_valid
352
+ end
353
+ end
354
+
355
+ context "with a duration property" do
356
+ before(:each) do
357
+ @it = RiCal::Component::Event.parse_string("BEGIN:VEVENT\nDURATION:H1\nEND:VEVENT").first
358
+ end
359
+
360
+ it "should have a duration property" do
361
+ @it.duration_property.should be
362
+ end
363
+
364
+ it "should have a duration of 1 Hour" do
365
+ @it.duration_property.value.should == "H1"
366
+ end
367
+
368
+ it "should reset the duration property if the dtend property is set" do
369
+ @it.dtend_property = "19970101T123456".to_ri_cal_date_time_value
370
+ @it.duration_property.should be_nil
371
+ end
372
+
373
+ it "should reset the duration property if the dtend ruby value is set" do
374
+ @it.dtend = "19970101"
375
+ @it.duration_property.should == nil
376
+ end
377
+ end
378
+
379
+ context "with a dtend property" do
380
+ before(:each) do
381
+ @it = RiCal::Component::Event.parse_string("BEGIN:VEVENT\nDTEND:19970903T190000Z\nEND:VEVENT").first
382
+ end
383
+
384
+ it "should have a duration property" do
385
+ @it.dtend_property.should be
386
+ end
387
+
388
+ it "should reset the dtend property if the duration property is set" do
389
+ @it.duration_property = "P1H".to_ri_cal_duration_value
390
+ @it.dtend_property.should be_nil
391
+ end
392
+
393
+ it "should reset the dtend property if the duration ruby value is set" do
394
+ @it.duration = "P1H".to_ri_cal_duration_value
395
+ @it.dtend_property.should be_nil
396
+ end
397
+ end
398
+
399
+ context "with a nested alarm component" do
400
+ before(:each) do
401
+ @it = RiCal::Component::Event.parse_string("BEGIN:VEVENT\nDTEND:19970903T190000Z\n\nBEGIN:VALARM\nEND:VALARM\nEND:VEVENT").first
402
+ end
403
+
404
+ it "should have one alarm" do
405
+ @it.alarms.length.should == 1
406
+ end
407
+
408
+ it "which should be an Alarm component" do
409
+ @it.alarms.first.should be_kind_of(RiCal::Component::Alarm)
410
+ end
411
+ end
412
+
413
+ context ".export" do
414
+ require 'rubygems'
415
+ require 'tzinfo'
416
+
417
+ def date_time_with_tzinfo_zone(date_time, timezone="America/New_York")
418
+ date_time.dup.set_tzid(timezone)
419
+ end
420
+
421
+ # Undo the effects of RFC2445 line folding
422
+ def unfold(string)
423
+ string.gsub("\n ", "")
424
+ end
425
+
426
+ before(:each) do
427
+ cal = RiCal.Calendar
428
+ @it = RiCal::Component::Event.new(cal)
429
+ end
430
+
431
+ it "should cause a VTIMEZONE to be included for a dtstart with a local timezone" do
432
+ @it.dtstart = date_time_with_tzinfo_zone(DateTime.parse("April 22, 2009 17:55"), "America/New_York")
433
+ unfold(@it.export).should match(/BEGIN:VTIMEZONE\nTZID;X-RICAL-TZSOURCE=TZINFO:America\/New_York\n/)
434
+ end
435
+
436
+ it "should properly format dtstart with a UTC date-time" do
437
+ @it.dtstart = DateTime.parse("April 22, 2009 1:23:45").set_tzid("UTC")
438
+ unfold(@it.export).should match(/^DTSTART;VALUE=DATE-TIME:20090422T012345Z$/)
439
+ end
440
+
441
+ it "should properly format dtstart with a floating date-time" do
442
+ @it.dtstart = DateTime.parse("April 22, 2009 1:23:45").with_floating_timezone
443
+ unfold(@it.export).should match(/^DTSTART;VALUE=DATE-TIME:20090422T012345$/)
444
+ end
445
+
446
+ it "should properly format dtstart with a local time zone" do
447
+ @it.dtstart = date_time_with_tzinfo_zone(DateTime.parse("April 22, 2009 17:55"), "America/New_York")
448
+ unfold(@it.export).should match(/^DTSTART;TZID=America\/New_York;VALUE=DATE-TIME:20090422T175500$/)
449
+ end
450
+
451
+ it "should properly format dtstart with a date" do
452
+ @it.dtstart = Date.parse("April 22, 2009")
453
+ unfold(@it.export).should match(/^DTSTART;VALUE=DATE:20090422$/)
454
+ end
455
+
456
+ it "should properly fold on export when the description contains a carriage return" do
457
+ @it.description = "Weather report looks nice, 80 degrees and partly cloudy, so following Michael's suggestion, let's meet at the food court at Crossroads:\n\rhttp://www.shopcrossroadsplaza.c...\n"
458
+ export_string = @it.export
459
+ export_string.should match(%r(^DESCRIPTION:Weather report looks nice\\, 80 degrees and partly cloudy\\, so$))
460
+ export_string.should match(%r(^ following Michael's suggestion\\, let's meet at the food court at Crossr$))
461
+ export_string.should match(%r(^ oads:\\nhttp://www\.shopcrossroadsplaza.c\.\.\.\\n$))
462
+ end
463
+ end
464
+
465
+ if RiCal::TimeWithZone
466
+ context "with ActiveSupport loaded" do
467
+
468
+ context "an event with an timezoned exdate" do
469
+ before(:each) do
470
+ @old_timezone = Time.zone
471
+ Time.zone = "America/New_York"
472
+ @exception_date_time = Time.zone.local(2009, 5, 19, 11, 13)
473
+ cal = RiCal.Calendar do |cal|
474
+ cal.event do |event|
475
+ event.add_exdate @exception_date_time
476
+ end
477
+ end
478
+ @event = cal.events.first
479
+ end
480
+
481
+ after(:each) do
482
+ Time.zone = @old_timezone
483
+ end
484
+
485
+ it "should pickup the timezone in the exdate property" do
486
+ @event.exdate.first.first.tzid.should == "America/New_York"
487
+ end
488
+
489
+ it "should have the timezone in the ical representation of the exdate property" do
490
+ @event.exdate_property.to_s.should match(%r{;TZID=America/New_York[:;]})
491
+ end
492
+ end
493
+
494
+ context "An event in a non-tzinfo source calendar" do
495
+ before(:each) do
496
+ cals = RiCal.parse_string <<ENDCAL
497
+ BEGIN:VCALENDAR
498
+ X-WR-TIMEZONE:America/New_York
499
+ PRODID:-//Apple Inc.//iCal 3.0//EN
500
+ CALSCALE:GREGORIAN
501
+ BEGIN:VTIMEZONE
502
+ TZID:US/Eastern
503
+ BEGIN:DAYLIGHT
504
+ TZOFFSETFROM:-0500
505
+ TZOFFSETTO:-0400
506
+ DTSTART:20070311T020000
507
+ RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
508
+ TZNAME:EDT
509
+ END:DAYLIGHT
510
+ BEGIN:STANDARD
511
+ TZOFFSETFROM:-0400
512
+ TZOFFSETTO:-0500
513
+ DTSTART:20071104T020000
514
+ RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
515
+ TZNAME:EST
516
+ END:STANDARD
517
+ END:VTIMEZONE
518
+ BEGIN:VEVENT
519
+ SEQUENCE:5
520
+ TRANSP:OPAQUE
521
+ UID:00481E53-9258-4EA7-9F8D-947D3041A3F2
522
+ DTSTART;TZID=US/Eastern:20090224T090000
523
+ DTSTAMP:20090225T000908Z
524
+ SUMMARY:Test Event
525
+ CREATED:20090225T000839Z
526
+ DTEND;TZID=US/Eastern:20090224T100000
527
+ RRULE:FREQ=DAILY;INTERVAL=1;UNTIL=20090228T045959Z
528
+ END:VEVENT
529
+ END:VCALENDAR
530
+ ENDCAL
531
+ @event = cals.first.events.first
532
+ end
533
+
534
+ it "should produce a DateTime for dtstart" do
535
+ @event.dtstart.should be_instance_of(DateTime)
536
+ end
537
+ end
538
+
539
+ context "An event starting in Paris and ending in New York" do
540
+
541
+ before(:each) do
542
+ @start = Time.now.utc.in_time_zone("Europe/Paris")
543
+ @finish = Time.now.utc.in_time_zone("America/New_York")
544
+ cal = RiCal.Calendar do |ical|
545
+ ical.event do |ievent|
546
+ ievent.dtstart @start
547
+ ievent.dtend @finish
548
+ end
549
+ end
550
+ @event = cal.events.first
551
+ end
552
+
553
+ it "should have the right time zone for dtstart" do
554
+ @event.dtstart.tzid.should == "Europe/Paris"
555
+ end
556
+
557
+ it "should produce a TimeWithZone for dtstart" do
558
+ @event.dtstart.should be_instance_of(RiCal::TimeWithZone)
559
+ end
560
+
561
+ # ActiveRecord::TimeWithZone doesn't implement == as expected
562
+ it "should produce a dtstart which looks like the provided value" do
563
+ @event.dtstart.to_s.should == @start.to_s
564
+ end
565
+
566
+ it "should have the right time zone for dtend" do
567
+ @event.dtend.tzid.should == "America/New_York"
568
+ end
569
+
570
+ it "should produce a TimeWithZone for dtend" do
571
+ @event.dtend.should be_instance_of(RiCal::TimeWithZone)
572
+ end
573
+
574
+ # ActiveRecord::TimeWithZone doesn't implement == as expected
575
+ it "should produce a dtend which looks like the provided value" do
576
+ @event.dtend.to_s.should == @finish.to_s
577
+ end
578
+ end
579
+ end
580
+ end
581
+
582
+ context "An event with a floating start" do
583
+
584
+ before(:each) do
585
+ cal = RiCal.Calendar do |ical|
586
+ ical.event do |ievent|
587
+ ievent.dtstart "20090530T120000"
588
+ end
589
+ end
590
+ @event = cal.events.first
591
+ end
592
+
593
+ it "should produce a DateTime for dtstart" do
594
+ @event.dtstart.should be_instance_of(DateTime)
595
+ end
596
+
597
+ it "should have a floating dtstart" do
598
+ @event.dtstart.should have_floating_timezone
599
+ end
600
+ end
601
+ end