rubyredrick-ri_cal 0.0.2
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 +3 -0
- data/Manifest.txt +122 -0
- data/README.txt +271 -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 +2 -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/component/alarm.rb +22 -0
- data/lib/ri_cal/component/calendar.rb +199 -0
- data/lib/ri_cal/component/event.rb +30 -0
- data/lib/ri_cal/component/freebusy.rb +19 -0
- data/lib/ri_cal/component/journal.rb +22 -0
- data/lib/ri_cal/component/t_z_info_timezone.rb +124 -0
- data/lib/ri_cal/component/timezone/daylight_period.rb +26 -0
- data/lib/ri_cal/component/timezone/standard_period.rb +24 -0
- data/lib/ri_cal/component/timezone/timezone_period.rb +54 -0
- data/lib/ri_cal/component/timezone.rb +193 -0
- data/lib/ri_cal/component/todo.rb +26 -0
- data/lib/ri_cal/component.rb +224 -0
- data/lib/ri_cal/core_extensions/array/conversions.rb +15 -0
- data/lib/ri_cal/core_extensions/array.rb +7 -0
- data/lib/ri_cal/core_extensions/date/conversions.rb +27 -0
- data/lib/ri_cal/core_extensions/date.rb +13 -0
- data/lib/ri_cal/core_extensions/date_time/conversions.rb +27 -0
- data/lib/ri_cal/core_extensions/date_time.rb +13 -0
- data/lib/ri_cal/core_extensions/object/conversions.rb +20 -0
- data/lib/ri_cal/core_extensions/object.rb +8 -0
- data/lib/ri_cal/core_extensions/string/conversions.rb +32 -0
- data/lib/ri_cal/core_extensions/string.rb +8 -0
- data/lib/ri_cal/core_extensions/time/calculations.rb +153 -0
- data/lib/ri_cal/core_extensions/time/conversions.rb +27 -0
- data/lib/ri_cal/core_extensions/time/week_day_predicates.rb +88 -0
- data/lib/ri_cal/core_extensions/time.rb +11 -0
- data/lib/ri_cal/core_extensions.rb +6 -0
- data/lib/ri_cal/invalid_timezone_identifer.rb +20 -0
- data/lib/ri_cal/occurrence_enumerator.rb +172 -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/array.rb +19 -0
- data/lib/ri_cal/property_value/cal_address.rb +12 -0
- data/lib/ri_cal/property_value/date.rb +119 -0
- data/lib/ri_cal/property_value/date_time/additive_methods.rb +43 -0
- data/lib/ri_cal/property_value/date_time/time_machine.rb +180 -0
- data/lib/ri_cal/property_value/date_time/timezone_support.rb +65 -0
- data/lib/ri_cal/property_value/date_time.rb +324 -0
- data/lib/ri_cal/property_value/duration.rb +106 -0
- data/lib/ri_cal/property_value/geo.rb +12 -0
- data/lib/ri_cal/property_value/integer.rb +13 -0
- data/lib/ri_cal/property_value/occurrence_list.rb +82 -0
- data/lib/ri_cal/property_value/period.rb +63 -0
- data/lib/ri_cal/property_value/recurrence_rule/enumeration_support_methods.rb +98 -0
- data/lib/ri_cal/property_value/recurrence_rule/enumerator.rb +77 -0
- data/lib/ri_cal/property_value/recurrence_rule/initialization_methods.rb +149 -0
- data/lib/ri_cal/property_value/recurrence_rule/negative_setpos_enumerator.rb +54 -0
- data/lib/ri_cal/property_value/recurrence_rule/numbered_span.rb +32 -0
- data/lib/ri_cal/property_value/recurrence_rule/occurence_incrementer.rb +794 -0
- data/lib/ri_cal/property_value/recurrence_rule/recurring_day.rb +132 -0
- data/lib/ri_cal/property_value/recurrence_rule/recurring_month_day.rb +61 -0
- data/lib/ri_cal/property_value/recurrence_rule/recurring_numbered_week.rb +34 -0
- data/lib/ri_cal/property_value/recurrence_rule/recurring_year_day.rb +50 -0
- data/lib/ri_cal/property_value/recurrence_rule/validations.rb +126 -0
- data/lib/ri_cal/property_value/recurrence_rule.rb +146 -0
- data/lib/ri_cal/property_value/text.rb +41 -0
- data/lib/ri_cal/property_value/uri.rb +12 -0
- data/lib/ri_cal/property_value/utc_offset.rb +34 -0
- data/lib/ri_cal/property_value.rb +110 -0
- data/lib/ri_cal/required_timezones.rb +56 -0
- data/lib/ri_cal/time_with_floating_timezone.rb +59 -0
- data/lib/ri_cal.rb +134 -0
- data/ri_cal.gemspec +47 -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 +13 -0
- data/spec/ri_cal/component/calendar_spec.rb +55 -0
- data/spec/ri_cal/component/event_spec.rb +157 -0
- data/spec/ri_cal/component/freebusy_spec.rb +13 -0
- data/spec/ri_cal/component/journal_spec.rb +13 -0
- data/spec/ri_cal/component/t_z_info_timezone_spec.rb +37 -0
- data/spec/ri_cal/component/timezone_spec.rb +155 -0
- data/spec/ri_cal/component/todo_spec.rb +61 -0
- data/spec/ri_cal/component_spec.rb +212 -0
- data/spec/ri_cal/core_extensions/time/calculations_spec.rb +189 -0
- data/spec/ri_cal/core_extensions/time/week_day_predicates_spec.rb +46 -0
- data/spec/ri_cal/occurrence_enumerator_spec.rb +218 -0
- data/spec/ri_cal/parser_spec.rb +304 -0
- data/spec/ri_cal/property_value/date_spec.rb +22 -0
- data/spec/ri_cal/property_value/date_time_spec.rb +448 -0
- data/spec/ri_cal/property_value/duration_spec.rb +80 -0
- data/spec/ri_cal/property_value/period_spec.rb +50 -0
- data/spec/ri_cal/property_value/recurrence_rule/recurring_year_day_spec.rb +22 -0
- data/spec/ri_cal/property_value/recurrence_rule_spec.rb +1815 -0
- data/spec/ri_cal/property_value/text_spec.rb +14 -0
- data/spec/ri_cal/property_value/utc_offset_spec.rb +49 -0
- data/spec/ri_cal/property_value_spec.rb +111 -0
- data/spec/ri_cal/required_timezones_spec.rb +68 -0
- data/spec/ri_cal_spec.rb +54 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +24 -0
- data/tasks/ri_cal.rake +403 -0
- data/tasks/spec.rake +35 -0
- metadata +201 -0
@@ -0,0 +1,110 @@
|
|
1
|
+
module RiCal
|
2
|
+
#- ©2009 Rick DeNatale
|
3
|
+
#- All rights reserved. Refer to the file README.txt for the license
|
4
|
+
#
|
5
|
+
# PropertyValue provides common implementation of various RFC 2445 property value types
|
6
|
+
class PropertyValue
|
7
|
+
|
8
|
+
attr_writer :params, :value #:nodoc:
|
9
|
+
attr_reader :timezone_finder #:nodoc:
|
10
|
+
def initialize(timezone_finder, options={}) # :nodoc:
|
11
|
+
@timezone_finder = timezone_finder
|
12
|
+
validate_value(options)
|
13
|
+
({:params => {}}).merge(options).each do |attribute, val|
|
14
|
+
unless attribute == :name
|
15
|
+
setter = :"#{attribute.to_s}="
|
16
|
+
send(setter, val)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def validate_value(options) #:nodoc:
|
22
|
+
val = options[:value]
|
23
|
+
raise "Invalid property value #{val.inspect}" if val.kind_of?(String) && /^;/.match(val)
|
24
|
+
end
|
25
|
+
|
26
|
+
# return a hash containing the parameters and values, if any
|
27
|
+
def params
|
28
|
+
@params ||= {}
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_options_hash #:nodoc:
|
32
|
+
options_hash = {:value => value}
|
33
|
+
options_hash[:params] = params unless params.empty?
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.date_or_date_time(parent, separated_line) # :nodoc:
|
37
|
+
match = separated_line[:value].match(/(\d\d\d\d)(\d\d)(\d\d)((T?)((\d\d)(\d\d)(\d\d))(Z?))?/)
|
38
|
+
raise Exception.new("Invalid date") unless match
|
39
|
+
if match[5] == "T" # date-time
|
40
|
+
time = Time.utc(match[1].to_i, match[2].to_i, match[3].to_i, match[7].to_i, match[8].to_i, match[9].to_i)
|
41
|
+
parms = (separated_line[:params] ||{}).dup
|
42
|
+
if match[10] == "Z"
|
43
|
+
raise Exception.new("Invalid time, cannot combine Zulu with timezone reference") if parms[:tzid]
|
44
|
+
parms['TZID'] = "UTC"
|
45
|
+
end
|
46
|
+
PropertyValue::DateTime.new(parent, separated_line.merge(:params => parms))
|
47
|
+
else
|
48
|
+
PropertyValue::Date.new(parent, separated_line)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.from_string(string) # :nodoc:
|
53
|
+
new(nil, :value => string)
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.convert(parent, value) #:nodoc:
|
57
|
+
new(parent, :value => value)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Determine if another object is equivalent to the receiver.
|
61
|
+
def ==(o)
|
62
|
+
if o.class == self.class
|
63
|
+
equality_value == o.equality_value
|
64
|
+
else
|
65
|
+
super
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Return the string value
|
70
|
+
def value
|
71
|
+
@value
|
72
|
+
end
|
73
|
+
|
74
|
+
def equality_value #:nodoc:
|
75
|
+
value
|
76
|
+
end
|
77
|
+
|
78
|
+
def visible_params # :nodoc:
|
79
|
+
params
|
80
|
+
end
|
81
|
+
|
82
|
+
def parms_string #:nodoc:
|
83
|
+
if (vp = visible_params) && !vp.empty?
|
84
|
+
# We only sort for testability reasons
|
85
|
+
vp.keys.sort.map {|key| ";#{key}=#{vp[key]}"}.join
|
86
|
+
else
|
87
|
+
""
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Return a string representing the receiver in RFC 2445 format
|
92
|
+
def to_s #:nodoc:
|
93
|
+
"#{parms_string}:#{value}"
|
94
|
+
end
|
95
|
+
|
96
|
+
# return the ruby value
|
97
|
+
def ruby_value
|
98
|
+
self.value
|
99
|
+
end
|
100
|
+
|
101
|
+
def to_ri_cal_property_value #:nodoc:
|
102
|
+
self
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
Dir[File.dirname(__FILE__) + "/property_value/*.rb"].sort.each do |path|
|
108
|
+
filename = File.basename(path)
|
109
|
+
require path
|
110
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module RiCal
|
2
|
+
#- ©2009 Rick DeNatale
|
3
|
+
#- All rights reserved. Refer to the file README.txt for the license
|
4
|
+
#
|
5
|
+
# RequireTimezones collects the timezones used by a given calendar component or set of calendar components
|
6
|
+
# For each timezone we collect it's id, and the earliest and latest times which reference the zone
|
7
|
+
class RequiredTimezones #:nodoc:
|
8
|
+
|
9
|
+
|
10
|
+
# A required timezone represents a single timezone and the earliest and latest times which reference it.
|
11
|
+
class RequiredTimezone #:nodoc:
|
12
|
+
|
13
|
+
attr_reader :first_time, :last_time, :timezone
|
14
|
+
|
15
|
+
def initialize(tzid)
|
16
|
+
@timezone = RiCal::Component::TZInfoTimezone.new(TZInfo::Timezone.get(tzid))
|
17
|
+
end
|
18
|
+
|
19
|
+
def tzid
|
20
|
+
@timezone.identifier
|
21
|
+
end
|
22
|
+
|
23
|
+
def add_datetime(date_time)
|
24
|
+
if @first_time
|
25
|
+
@first_time = date_time if date_time < @first_time
|
26
|
+
else
|
27
|
+
@first_time = date_time
|
28
|
+
end
|
29
|
+
if @last_time
|
30
|
+
@last_time = date_time if date_time > @last_time
|
31
|
+
else
|
32
|
+
@last_time = date_time
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def required_timezones
|
38
|
+
@required_zones ||= {}
|
39
|
+
end
|
40
|
+
|
41
|
+
def required_zones
|
42
|
+
required_timezones.values
|
43
|
+
end
|
44
|
+
|
45
|
+
def export_to(export_stream)
|
46
|
+
required_zones.each do |z|
|
47
|
+
tzinfo_timezone =z.timezone
|
48
|
+
tzinfo_timezone.export_local_to(export_stream, z.first_time, z.last_time)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def add_datetime(date_time, tzid)
|
53
|
+
(required_timezones[tzid] ||= RequiredTimezone.new(tzid)).add_datetime(date_time)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module RiCal
|
2
|
+
#- ©2009 Rick DeNatale
|
3
|
+
#- All rights reserved. Refer to the file README.txt for the license
|
4
|
+
#
|
5
|
+
# FloatingTimezone represents the 'time zone' for a time or date time with no timezone
|
6
|
+
# Times with floating timezones are always interpreted in the timezone of the observer
|
7
|
+
class FloatingTimezone
|
8
|
+
|
9
|
+
def self.identifier #:nodoc:
|
10
|
+
nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.tzinfo_timezone #:nodoc:
|
14
|
+
nil
|
15
|
+
end
|
16
|
+
|
17
|
+
# Return the time unchanged #:nodoc:
|
18
|
+
def self.utc_to_local(time)
|
19
|
+
time.with_floating_timezone.to_ri_cal_date_time_value
|
20
|
+
end
|
21
|
+
|
22
|
+
# Return the time unchanged #:nodoc:
|
23
|
+
def self.local_to_utc(time)
|
24
|
+
time.with_floating_timezone.to_ri_cal_date_time_value
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class TimeWithFloatingTimezone #:nodoc:
|
29
|
+
def initialize(time) #:nodoc:
|
30
|
+
@time = time
|
31
|
+
end
|
32
|
+
|
33
|
+
def acts_like_time? #:nodoc:
|
34
|
+
true
|
35
|
+
end
|
36
|
+
|
37
|
+
def time_zone
|
38
|
+
FloatingTimezone #:nodoc:
|
39
|
+
end
|
40
|
+
|
41
|
+
def strftime(format) #:nodoc:
|
42
|
+
@time.strftime(format)
|
43
|
+
end
|
44
|
+
|
45
|
+
def with_floating_timezone #:nodoc:
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_ri_cal_date_time_value #:nodoc:
|
50
|
+
::RiCal::PropertyValue::DateTime.new(nil, :value => @time, :params => {'TZID' => nil})
|
51
|
+
end
|
52
|
+
|
53
|
+
alias_method :to_ri_cal_date_or_date_time_value, :to_ri_cal_date_time_value #:nodoc:
|
54
|
+
|
55
|
+
def method_missing(selector, *args) #:nodoc:
|
56
|
+
@time.send(selector, *args)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/ri_cal.rb
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
#- ©2009 Rick DeNatale
|
2
|
+
#- All rights reserved. Refer to the file README.txt for the license
|
3
|
+
#
|
4
|
+
# The RiCal module provides the outermost namespace, along with several convenience methods for parsing
|
5
|
+
# and building calendars and calendar components.
|
6
|
+
module RiCal
|
7
|
+
|
8
|
+
my_dir = File.dirname(__FILE__)
|
9
|
+
|
10
|
+
autoload :Component, "#{my_dir}/ri_cal/component.rb"
|
11
|
+
autoload :TimezonePeriod, "#{my_dir}/ri_cal/properties/timezone_period.rb"
|
12
|
+
autoload :OccurrenceEnumerator, "#{my_dir}/ri_cal/occurrence_enumerator.rb"
|
13
|
+
|
14
|
+
# :stopdoc:
|
15
|
+
VERSION = '0.0.3'
|
16
|
+
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
17
|
+
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
18
|
+
|
19
|
+
# Returns the version string for the library.
|
20
|
+
#
|
21
|
+
def self.version
|
22
|
+
VERSION
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns the library path for the module. If any arguments are given,
|
26
|
+
# they will be joined to the end of the libray path using
|
27
|
+
# <tt>File.join</tt>.
|
28
|
+
#
|
29
|
+
def self.libpath( *args )
|
30
|
+
args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns the lpath for the module. If any arguments are given,
|
34
|
+
# they will be joined to the end of the path using
|
35
|
+
# <tt>File.join</tt>.
|
36
|
+
#
|
37
|
+
def self.path( *args )
|
38
|
+
args.empty? ? PATH : ::File.join(PATH, args.flatten)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Utility method used to rquire all files ending in .rb that lie in the
|
42
|
+
# directory below this file that has the same name as the filename passed
|
43
|
+
# in. Optionally, a specific _directory_ name can be passed in such that
|
44
|
+
# the _filename_ does not have to be equivalent to the directory.
|
45
|
+
#
|
46
|
+
def self.require_all_libs_relative_to( fname, dir = nil )
|
47
|
+
dir ||= ::File.basename(fname, '.*')
|
48
|
+
search_me = ::File.expand_path(::File.join(::File.dirname(fname), dir, '**', '*.rb'))
|
49
|
+
Dir.glob(search_me).sort.each {|rb|
|
50
|
+
require rb}
|
51
|
+
end
|
52
|
+
|
53
|
+
# :startdoc:
|
54
|
+
|
55
|
+
# Parse an io stream and return an array of iCalendar entities.
|
56
|
+
# Normally this will be an array of RiCal::Component::Calendar instances
|
57
|
+
def self.parse(io)
|
58
|
+
Parser.new(io).parse
|
59
|
+
end
|
60
|
+
|
61
|
+
# Parse a string and return an array of iCalendar entities.
|
62
|
+
# see RiCal.parse
|
63
|
+
def self.parse_string(string)
|
64
|
+
parse(StringIO.new(string))
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.debug # :nodoc:
|
68
|
+
@debug
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.debug=(val) # :nodoc:
|
72
|
+
@debug = val
|
73
|
+
end
|
74
|
+
|
75
|
+
# return a new Alarm event or todo component. If a block is provided it will will be executed in
|
76
|
+
# the context of a builder object which can be used to initialize the properties of the
|
77
|
+
# new Alarm.
|
78
|
+
def self.Alarm(&init_block)
|
79
|
+
Component::Alarm.new(&init_block)
|
80
|
+
end
|
81
|
+
|
82
|
+
# return a new Calendar. If a block is provided it will will be executed in
|
83
|
+
# the context of a builder object which can be used to initialize the properties and components of the
|
84
|
+
# new calendar.
|
85
|
+
def self.Calendar(&init_block)
|
86
|
+
Component::Calendar.new(&init_block)
|
87
|
+
end
|
88
|
+
|
89
|
+
# return a new Event calendar component. If a block is provided it will will be executed in
|
90
|
+
# the context of a builder object which can be used to initialize the properties and alarms of the
|
91
|
+
# new Event.
|
92
|
+
def self.Event(&init_block)
|
93
|
+
Component::Event.new(&init_block)
|
94
|
+
end
|
95
|
+
|
96
|
+
# return a new Freebusy calendar component. If a block is provided it will will be executed in
|
97
|
+
# the context of a builder object which can be used to initialize the properties and components of the
|
98
|
+
# new Freebusy.
|
99
|
+
def self.Freebusy(&init_block)
|
100
|
+
Component::Freebusy.new(&init_block)
|
101
|
+
end
|
102
|
+
|
103
|
+
# return a new Journal calendar component. If a block is provided it will will be executed in
|
104
|
+
# the context of a builder object which can be used to initialize the properties and components of the
|
105
|
+
# new Event.
|
106
|
+
def self.Journal(&init_block)
|
107
|
+
Component::Journal.new(&init_block)
|
108
|
+
end
|
109
|
+
|
110
|
+
# return a new Timezone calendar component. If a block is provided it will will be executed in
|
111
|
+
# the context of a builder object which can be used to initialize the properties and timezone periods of the
|
112
|
+
# new Timezone.
|
113
|
+
def self.Timezone(&init_block)
|
114
|
+
Component::Timezone.new(&init_block)
|
115
|
+
end
|
116
|
+
|
117
|
+
# return a new TimezonePeriod timezone component. If a block is provided it will will be executed in
|
118
|
+
# the context of a builder object which can be used to initialize the properties of the
|
119
|
+
# new TimezonePeriod.
|
120
|
+
def self.TimezonePeriod(&init_block)
|
121
|
+
Component::TimezonePeriod.new(&init_block)
|
122
|
+
end
|
123
|
+
|
124
|
+
# return a new Todo calendar component. If a block is provided it will will be executed in
|
125
|
+
# the context of a builder object which can be used to initialize the properties and alarms of the
|
126
|
+
# new Todo.
|
127
|
+
def self.Todo(&init_block)
|
128
|
+
Component::Todo.new(&init_block)
|
129
|
+
end
|
130
|
+
end # module RiCal
|
131
|
+
|
132
|
+
RiCal.require_all_libs_relative_to(__FILE__)
|
133
|
+
|
134
|
+
# EOF
|
data/ri_cal.gemspec
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{ri_cal}
|
5
|
+
s.version = "0.0.2"
|
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-06}
|
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
|
+
s.email = ["rick.denatale@gmail.com"]
|
21
|
+
s.executables = ["ri_cal"]
|
22
|
+
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"]
|
23
|
+
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/week_day_predicates.rb", "lib/ri_cal/invalid_timezone_identifer.rb", "lib/ri_cal/occurrence_enumerator.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", "lib/ri_cal/time_with_floating_timezone.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/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/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/ri_cal.rake", "tasks/spec.rake"]
|
24
|
+
s.has_rdoc = true
|
25
|
+
s.homepage = %q{http://rical.rubyforge.org/}
|
26
|
+
s.rdoc_options = ["--main", "README.txt"]
|
27
|
+
s.require_paths = ["lib"]
|
28
|
+
s.rubyforge_project = %q{rical}
|
29
|
+
s.rubygems_version = %q{1.3.2}
|
30
|
+
s.summary = %q{This is an UNOFFICIAL version}
|
31
|
+
|
32
|
+
if s.respond_to? :specification_version then
|
33
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
34
|
+
s.specification_version = 3
|
35
|
+
|
36
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
37
|
+
s.add_development_dependency(%q<newgem>, [">= 1.3.0"])
|
38
|
+
s.add_development_dependency(%q<hoe>, [">= 1.8.0"])
|
39
|
+
else
|
40
|
+
s.add_dependency(%q<newgem>, [">= 1.3.0"])
|
41
|
+
s.add_dependency(%q<hoe>, [">= 1.8.0"])
|
42
|
+
end
|
43
|
+
else
|
44
|
+
s.add_dependency(%q<newgem>, [">= 1.3.0"])
|
45
|
+
s.add_dependency(%q<hoe>, [">= 1.8.0"])
|
46
|
+
end
|
47
|
+
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,13 @@
|
|
1
|
+
#- ©2009 Rick DeNatale
|
2
|
+
#- All rights reserved
|
3
|
+
|
4
|
+
require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
|
5
|
+
|
6
|
+
describe RiCal::Component::Alarm do
|
7
|
+
|
8
|
+
describe ".entity_name" do
|
9
|
+
it "should be VALARM" do
|
10
|
+
RiCal::Component::Alarm.entity_name.should == "VALARM"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
#- ©2009 Rick DeNatale
|
2
|
+
#- All rights reserved
|
3
|
+
|
4
|
+
require File.join(File.dirname(__FILE__), %w[.. .. spec_helper])
|
5
|
+
|
6
|
+
describe RiCal::Component::Calendar do
|
7
|
+
|
8
|
+
context ".entity_name" do
|
9
|
+
it "should be VCALENDAR" do
|
10
|
+
RiCal::Component::Calendar.entity_name.should == "VCALENDAR"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context "a new instance" do
|
15
|
+
before(:each) do
|
16
|
+
@it = RiCal.Calendar
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should have a tz_source of 'TZ_INFO" do
|
20
|
+
@it.tz_source.should == "TZINFO"
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should export a product id with an X-RICAL-TZSOURCE parameter of TZINFO" do
|
24
|
+
@it.export.should match(%r{\nPRODID;X-RICAL-TZSOURCE=TZINFO:-//com.denhaven2/NONSGML ri_cal gem//EN\n})
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "an imported instance with a tzinfo source" do
|
29
|
+
before(:each) do
|
30
|
+
@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
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should have a tz_source of 'TZ_INFO" do
|
34
|
+
@it.tz_source.should == "TZINFO"
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should export a product id with an X-RICAL-TZSOURCE parameter of TZINFO" do
|
38
|
+
@it.export.should match(%r{\nPRODID;X-RICAL-TZSOURCE=TZINFO:-//com.denhaven2/NONSGML ri_cal gem//EN\n})
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "an imported instance without a tzinfo source" do
|
43
|
+
before(:each) do
|
44
|
+
@it = RiCal.parse_string("BEGIN:VCALENDAR\nPRODID:-//Apple Inc.//iCal 3.0//EN\nEND:VCALENDAR\n").first
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should have a tz_source of nil" do
|
48
|
+
@it.tz_source.should be_nil
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should export not export a product id with an X-RICAL-TZSOURCE parameter of TZINFO" do
|
52
|
+
@it.export.should_not match(%r{X-RICAL-TZSOURCE=TZINFO:})
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|