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.
- data/History.txt +45 -0
- data/Manifest.txt +129 -0
- data/README.txt +394 -0
- data/Rakefile +31 -0
- data/bin/ri_cal +8 -0
- data/component_attributes/alarm.yml +10 -0
- data/component_attributes/calendar.yml +4 -0
- data/component_attributes/component_property_defs.yml +180 -0
- data/component_attributes/event.yml +45 -0
- data/component_attributes/freebusy.yml +16 -0
- data/component_attributes/journal.yml +35 -0
- data/component_attributes/timezone.yml +3 -0
- data/component_attributes/timezone_period.yml +11 -0
- data/component_attributes/todo.yml +46 -0
- data/copyrights.txt +1 -0
- data/docs/draft-ietf-calsify-2446bis-08.txt +7280 -0
- data/docs/draft-ietf-calsify-rfc2445bis-09.txt +10416 -0
- data/docs/incrementers.txt +7 -0
- data/docs/rfc2445.pdf +0 -0
- data/lib/ri_cal.rb +144 -0
- data/lib/ri_cal/component.rb +247 -0
- data/lib/ri_cal/component/alarm.rb +21 -0
- data/lib/ri_cal/component/calendar.rb +219 -0
- data/lib/ri_cal/component/event.rb +60 -0
- data/lib/ri_cal/component/freebusy.rb +18 -0
- data/lib/ri_cal/component/journal.rb +30 -0
- data/lib/ri_cal/component/t_z_info_timezone.rb +123 -0
- data/lib/ri_cal/component/timezone.rb +196 -0
- data/lib/ri_cal/component/timezone/daylight_period.rb +25 -0
- data/lib/ri_cal/component/timezone/standard_period.rb +23 -0
- data/lib/ri_cal/component/timezone/timezone_period.rb +53 -0
- data/lib/ri_cal/component/todo.rb +43 -0
- data/lib/ri_cal/core_extensions.rb +6 -0
- data/lib/ri_cal/core_extensions/array.rb +7 -0
- data/lib/ri_cal/core_extensions/array/conversions.rb +15 -0
- data/lib/ri_cal/core_extensions/date.rb +13 -0
- data/lib/ri_cal/core_extensions/date/conversions.rb +61 -0
- data/lib/ri_cal/core_extensions/date_time.rb +15 -0
- data/lib/ri_cal/core_extensions/date_time/conversions.rb +50 -0
- data/lib/ri_cal/core_extensions/object.rb +8 -0
- data/lib/ri_cal/core_extensions/object/conversions.rb +20 -0
- data/lib/ri_cal/core_extensions/string.rb +8 -0
- data/lib/ri_cal/core_extensions/string/conversions.rb +63 -0
- data/lib/ri_cal/core_extensions/time.rb +13 -0
- data/lib/ri_cal/core_extensions/time/calculations.rb +153 -0
- data/lib/ri_cal/core_extensions/time/conversions.rb +61 -0
- data/lib/ri_cal/core_extensions/time/tzid_access.rb +50 -0
- data/lib/ri_cal/core_extensions/time/week_day_predicates.rb +88 -0
- data/lib/ri_cal/floating_timezone.rb +32 -0
- data/lib/ri_cal/invalid_property_value.rb +8 -0
- data/lib/ri_cal/invalid_timezone_identifer.rb +20 -0
- data/lib/ri_cal/occurrence_enumerator.rb +206 -0
- data/lib/ri_cal/occurrence_period.rb +17 -0
- data/lib/ri_cal/parser.rb +138 -0
- data/lib/ri_cal/properties/alarm.rb +390 -0
- data/lib/ri_cal/properties/calendar.rb +164 -0
- data/lib/ri_cal/properties/event.rb +1526 -0
- data/lib/ri_cal/properties/freebusy.rb +594 -0
- data/lib/ri_cal/properties/journal.rb +1240 -0
- data/lib/ri_cal/properties/timezone.rb +151 -0
- data/lib/ri_cal/properties/timezone_period.rb +416 -0
- data/lib/ri_cal/properties/todo.rb +1562 -0
- data/lib/ri_cal/property_value.rb +149 -0
- data/lib/ri_cal/property_value/array.rb +27 -0
- data/lib/ri_cal/property_value/cal_address.rb +11 -0
- data/lib/ri_cal/property_value/date.rb +175 -0
- data/lib/ri_cal/property_value/date_time.rb +335 -0
- data/lib/ri_cal/property_value/date_time/additive_methods.rb +44 -0
- data/lib/ri_cal/property_value/date_time/time_machine.rb +181 -0
- data/lib/ri_cal/property_value/date_time/timezone_support.rb +96 -0
- data/lib/ri_cal/property_value/duration.rb +110 -0
- data/lib/ri_cal/property_value/geo.rb +11 -0
- data/lib/ri_cal/property_value/integer.rb +12 -0
- data/lib/ri_cal/property_value/occurrence_list.rb +144 -0
- data/lib/ri_cal/property_value/period.rb +82 -0
- data/lib/ri_cal/property_value/recurrence_rule.rb +145 -0
- data/lib/ri_cal/property_value/recurrence_rule/enumeration_support_methods.rb +97 -0
- data/lib/ri_cal/property_value/recurrence_rule/enumerator.rb +79 -0
- data/lib/ri_cal/property_value/recurrence_rule/initialization_methods.rb +148 -0
- data/lib/ri_cal/property_value/recurrence_rule/negative_setpos_enumerator.rb +53 -0
- data/lib/ri_cal/property_value/recurrence_rule/numbered_span.rb +31 -0
- data/lib/ri_cal/property_value/recurrence_rule/occurence_incrementer.rb +793 -0
- data/lib/ri_cal/property_value/recurrence_rule/recurring_day.rb +131 -0
- data/lib/ri_cal/property_value/recurrence_rule/recurring_month_day.rb +60 -0
- data/lib/ri_cal/property_value/recurrence_rule/recurring_numbered_week.rb +33 -0
- data/lib/ri_cal/property_value/recurrence_rule/recurring_year_day.rb +49 -0
- data/lib/ri_cal/property_value/recurrence_rule/validations.rb +125 -0
- data/lib/ri_cal/property_value/text.rb +40 -0
- data/lib/ri_cal/property_value/uri.rb +11 -0
- data/lib/ri_cal/property_value/utc_offset.rb +33 -0
- data/lib/ri_cal/required_timezones.rb +55 -0
- data/ri_cal.gemspec +49 -0
- data/sample_ical_files/from_ical_dot_app/test1.ics +38 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +71 -0
- data/spec/ri_cal/component/alarm_spec.rb +12 -0
- data/spec/ri_cal/component/calendar_spec.rb +54 -0
- data/spec/ri_cal/component/event_spec.rb +601 -0
- data/spec/ri_cal/component/freebusy_spec.rb +12 -0
- data/spec/ri_cal/component/journal_spec.rb +37 -0
- data/spec/ri_cal/component/t_z_info_timezone_spec.rb +36 -0
- data/spec/ri_cal/component/timezone_spec.rb +218 -0
- data/spec/ri_cal/component/todo_spec.rb +112 -0
- data/spec/ri_cal/component_spec.rb +224 -0
- data/spec/ri_cal/core_extensions/string/conversions_spec.rb +78 -0
- data/spec/ri_cal/core_extensions/time/calculations_spec.rb +188 -0
- data/spec/ri_cal/core_extensions/time/week_day_predicates_spec.rb +45 -0
- data/spec/ri_cal/occurrence_enumerator_spec.rb +573 -0
- data/spec/ri_cal/parser_spec.rb +303 -0
- data/spec/ri_cal/property_value/date_spec.rb +53 -0
- data/spec/ri_cal/property_value/date_time_spec.rb +383 -0
- data/spec/ri_cal/property_value/duration_spec.rb +126 -0
- data/spec/ri_cal/property_value/occurrence_list_spec.rb +72 -0
- data/spec/ri_cal/property_value/period_spec.rb +49 -0
- data/spec/ri_cal/property_value/recurrence_rule/recurring_year_day_spec.rb +21 -0
- data/spec/ri_cal/property_value/recurrence_rule_spec.rb +1814 -0
- data/spec/ri_cal/property_value/text_spec.rb +25 -0
- data/spec/ri_cal/property_value/utc_offset_spec.rb +48 -0
- data/spec/ri_cal/property_value_spec.rb +125 -0
- data/spec/ri_cal/required_timezones_spec.rb +67 -0
- data/spec/ri_cal_spec.rb +53 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +46 -0
- data/tasks/gem_loader/load_active_support.rb +3 -0
- data/tasks/gem_loader/load_tzinfo_gem.rb +2 -0
- data/tasks/ri_cal.rake +410 -0
- data/tasks/spec.rake +50 -0
- 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
|
data/ri_cal.gemspec
ADDED
|
@@ -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
|
data/script/console
ADDED
|
@@ -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"
|
data/script/destroy
ADDED
|
@@ -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)
|
data/script/generate
ADDED
|
@@ -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)
|
data/script/txt2html
ADDED
|
@@ -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
|