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,23 @@
1
+ module RiCal
2
+ class Component
3
+ class Timezone
4
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
5
+ #
6
+ # A StandardPeriod is a TimezonePeriod during which daylight saving time is *not* in effect
7
+ class StandardPeriod < TimezonePeriod #:nodoc: all
8
+
9
+ def self.entity_name #:nodoc:
10
+ "STANDARD"
11
+ end
12
+
13
+ def dst?
14
+ false
15
+ end
16
+
17
+ def ambiguous_local?(time)
18
+ [time.year, time.month, time.day] == [dtstart.year, dtstart.month, dtstart.day]
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,53 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. .. properties timezone_period.rb])
2
+
3
+ module RiCal
4
+ class Component
5
+ class Timezone
6
+ #- ©2009 Rick DeNatale, All rights reserved. Refer to the file README.txt for the license
7
+ #
8
+ # A TimezonePeriod is a component of a timezone representing a period during which a particular offset from UTC is
9
+ # in effect.
10
+ #
11
+ # to see the property accessing methods for this class see the RiCal::Properties::TimezonePeriod module
12
+ class TimezonePeriod < Component
13
+ include Properties::TimezonePeriod
14
+
15
+ include OccurrenceEnumerator
16
+
17
+ def zone_identifier #:nodoc:
18
+ tzname.first
19
+ end
20
+
21
+ def dtend #:nodoc:
22
+ nil
23
+ end
24
+
25
+ def exdate_property #:nodoc:
26
+ nil
27
+ end
28
+
29
+ def utc_total_offset #:nodoc:
30
+ tzoffsetto_property.to_seconds
31
+ end
32
+
33
+ def exrule_property #:nodoc:
34
+ nil
35
+ end
36
+
37
+ def last_before_utc(utc_time) #:nodoc:
38
+ last_before_local(utc_time + tzoffsetfrom_property)
39
+ end
40
+
41
+ def last_before_local(local_time) #:nodoc:
42
+ cand_occurrence = nil
43
+ each do |occurrence|
44
+ return cand_occurrence if occurrence.dtstart_property > local_time
45
+ cand_occurrence = occurrence
46
+ end
47
+ return cand_occurrence
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+
@@ -0,0 +1,43 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. properties todo.rb])
2
+
3
+ module RiCal
4
+ class Component
5
+ #- ©2009 Rick DeNatale
6
+ #- All rights reserved. Refer to the file README.txt for the license
7
+ #
8
+ # A Todo (VTODO) calendar component groups properties describing a to-do
9
+ # Todos may have multiple occurrences
10
+ #
11
+ # Todos may also contain one or more ALARM subcomponents
12
+ # to see the property accessing methods for this class see the RiCal::Properties::Todo module
13
+ # to see the methods for enumerating occurrences of recurring to-dos see the RiCal::OccurrenceEnumerator module
14
+ class Todo < Component
15
+ include Properties::Todo
16
+
17
+ def self.entity_name #:nodoc:
18
+ "VTODO"
19
+ end
20
+
21
+ def subcomponent_class #:nodoc:
22
+ {:alarm => Alarm }
23
+ end
24
+
25
+ # Return a date_time representing the time at which the todo should start
26
+ def start_time
27
+ dtstart_property ? dtstart.to_datetime : nil
28
+ end
29
+
30
+ # Return a date_time representing the time at which the todo is due
31
+ def finish_time
32
+ if due
33
+ due_property.to_finish_time
34
+ elsif duration_property && dtstart_property
35
+ (dtstart_property + duration_property).to_finish_time
36
+ else
37
+ nil
38
+ end
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,6 @@
1
+ #- ©2009 Rick DeNatale
2
+ #- All rights reserved. Refer to the file README.txt for the license
3
+ #
4
+ Dir[File.dirname(__FILE__) + "/core_extensions/*.rb"].sort.each do |path|
5
+ require path
6
+ end
@@ -0,0 +1,7 @@
1
+ require "#{File.dirname(__FILE__)}/array/conversions.rb"
2
+ class Array #:nodoc:
3
+ #- ©2009 Rick DeNatale
4
+ #- All rights reserved. Refer to the file README.txt for the license
5
+ #
6
+ include RiCal::CoreExtensions::Array::Conversions
7
+ end
@@ -0,0 +1,15 @@
1
+ module RiCal
2
+ module CoreExtensions #:nodoc:
3
+ module Array #:nodoc:
4
+ #- ©2009 Rick DeNatale
5
+ #- All rights reserved. Refer to the file README.txt for the license
6
+ #
7
+ module Conversions
8
+ # return the concatenation of the elements representation in rfc 2445 format
9
+ def to_rfc2445_string # :doc:
10
+ join(",")
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ require "#{File.dirname(__FILE__)}/date/conversions.rb"
2
+ require "#{File.dirname(__FILE__)}/time/week_day_predicates.rb"
3
+ require "#{File.dirname(__FILE__)}/time/calculations.rb"
4
+ require 'date'
5
+
6
+ class Date #:nodoc:
7
+ #- ©2009 Rick DeNatale
8
+ #- All rights reserved. Refer to the file README.txt for the license
9
+ #
10
+ include RiCal::CoreExtensions::Time::WeekDayPredicates
11
+ include RiCal::CoreExtensions::Time::Calculations
12
+ include RiCal::CoreExtensions::Date::Conversions
13
+ end
@@ -0,0 +1,61 @@
1
+ module RiCal
2
+ module CoreExtensions #:nodoc:
3
+ module Date #:nodoc:
4
+ #- ©2009 Rick DeNatale
5
+ #- All rights reserved. Refer to the file README.txt for the license
6
+ #
7
+ module Conversions #:nodoc:
8
+ # Return an RiCal::PropertyValue::DateTime representing the receiver
9
+ def to_ri_cal_date_time_value(timezone_finder = nil)
10
+ RiCal::PropertyValue::DateTime.new(timezone_finder, :value => self)
11
+ end
12
+
13
+ # Return an RiCal::PropertyValue::Date representing the receiver
14
+ def to_ri_cal_date_value(timezone_finder = nil)
15
+ RiCal::PropertyValue::Date.new(timezone_finder, :value => self)
16
+ end
17
+
18
+ alias_method :to_ri_cal_date_or_date_time_value, :to_ri_cal_date_value
19
+ alias_method :to_ri_cal_occurrence_list_value, :to_ri_cal_date_value
20
+
21
+ # Return the natural ri_cal_property for this object
22
+ def to_ri_cal_property_value(timezone_finder = nil)
23
+ to_ri_cal_date_value(timezone_finder)
24
+ end
25
+
26
+ unless defined? ActiveSupport
27
+ # A method to keep Time, Date and DateTime instances interchangeable on conversions.
28
+ # In this case, it simply returns +self+.
29
+ def to_date
30
+ self
31
+ end if RUBY_VERSION < '1.9'
32
+
33
+ # Converts a Date instance to a Time, where the time is set to the beginning of the day.
34
+ # The timezone can be either :local or :utc (default :local).
35
+ #
36
+ # ==== Examples
37
+ # date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
38
+ #
39
+ # date.to_time # => Sat Nov 10 00:00:00 0800 2007
40
+ # date.to_time(:local) # => Sat Nov 10 00:00:00 0800 2007
41
+ #
42
+ # date.to_time(:utc) # => Sat Nov 10 00:00:00 UTC 2007
43
+ def to_time(form = :local)
44
+ ::Time.send("#{form}_time", year, month, day)
45
+ end
46
+
47
+ # Converts a Date instance to a DateTime, where the time is set to the beginning of the day
48
+ # and UTC offset is set to 0.
49
+ #
50
+ # ==== Examples
51
+ # date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
52
+ #
53
+ # date.to_datetime # => Sat, 10 Nov 2007 00:00:00 0000
54
+ def to_datetime
55
+ ::DateTime.civil(year, month, day, 0, 0, 0, 0)
56
+ end if RUBY_VERSION < '1.9'
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,15 @@
1
+ require "#{File.dirname(__FILE__)}/date_time/conversions.rb"
2
+ require "#{File.dirname(__FILE__)}/time/tzid_access.rb"
3
+ require "#{File.dirname(__FILE__)}/time/week_day_predicates.rb"
4
+ require "#{File.dirname(__FILE__)}/time/calculations.rb"
5
+ require 'date'
6
+
7
+ class DateTime #:nodoc:
8
+ #- ©2009 Rick DeNatale
9
+ #- All rights reserved. Refer to the file README.txt for the license
10
+ #
11
+ include RiCal::CoreExtensions::Time::WeekDayPredicates
12
+ include RiCal::CoreExtensions::Time::Calculations
13
+ include RiCal::CoreExtensions::Time::TzidAccess
14
+ include RiCal::CoreExtensions::DateTime::Conversions
15
+ end
@@ -0,0 +1,50 @@
1
+ require 'date'
2
+ module RiCal
3
+ module CoreExtensions #:nodoc:
4
+ module DateTime #:nodoc:
5
+ #- ©2009 Rick DeNatale
6
+ #- All rights reserved. Refer to the file README.txt for the license
7
+ #
8
+ module Conversions #:nodoc:
9
+ # Return an RiCal::PropertyValue::DateTime representing the receiver
10
+ def to_ri_cal_date_time_value(timezone_finder = nil) #:nodoc:
11
+ RiCal::PropertyValue::DateTime.new(
12
+ timezone_finder,
13
+ :value => strftime("%Y%m%dT%H%M%S"),
14
+ :params => {"TZID" => self.tzid || :default})
15
+ end
16
+
17
+ alias_method :to_ri_cal_date_or_date_time_value, :to_ri_cal_date_time_value #:nodoc:
18
+ alias_method :to_ri_cal_occurrence_list_value, :to_ri_cal_date_time_value #:nodoc:
19
+
20
+ # Return the natural ri_cal_property for this object
21
+ def to_ri_cal_property_value(timezone_finder = nil) #:nodoc:
22
+ to_ri_cal_date_time_value(timezone_finder)
23
+ end
24
+
25
+ # Return a copy of this object which will be interpreted as a floating time.
26
+ def with_floating_timezone
27
+ dup.set_tzid(:floating)
28
+ end
29
+
30
+ unless defined? ActiveSupport
31
+ # Converts self to a Ruby Date object; time portion is discarded
32
+ def to_date
33
+ ::Date.new(year, month, day)
34
+ end
35
+
36
+ # Attempts to convert self to a Ruby Time object; returns self if out of range of Ruby Time class
37
+ # If self has an offset other than 0, self will just be returned unaltered, since there's no clean way to map it to a Time
38
+ def to_time
39
+ self.offset == 0 ? ::Time.utc_time(year, month, day, hour, min, sec) : self
40
+ end
41
+
42
+ # To be able to keep Times, Dates and DateTimes interchangeable on conversions
43
+ def to_datetime
44
+ self
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,8 @@
1
+ require "#{File.dirname(__FILE__)}/object/conversions.rb"
2
+
3
+ class Object #:nodoc:
4
+ #- ©2009 Rick DeNatale
5
+ #- All rights reserved. Refer to the file README.txt for the license
6
+ #
7
+ include RiCal::CoreExtensions::Object::Conversions
8
+ end
@@ -0,0 +1,20 @@
1
+ module RiCal
2
+ module CoreExtensions #:nodoc:
3
+ module Object #:nodoc:
4
+ #- ©2009 Rick DeNatale
5
+ #- All rights reserved. Refer to the file README.txt for the license
6
+ #
7
+ module Conversions #:nodoc:
8
+ # Used to format rfc2445 output for RiCal
9
+ def to_rfc2445_string
10
+ to_s
11
+ end
12
+
13
+ # Used by RiCal specs returns the receiver
14
+ def to_ri_cal_ruby_value
15
+ self
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,8 @@
1
+ require "#{File.dirname(__FILE__)}/string/conversions.rb"
2
+
3
+ class String #:nodoc:
4
+ #- ©2009 Rick DeNatale
5
+ #- All rights reserved. Refer to the file README.txt for the license
6
+ #
7
+ include RiCal::CoreExtensions::String::Conversions
8
+ end
@@ -0,0 +1,63 @@
1
+ module RiCal
2
+ module CoreExtensions #:nodoc:
3
+ module String #:nodoc:
4
+ #- ©2009 Rick DeNatale
5
+ #- All rights reserved. Refer to the file README.txt for the license
6
+ #
7
+ module Conversions #:nodoc:
8
+ # Parse the receiver as an RiCal::PropertyValue::DateTime
9
+ def to_ri_cal_date_time_value(timezone_finder = nil)
10
+ params, value = *Parser.params_and_value(self, :no_leading_semicolon)
11
+ if PropertyValue::DateTime.valid_string?(value)
12
+ PropertyValue::DateTime.new(timezone_finder, :params => params, :value => value)
13
+ else
14
+ raise InvalidPropertyValue.new("#{self.inspect} is not a valid rfc 2445 date-time")
15
+ end
16
+ end
17
+
18
+
19
+ def to_ri_cal_date_or_date_time_value(timezone_finder = nil)
20
+ params, value = *Parser.params_and_value(self, :no_leading_semicolon)
21
+ if PropertyValue::DateTime.valid_string?(value) || PropertyValue::Date.valid_string?(value)
22
+ PropertyValue.date_or_date_time(timezone_finder, :params => params, :value => value)
23
+ else
24
+ raise InvalidPropertyValue.new("#{self.inspect} is not a valid rfc 2445 date or date-time")
25
+ end
26
+ end
27
+
28
+ # Parse the receiver as an RiCal::PropertyValue::DurationValue
29
+ def to_ri_cal_duration_value(timezone_finder = nil)
30
+ params, value = *Parser.params_and_value(self)
31
+ if PropertyValue::Duration.valid_string?(value)
32
+ PropertyValue::Duration.new(timezone_finder, :params => params, :value => value)
33
+ else
34
+ raise InvalidPropertyValue.new("#{self.inspect} is not a valid rfc 2445 duration")
35
+ end
36
+ end
37
+
38
+ def to_ri_cal_occurrence_list_value(timezone_finder = nil)
39
+ params, value = *Parser.params_and_value(self, :no_leading_semicolon)
40
+ if PropertyValue::DateTime.valid_string?(value)
41
+ PropertyValue::DateTime.new(timezone_finder, :params => params, :value => value)
42
+ elsif PropertyValue::Date.valid_string?(value)
43
+ PropertyValue::Date.new(timezone_finder, :params => params, :value => value)
44
+ elsif PropertyValue::Period.valid_string?(value)
45
+ PropertyValue::Period.new(timezone_finder, :params => params, :value => value)
46
+ else
47
+ raise "Invalid value for occurrence list #{self.inspect}"
48
+ end
49
+ end
50
+
51
+ # code stolen from ActiveSupport Gem
52
+ unless ::String.instance_methods.include?("camelize")
53
+ # Convert the receiver to camelized form
54
+ # This method duplicates the method provided by ActiveSupport, and will only be defined
55
+ # by the RiCal gem if it is not already defined.
56
+ def camelize
57
+ self.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,13 @@
1
+ require "#{File.dirname(__FILE__)}/time/conversions.rb"
2
+ require "#{File.dirname(__FILE__)}/time/tzid_access.rb"
3
+ require "#{File.dirname(__FILE__)}/time/week_day_predicates.rb"
4
+ require "#{File.dirname(__FILE__)}/time/calculations.rb"
5
+ #- ©2009 Rick DeNatale
6
+ #- All rights reserved. Refer to the file README.txt for the license
7
+ #
8
+ class Time #:nodoc:
9
+ include RiCal::CoreExtensions::Time::WeekDayPredicates
10
+ include RiCal::CoreExtensions::Time::Calculations
11
+ include RiCal::CoreExtensions::Time::Conversions
12
+ include RiCal::CoreExtensions::Time::TzidAccess
13
+ end
@@ -0,0 +1,153 @@
1
+ module RiCal
2
+ module CoreExtensions #:nodoc:
3
+ module Time #:nodoc:
4
+ #- ©2009 Rick DeNatale
5
+ #- All rights reserved. Refer to the file README.txt for the license
6
+ #
7
+ # Provide calculation methods for use by the RiCal gem
8
+ # This module is included by Time, Date, and DateTime
9
+ module Calculations
10
+ # A predicate method used to determine if the receiver is within a leap year
11
+ def leap_year?
12
+ year % 4 == 0 && (year % 400 == 0 || year % 100 != 0)
13
+ end
14
+
15
+ # Return the number of days in the month which includes the receiver
16
+ def days_in_month
17
+ raw = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][self.month]
18
+ self.month == 2 && leap_year? ? raw + 1 : raw
19
+ end
20
+
21
+ # Return the date on which the first iso week with a given starting week day occurs
22
+ # for a given iso year
23
+ #
24
+ #
25
+ # From RFC 2445 page 43:
26
+ # A week is defined as a seven day period, starting on the day of the week defined to be the
27
+ # week start (see WKST). Week number one of the calendar year is the first week which contains
28
+ # at least four (4) days in that calendar
29
+ # year.
30
+ #
31
+ # == parameters
32
+ # year:: the iso year
33
+ # wkst:: an integer representing the day of the week on which weeks are deemed to start. This uses
34
+ # the ruby convention where 0 represents Sunday.
35
+ def self.iso_week_one(year, wkst)
36
+ #
37
+ # Note that wkst uses the ruby definition, with Sunday = 0
38
+ #
39
+ # A good article about calculating ISO week number is at
40
+ # http://www.boyet.com/Articles/PublishedArticles/CalculatingtheISOweeknumb.html
41
+ #
42
+ # RFC 2445 generalizes the notion of ISO week by allowing the start of the week to vary.
43
+ # In order to adopt the algorithm in the referenced article, we must determine, for each
44
+ # wkst value, the day in January which must be contained in week 1 of the year.
45
+ #
46
+ # For a given wkst week 1 for a year is the first week which
47
+ # 1) Starts with a day with a wday of wkst
48
+ # 2) Contains a majority (4 or more) of days in that year
49
+ #
50
+ # If end of prior Dec, start of Jan Week 1 starts on For WKST =
51
+
52
+ # MO TU WE TH FR SA SU MO TU WE TH FR SA SU MO TU WE TH FR SA SU
53
+ # 01 02 03 04 05 06 07 08 09 10 11 12 13 14 01-07 02-08 03-09 04-10 05-11 06-12 07-13
54
+ # 31 01 02 03 04 05 06 07 08 09 10 11 12 13 31-06 01-07 02-08 03-09 04-10 05-11 06-12
55
+ # 30 31 01 02 03 04 05 06 07 08 09 10 11 12 30-05 31-06 01-07 02-08 03-09 04-10 05-11
56
+ # 29 30 31 01 02 03 04 05 06 07 08 09 10 11 29-04 30-05 31-06 01-07 02-08 03-09 04-10
57
+ # 28 29 30 31 01 02 03 04 05 06 07 08 09 10 04-10 29-04 30-05 31-06 01-07 02-08 03-09
58
+ # 27 28 29 30 31 01 02 03 04 05 06 07 08 09 03-09 04-10 29-04 30-05 31-06 01-07 02-08
59
+ # 26 27 28 29 30 31 01 02 03 04 05 06 07 08 02-08 03-09 04-10 29-04 30-05 31-06 01-07
60
+ # 25 26 27 28 29 30 31 01 02 03 04 05 06 07 01-07 02-08 03-09 04-10 29-04 30-05 31-06
61
+ # Week 1 must contain 4 4 4 4 ? ? ?
62
+ #
63
+ # So for a wkst of FR, SA, or SU, there is no date which MUST be contained in the 1st week
64
+ # We'll have to brute force that
65
+ if (1..4).include?(wkst)
66
+ # return the date of the wkst day which is less than or equal to jan4th
67
+ jan4th = ::Date.new(year, 1, 4)
68
+ result = jan4th - (convert_wday(jan4th.wday) - convert_wday(wkst))
69
+ else
70
+ # return the date of the wkst day which is greater than or equal to Dec 31 of the prior year
71
+ dec29th = ::Date.new(year-1, 12, 29)
72
+ result = dec29th + convert_wday(wkst) - convert_wday(dec29th.wday)
73
+ end
74
+ result
75
+ end
76
+
77
+ # Convert the receivers wday to RFC 2445 format. Whereas the Ruby time/date classes use
78
+ # 0 to represent Sunday, RFC 2445 uses 7.
79
+ def self.convert_wday(wday)
80
+ wday == 0 ? 7 : wday
81
+ end
82
+
83
+ # Return an array containing the iso year and iso week number for the receiver.
84
+ # Note that the iso year may be the year before or after the calendar year containing the receiver.
85
+ # == parameter
86
+ # wkst:: an integer representing the day of the week on which weeks are deemed to start. This uses
87
+ # the ruby convention where 0 represents Sunday.
88
+ def iso_year_and_week_one_start(wkst)
89
+ iso_year = self.year
90
+ date = ::Date.new(self.year, self.month, self.mday)
91
+ if (date >= ::Date.new(iso_year, 12, 29))
92
+ week_one_start = Calculations.iso_week_one(iso_year + 1, wkst)
93
+ if date < week_one_start
94
+ week_one_start = Calculations.iso_week_one(iso_year, wkst)
95
+ else
96
+ iso_year += 1
97
+ end
98
+ else
99
+ week_one_start = Calculations.iso_week_one(iso_year, wkst)
100
+ if (date < week_one_start)
101
+ iso_year -= 1
102
+ week_one_start = Calculations.iso_week_one(iso_year, wkst)
103
+ end
104
+ end
105
+ [iso_year, week_one_start]
106
+ end
107
+
108
+ def iso_year_and_week_num(wkst) #:nodoc:
109
+ iso_year, week_one_start = *iso_year_and_week_one_start(wkst)
110
+ [iso_year, (::Date.new(self.year, self.month, self.mday) - week_one_start).to_i / 7 + 1]
111
+ end
112
+
113
+ # return the number of weeks in the the iso year containing the receiver
114
+ # == parameter
115
+ # wkst:: an integer representing the day of the week on which weeks are deemed to start. This uses
116
+ # the ruby convention where 0 represents Sunday.
117
+ def iso_weeks_in_year(wkst)
118
+ iso_year, week_one_start = *iso_year_and_week_one_start(wkst)
119
+ probe_date = week_one_start + (7*52)
120
+ if probe_date.iso_year(wkst) == iso_year
121
+ 53
122
+ else
123
+ 52
124
+ end
125
+ end
126
+
127
+ # return the iso week number of the receiver
128
+ # == parameter
129
+ # wkst:: an integer representing the day of the week on which weeks are deemed to start. This uses
130
+ # the ruby convention where 0 represents Sunday.
131
+ def iso_week_num(wkst)
132
+ iso_year_and_week_num(wkst)[1]
133
+ end
134
+
135
+ # return the iso year of the receiver
136
+ # == parameter
137
+ # wkst:: an integer representing the day of the week on which weeks are deemed to start. This uses
138
+ # the ruby convention where 0 represents Sunday.
139
+ def iso_year(wkst)
140
+ iso_year_and_week_num(wkst)[0]
141
+ end
142
+
143
+ # return the first day of the iso year of the receiver
144
+ # == parameter
145
+ # wkst:: an integer representing the day of the week on which weeks are deemed to start. This uses
146
+ # the ruby convention where 0 represents Sunday.
147
+ def iso_year_start(wkst)
148
+ iso_year_and_week_one_start(wkst)[1]
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end