jruby-rfc2445 0.0.4
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/MIT-LICENSE +22 -0
- data/README +14 -0
- data/lib/ical_parse_util.rb +51 -0
- data/lib/jtime.rb +201 -0
- data/lib/rdate_list.rb +95 -0
- data/lib/recurrence_time.rb +58 -0
- data/lib/rfc2445.jar +0 -0
- data/lib/rfc2445.rb +9 -0
- data/lib/rrule.rb +244 -0
- data/lib/weekday.rb +23 -0
- data/lib/weekday_num.rb +36 -0
- data/spec/rfc2445_spec.rb +501 -0
- metadata +66 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2009 Jerry Luk <jerryluk@gmail.com>
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
jruby-rfc2445
|
2
|
+
=============
|
3
|
+
A JRuby implementation of RFC 2445 (ical) recurrence rules.
|
4
|
+
|
5
|
+
This library makes use of the google-rfc-2445 library (http://code.google.com/p/google-rfc-2445/)
|
6
|
+
To see the usage, please see the RSpec test cases.
|
7
|
+
|
8
|
+
The JTime class uses Joda-time as its underlying implementation. To find out more about Joda time, visit:
|
9
|
+
http://joda-time.sourceforge.net/
|
10
|
+
|
11
|
+
Getting Started
|
12
|
+
===============
|
13
|
+
1. Make sure you can install RubyGem from GitHub (you only have to do this once): jruby -S gem sources -a http://gems.github.com
|
14
|
+
2. Install JRuby RFC 2445 library: jruby -S gem install jerryluk-jruby-rfc2445
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'java'
|
2
|
+
require File.dirname(__FILE__) + '/rfc2445.jar'
|
3
|
+
|
4
|
+
class ICalParseUtil
|
5
|
+
include_class('com.google.ical.values.IcalParseUtil'){|package,name| "J#{name}" }
|
6
|
+
|
7
|
+
# Class Methods
|
8
|
+
class << self
|
9
|
+
def parse_date_value(s, tzid = 'UTC')
|
10
|
+
timezone = java.util.TimeZone.getTimeZone(tzid || 'UTC')
|
11
|
+
s ? JIcalParseUtil.parseDateValue(s, timezone) : nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse_jtime(s, tzid = 'UTC')
|
15
|
+
s ? JTime.from_date_time_value(parse_date_value(s, tzid || 'UTC')) : nil
|
16
|
+
end
|
17
|
+
|
18
|
+
# Parse a recurrence block and returns DTSTART, DTEND, RRULE, EXRULE, RDATE, and EXDATE
|
19
|
+
def parse_recurrence(s)
|
20
|
+
result = {}
|
21
|
+
|
22
|
+
# Strip out all the begin..end blocks
|
23
|
+
s = s.gsub(/BEGIN.*END[^\s]+/m, '')
|
24
|
+
|
25
|
+
s =~ /(DTSTART[^\s]+)/
|
26
|
+
result[:dtstart] = $1 if $1
|
27
|
+
|
28
|
+
s =~ /(DTEND[^\s]+)/
|
29
|
+
result[:dtend] = $1 if $1
|
30
|
+
|
31
|
+
s =~ /(RRULE[^\s]+)/
|
32
|
+
result[:rrule] = $1 if $1
|
33
|
+
|
34
|
+
s =~ /(EXRULE[^\s]+)/
|
35
|
+
result[:exrule] = $1 if $1
|
36
|
+
|
37
|
+
s =~ /(RDATE[^\s]+)/
|
38
|
+
result[:rdate] = $1 if $1
|
39
|
+
|
40
|
+
s =~ /(EXDATE[^\s]+)/
|
41
|
+
result[:exdate] = $1 if $1
|
42
|
+
|
43
|
+
result
|
44
|
+
end
|
45
|
+
|
46
|
+
def parse_datetime(s)
|
47
|
+
s =~ /(;TZID=([^\s]+))?:([^\s]+)/
|
48
|
+
parse_jtime($3, $2)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/jtime.rb
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
require 'java'
|
2
|
+
require File.dirname(__FILE__) + '/rfc2445.jar'
|
3
|
+
|
4
|
+
class JTime
|
5
|
+
include Comparable
|
6
|
+
include_class('org.joda.time.DateTime'){|package,name| "J#{name}" }
|
7
|
+
|
8
|
+
# Class Methods
|
9
|
+
class << self
|
10
|
+
# Creates a new time object with the given number of seconds (and optional
|
11
|
+
# microseconds) from epoch.
|
12
|
+
#
|
13
|
+
# ==== Options
|
14
|
+
# +seconds+:: given number of seconds from epoch
|
15
|
+
# +microseconds+:: Optional. microseconds from epoch
|
16
|
+
#
|
17
|
+
def at(seconds, microseconds=0)
|
18
|
+
datetime = JDateTime.new(seconds * 1000 + microseconds)
|
19
|
+
new(datetime)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Creates a time based on given values, interpreted as UTC (GMT).
|
23
|
+
# The year must be specified. Other values default to the minimum
|
24
|
+
# value for that field.
|
25
|
+
#
|
26
|
+
# ==== Options
|
27
|
+
# +year+:: Year
|
28
|
+
# +month+:: Optional. Numbers from 1 to 12, or by the three-letter
|
29
|
+
# English month names
|
30
|
+
# +hour+:: Optional.24-hour clock (0..23)
|
31
|
+
# +min+:: Optional. 0..59
|
32
|
+
# +sec+:: Optional. seconds of the time
|
33
|
+
# +usec+:: Optional. microsecond of the time
|
34
|
+
def utc(year, month=1, day=1, hour=0, min=0, sec=0, usec=0)
|
35
|
+
datetime = JDateTime.new(year, numeric_month(month), day, hour, min, sec, usec,
|
36
|
+
org.joda.time.DateTimeZone::UTC)
|
37
|
+
new(datetime)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Same as JTime.utc, but interprets the values in local time zone
|
41
|
+
def local(year, month=1, day=1, hour=0, min=0, sec=0, usec=0)
|
42
|
+
datetime = JDateTime.new(year, numeric_month(month), day, hour, min, sec, usec)
|
43
|
+
new(datetime)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Initialize a JTime object from DateTimeValue
|
47
|
+
def from_date_time_value(dtv)
|
48
|
+
utc(dtv.year, dtv.month, dtv.day, dtv.hour, dtv.minute, dtv.second)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Initialize a JTime object from Ruby Time object
|
52
|
+
def from_time(time)
|
53
|
+
datetime = JDateTime.new((time.to_f * 1000).to_i)
|
54
|
+
new(datetime)
|
55
|
+
end
|
56
|
+
|
57
|
+
alias :now :new
|
58
|
+
alias :gm :utc
|
59
|
+
alias :mktime :local
|
60
|
+
|
61
|
+
protected
|
62
|
+
MONTH_NAME_HASH = {
|
63
|
+
'jan' => 1,
|
64
|
+
'feb' => 2,
|
65
|
+
'mar' => 3,
|
66
|
+
'apr' => 4,
|
67
|
+
'may' => 5,
|
68
|
+
'jun' => 6,
|
69
|
+
'jul' => 7,
|
70
|
+
'aug' => 8,
|
71
|
+
'sep' => 9,
|
72
|
+
'oct' => 10,
|
73
|
+
'nov' => 11,
|
74
|
+
'dec' => 12
|
75
|
+
}
|
76
|
+
|
77
|
+
def numeric_month(mon)
|
78
|
+
return mon if mon.kind_of? Fixnum
|
79
|
+
MONTH_NAME_HASH[mon.downcase]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Instance Methods
|
84
|
+
|
85
|
+
# Returns a JTime object. If a Java DateTime object is passed, it is initialized
|
86
|
+
# from the Java JDateTime object, otherwise it is initialized to the current
|
87
|
+
# system time
|
88
|
+
#
|
89
|
+
# ==== Options
|
90
|
+
# +datetime+:: Optional. The Java DateTime (org.joda.time.DateTime')object
|
91
|
+
#
|
92
|
+
def initialize(datetime = JDateTime.new)
|
93
|
+
@time = datetime
|
94
|
+
self
|
95
|
+
end
|
96
|
+
|
97
|
+
# Returns a Ruby Time object
|
98
|
+
def to_time
|
99
|
+
millis = @time.getMillis
|
100
|
+
Time.at(millis / 1000, millis % 1000 * 1000)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Returns the underlying Java DateTime object
|
104
|
+
def to_java
|
105
|
+
@time
|
106
|
+
end
|
107
|
+
|
108
|
+
# Returns the value of time as an integer number of seconds since epoch
|
109
|
+
def to_i
|
110
|
+
@time.getMillis / 1000
|
111
|
+
end
|
112
|
+
|
113
|
+
# Returns the value of time as a floating point number of seconds since epoch
|
114
|
+
def to_f
|
115
|
+
@time.getMillis / 1000.0
|
116
|
+
end
|
117
|
+
|
118
|
+
# Returns a string representing JTime
|
119
|
+
def to_s
|
120
|
+
@time.toString
|
121
|
+
end
|
122
|
+
|
123
|
+
# Returns a new JTime object in UTC time. The receiver is unchanged
|
124
|
+
# IMPORTANT: The original utc in Ruby modified the receiver object
|
125
|
+
def utc
|
126
|
+
datetime = @time.toDateTime(org.joda.time.DateTimeZone::UTC)
|
127
|
+
self.class.new(datetime)
|
128
|
+
end
|
129
|
+
|
130
|
+
def <=>(another_time)
|
131
|
+
@time.compareTo(another_time.to_java)
|
132
|
+
end
|
133
|
+
|
134
|
+
def year
|
135
|
+
@time.getYear
|
136
|
+
end
|
137
|
+
|
138
|
+
def month
|
139
|
+
@time.getMonthOfYear
|
140
|
+
end
|
141
|
+
|
142
|
+
def day
|
143
|
+
@time.getDayOfMonth
|
144
|
+
end
|
145
|
+
|
146
|
+
def hour
|
147
|
+
@time.getHourOfDay
|
148
|
+
end
|
149
|
+
|
150
|
+
def min
|
151
|
+
@time.getMinuteOfHour
|
152
|
+
end
|
153
|
+
|
154
|
+
def sec
|
155
|
+
@time.getSecondOfMinute
|
156
|
+
end
|
157
|
+
|
158
|
+
def wday
|
159
|
+
@time.getDayOfWeek
|
160
|
+
end
|
161
|
+
|
162
|
+
def yday
|
163
|
+
@time.getDayOfYear
|
164
|
+
end
|
165
|
+
|
166
|
+
def week
|
167
|
+
@time.getWeekOfWeekyear
|
168
|
+
end
|
169
|
+
|
170
|
+
# Returns the name of the timezone used for time.
|
171
|
+
# IMPORTANT: Unlike Ruby Time, which returns "PST"
|
172
|
+
# it actuallys return real timezone ID such as 'America/Los_Angeles'
|
173
|
+
def zone
|
174
|
+
@time.getZone.getID
|
175
|
+
end
|
176
|
+
|
177
|
+
# Returns DateTimeValue object
|
178
|
+
def to_date_time_value
|
179
|
+
com.google.ical.values.DateTimeValueImpl.new(self.year, self.month, self.day, self.hour, self.min, self.sec)
|
180
|
+
end
|
181
|
+
|
182
|
+
# Returns the Java Timezone object
|
183
|
+
def java_zone
|
184
|
+
@time.getZone
|
185
|
+
end
|
186
|
+
|
187
|
+
# Returns true if time occurs during Daylight Saveing Time in its timeezone
|
188
|
+
def isdst
|
189
|
+
timezone = @time.getZone.toTimeZone
|
190
|
+
timezone.inDaylightTime(@time.toDate)
|
191
|
+
end
|
192
|
+
|
193
|
+
# We should consider getting rid of this or implement this using meta-programming
|
194
|
+
def method_missing(key, *params)
|
195
|
+
@time.send(key, *params)
|
196
|
+
end
|
197
|
+
|
198
|
+
alias :mon :month
|
199
|
+
alias :dst? :isdst
|
200
|
+
|
201
|
+
end
|
data/lib/rdate_list.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'java'
|
2
|
+
require File.dirname(__FILE__) + '/rfc2445.jar'
|
3
|
+
|
4
|
+
class RDateList
|
5
|
+
include_class('com.google.ical.values.RDateList') { |package,name| "J#{name}" }
|
6
|
+
include_class('java.util.TimeZone') { |package,name| "J#{name}" }
|
7
|
+
|
8
|
+
RDATE = 'RDATE'
|
9
|
+
EXDATE = 'EXDATE'
|
10
|
+
VEVENT = 'VEVENT'
|
11
|
+
|
12
|
+
# Initializes a RDateList with optionally a time zone ID and an iCal string
|
13
|
+
#
|
14
|
+
# ==== Options
|
15
|
+
# +timezone+:: Optional. Time zone ID. For instance, the time zone ID for the
|
16
|
+
# U.S. Pacific Time zone is "America/Los_Angeles"
|
17
|
+
# If no timezone is specify, it uses time zone where the program
|
18
|
+
# is run
|
19
|
+
# +ical_string+:: Optional. The iCal string for the recurrent rule.
|
20
|
+
# The string must specify the rule type (RRULE, EXRULE or VEVENT)
|
21
|
+
#
|
22
|
+
def initialize(timezone=nil, ical_string=nil)
|
23
|
+
tz = timezone ? JTimeZone.getTimeZone(timezone) : JTimeZone.getDefault
|
24
|
+
@rdatelist = ical_string ?
|
25
|
+
JRDateList.new(ical_string, tz) :
|
26
|
+
JRDateList.new(tz)
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns the underlying Java object
|
31
|
+
def to_java
|
32
|
+
@rdatelist
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns the unfolded RFC 2445 content line.
|
36
|
+
def to_ical
|
37
|
+
@rdatelist.toIcal
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns a hash map of any extension parameters such as
|
41
|
+
# the X-FOO=BAR in RRULE;X-FOO=BAR
|
42
|
+
def ext_params
|
43
|
+
h = {}
|
44
|
+
@rdatelist.getExtParams.to_a.each do |p|
|
45
|
+
h[p[0]] = p[1]
|
46
|
+
end
|
47
|
+
h
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns the type of the object name such as
|
51
|
+
# RRULE, EXRULE, or VEVENT
|
52
|
+
def name
|
53
|
+
@rdatelist.getName
|
54
|
+
end
|
55
|
+
|
56
|
+
# Sets the type of the object such as
|
57
|
+
# RRULE, EXRULE, or VEVENT
|
58
|
+
#
|
59
|
+
# ==== Options
|
60
|
+
# +new_name+:: 'RRULE', 'EXRULE', or 'VEVENT'
|
61
|
+
def name=(new_name)
|
62
|
+
@rdatelist.setName(new_name)
|
63
|
+
self
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns the timezone ID. For instance, the time zone ID for the
|
67
|
+
# U.S. Pacific Time zone is "America/Los_Angeles"
|
68
|
+
def zone
|
69
|
+
@rdatelist.getTzid.getID
|
70
|
+
end
|
71
|
+
|
72
|
+
# Sets the timezone using Time zone ID
|
73
|
+
def zone=(timezone)
|
74
|
+
@rdatelist.setTzid(JTimeZone.getTimeZone(timezone))
|
75
|
+
self
|
76
|
+
end
|
77
|
+
|
78
|
+
# Returns the JTime in UTC time zone
|
79
|
+
def utc_dates
|
80
|
+
dates = @rdatelist.getDatesUtc
|
81
|
+
dates.map do |d|
|
82
|
+
JTime.utc(d.year, d.month, d.day)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Sets the dates. It will convert the dates into UTC.
|
87
|
+
def utc_dates=(dates)
|
88
|
+
dates = dates.map do |d|
|
89
|
+
utc_d = d.utc
|
90
|
+
com.google.ical.values.DateValueImpl.new(utc_d.year, utc_d.month, utc_d.day)
|
91
|
+
end
|
92
|
+
@rdatelist.setDatesUtc(dates.to_java('com.google.ical.values.DateValue'))
|
93
|
+
self
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'java'
|
2
|
+
require File.dirname(__FILE__) + '/rfc2445.jar'
|
3
|
+
|
4
|
+
class RecurrenceTime
|
5
|
+
include Enumerable
|
6
|
+
include_class('com.google.ical.compat.jodatime.DateTimeIteratorFactory')
|
7
|
+
|
8
|
+
# Initializes a RecurrenceTime objects which generates JTime based on
|
9
|
+
# recurrence rule
|
10
|
+
#
|
11
|
+
# ==== Options
|
12
|
+
# +rdata+:: it can be one of the following:
|
13
|
+
# 1. RRULE, EXRULE, RDATE, and EXDATE lines (RFC 2445 content strings)
|
14
|
+
# 2. RRule or RDateList object
|
15
|
+
# 3. Array of RRule and RDateList objects, which can be a combinations of
|
16
|
+
# RRULE and EXRULE
|
17
|
+
# +start_time+:: Optional. Start time of the recurrence time. The default is now
|
18
|
+
# +strict+:: Optional. Any failure to parse should result in a ParseException
|
19
|
+
# false causes bad content lines to be logged and ignored. Default is true
|
20
|
+
#
|
21
|
+
def initialize(rdata, start_time=JTime.new, strict=true)
|
22
|
+
rdata = rdata.to_ical if (rdata.kind_of? RRule or
|
23
|
+
rdata.kind_of? RDateList)
|
24
|
+
rdata = (rdata.map {|r| r.to_ical}).join("\n") if rdata.kind_of? Array
|
25
|
+
@iterator = DateTimeIteratorFactory.createDateTimeIterator(rdata,
|
26
|
+
start_time.to_java,
|
27
|
+
start_time.java_zone,
|
28
|
+
strict)
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns a JTime for the instance of next recurrence time
|
33
|
+
def next
|
34
|
+
@iterator.hasNext ? JTime.new(@iterator.next) : nil
|
35
|
+
end
|
36
|
+
|
37
|
+
# Skips all dates in the series before the given date.
|
38
|
+
#
|
39
|
+
# ==== Options
|
40
|
+
# +new_start_time+:: JTime which the iterator is advanced to.
|
41
|
+
#
|
42
|
+
def advance_to(new_start_time)
|
43
|
+
@iterator.advanceTo(new_start_time.to_java)
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
def has_next?
|
48
|
+
@iterator.hasNext
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_java
|
52
|
+
@iterator
|
53
|
+
end
|
54
|
+
|
55
|
+
def each
|
56
|
+
yield self.next until self.has_next? == false
|
57
|
+
end
|
58
|
+
end
|
data/lib/rfc2445.jar
ADDED
Binary file
|
data/lib/rfc2445.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'java'
|
2
|
+
require File.dirname(__FILE__) + '/jtime.rb'
|
3
|
+
require File.dirname(__FILE__) + '/weekday.rb'
|
4
|
+
require File.dirname(__FILE__) + '/weekday_num.rb'
|
5
|
+
require File.dirname(__FILE__) + '/rrule.rb'
|
6
|
+
require File.dirname(__FILE__) + '/rdate_list.rb'
|
7
|
+
require File.dirname(__FILE__) + '/recurrence_time.rb'
|
8
|
+
require File.dirname(__FILE__) + '/ical_parse_util.rb'
|
9
|
+
include_class "com.google.ical.values.Frequency"
|
data/lib/rrule.rb
ADDED
@@ -0,0 +1,244 @@
|
|
1
|
+
require 'java'
|
2
|
+
require File.dirname(__FILE__) + '/rfc2445.jar'
|
3
|
+
|
4
|
+
class RRule
|
5
|
+
include_class('com.google.ical.values.RRule'){|package,name| "J#{name}" }
|
6
|
+
|
7
|
+
RRULE = 'RRULE'
|
8
|
+
EXRULE = 'EXRULE'
|
9
|
+
VEVENT = 'VEVENT'
|
10
|
+
|
11
|
+
# Initializes a Recurrence Rule with optionally an iCal string
|
12
|
+
#
|
13
|
+
# ==== Options
|
14
|
+
# +ical_string+:: Optional. The iCal string for the recurrent rule.
|
15
|
+
# The string must specify the rule type (RRULE, EXRULE or VEVENT)
|
16
|
+
#
|
17
|
+
def initialize(ical_string=nil)
|
18
|
+
@rrule = ical_string ? JRRule.new(ical_string) : JRRule.new
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns the underlying Java object
|
23
|
+
def to_java
|
24
|
+
@rrule
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the unfolded RFC 2445 content line.
|
28
|
+
def to_ical
|
29
|
+
@rrule.toIcal
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns a hash map of any extension parameters such as
|
33
|
+
# the X-FOO=BAR in RRULE;X-FOO=BAR
|
34
|
+
def ext_params
|
35
|
+
h = {}
|
36
|
+
@rrule.getExtParams.to_a.each do |p|
|
37
|
+
h[p[0]] = p[1]
|
38
|
+
end
|
39
|
+
h
|
40
|
+
end
|
41
|
+
|
42
|
+
def count
|
43
|
+
@rrule.getCount
|
44
|
+
end
|
45
|
+
|
46
|
+
# ==== Options
|
47
|
+
# +new_count+:: number of count
|
48
|
+
def count=(new_count)
|
49
|
+
@rrule.setCount(new_count)
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
def hours
|
54
|
+
@rrule.getByHour.to_a
|
55
|
+
end
|
56
|
+
|
57
|
+
# ==== Options
|
58
|
+
# +new_hours+:: array of numbers (0..23)
|
59
|
+
def hours=(new_hours=[])
|
60
|
+
@rrule.setByHour(new_hours.to_java(:int))
|
61
|
+
self
|
62
|
+
end
|
63
|
+
|
64
|
+
def minutes
|
65
|
+
@rrule.getByMinute.to_a
|
66
|
+
end
|
67
|
+
|
68
|
+
# ==== Options
|
69
|
+
# +new_minutes+:: array of numbers (0..59)
|
70
|
+
def minutes=(new_minutes=[])
|
71
|
+
@rrule.setByMinute(new_minutes.to_java(:int))
|
72
|
+
self
|
73
|
+
end
|
74
|
+
|
75
|
+
def months
|
76
|
+
@rrule.getByMonth.to_a
|
77
|
+
end
|
78
|
+
|
79
|
+
# ==== Options
|
80
|
+
# +new_months+:: array of numbers (1..12)
|
81
|
+
def months=(new_months=[])
|
82
|
+
@rrule.setByMonth(new_months.to_java(:int))
|
83
|
+
self
|
84
|
+
end
|
85
|
+
|
86
|
+
# Gets the days of month
|
87
|
+
def mdays
|
88
|
+
@rrule.getByMonthDay.to_a
|
89
|
+
end
|
90
|
+
|
91
|
+
# Sets the days of month
|
92
|
+
#
|
93
|
+
# ==== Options
|
94
|
+
# +new_mdays+:: array of days of month (1..31)
|
95
|
+
def mdays=(new_mdays=[])
|
96
|
+
@rrule.setByMonthDay(new_mdays.to_java(:int))
|
97
|
+
self
|
98
|
+
end
|
99
|
+
|
100
|
+
def seconds
|
101
|
+
@rrule.getBySecond.to_a
|
102
|
+
end
|
103
|
+
|
104
|
+
# ==== Options
|
105
|
+
# +new_seconds+:: array of days of month (0..59)
|
106
|
+
def seconds=(new_seconds=[])
|
107
|
+
@rrule.setBySecond(new_seconds.to_java(:int))
|
108
|
+
self
|
109
|
+
end
|
110
|
+
|
111
|
+
def setpos
|
112
|
+
@rrule.getBySetPos.to_a
|
113
|
+
end
|
114
|
+
|
115
|
+
def setpos=(new_setpos=[])
|
116
|
+
@rrule.setByPos(new_setpos.to_java(:int))
|
117
|
+
self
|
118
|
+
end
|
119
|
+
|
120
|
+
def weeknums
|
121
|
+
@rrule.getByWeekNo.to_a
|
122
|
+
end
|
123
|
+
|
124
|
+
# Sets the numbers of week
|
125
|
+
#
|
126
|
+
# ==== Options
|
127
|
+
# +new_weeknums+:: array of weeks (1..52)
|
128
|
+
def weeknums=(new_weeknums=[])
|
129
|
+
@rrule.setByWeekNo(new_weeknums.to_java(:int))
|
130
|
+
self
|
131
|
+
end
|
132
|
+
|
133
|
+
# Gets the day of year
|
134
|
+
def ydays
|
135
|
+
@rrule.getByYearDay.to_a
|
136
|
+
end
|
137
|
+
|
138
|
+
# Sets the day of year
|
139
|
+
#
|
140
|
+
# ==== Options
|
141
|
+
# +new_ydays+:: array of day of year (1..365)
|
142
|
+
def ydays=(new_ydays=[])
|
143
|
+
@rrule.setByYearDay(new_ydays.to_java(:int))
|
144
|
+
self
|
145
|
+
end
|
146
|
+
|
147
|
+
# Gets the recurrence frequency, return type is defined in
|
148
|
+
# "com.google.ical.values.Frequency", such as Frequency::MONTHLY
|
149
|
+
def frequency
|
150
|
+
@rrule.getFreq
|
151
|
+
end
|
152
|
+
|
153
|
+
# Sets the recurrence frequency
|
154
|
+
#
|
155
|
+
# ==== Options
|
156
|
+
# +freq+:: defined in com.google.ical.values.Frequency, such as
|
157
|
+
# Frequency::MONTHLY or Frequency::DAILY
|
158
|
+
def frequency=(freq)
|
159
|
+
@rrule.setFreq(freq)
|
160
|
+
self
|
161
|
+
end
|
162
|
+
|
163
|
+
def interval
|
164
|
+
@rrule.getInterval
|
165
|
+
end
|
166
|
+
|
167
|
+
def interval=(new_interval)
|
168
|
+
@rrule.setInterval(new_interval)
|
169
|
+
self
|
170
|
+
end
|
171
|
+
|
172
|
+
# Returns the type of the recurrence rule such as
|
173
|
+
# RRULE, EXRULE, or VEVENT
|
174
|
+
def name
|
175
|
+
@rrule.getName
|
176
|
+
end
|
177
|
+
|
178
|
+
# Sets the type of the recurrence rule such as
|
179
|
+
# RRULE, EXRULE, or VEVENT
|
180
|
+
#
|
181
|
+
# ==== Options
|
182
|
+
# +new_name+:: 'RRULE', 'EXRULE', or 'VEVENT'
|
183
|
+
def name=(new_name)
|
184
|
+
@rrule.setName(new_name)
|
185
|
+
self
|
186
|
+
end
|
187
|
+
|
188
|
+
# Gets the WeekdayNums for the recurrence rule
|
189
|
+
# WeekdayNum is an object which specifies the week of year
|
190
|
+
# and the day of week
|
191
|
+
def days
|
192
|
+
@rrule.getByDay.to_a.map do |d|
|
193
|
+
WeekdayNum.new(d)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
# Sets the WeekdayNums for the recurrence rule
|
198
|
+
# WeekdayNum is an object which specifies the week of year
|
199
|
+
# and the day of week
|
200
|
+
#
|
201
|
+
# ==== Options
|
202
|
+
# +new_days+:: Array of WeekdayNums
|
203
|
+
def days=(new_days)
|
204
|
+
@rrule.setByDay(new_days.map {|d| d.to_java})
|
205
|
+
self
|
206
|
+
end
|
207
|
+
|
208
|
+
# Gets the starting day of the week (0-6)
|
209
|
+
def wdaystart
|
210
|
+
weekday = @rrule.getWkSt
|
211
|
+
Weekday::MAP[weekday]
|
212
|
+
end
|
213
|
+
|
214
|
+
# Sets the starting day of the week (0-6, Mon-Sun, Mo-Su)
|
215
|
+
#
|
216
|
+
# ==== Options
|
217
|
+
# +wday+:: 0-6, 'Mon' - 'Sun', or 'Mo' - 'Su'
|
218
|
+
def wdaystart=(wday)
|
219
|
+
wday = Weekday::MAP[wday.to_s.downcase]
|
220
|
+
@rrule.setWkSt(wday)
|
221
|
+
self
|
222
|
+
end
|
223
|
+
|
224
|
+
# Gets the end date
|
225
|
+
def until
|
226
|
+
d = @rrule.getUntil
|
227
|
+
d ? JTime.local(d.year, d.month, d.day, d.hour, d.minute, d.second) : nil
|
228
|
+
end
|
229
|
+
|
230
|
+
# Sets the end date
|
231
|
+
#
|
232
|
+
# ==== Options
|
233
|
+
# +new_date+:: JTime object
|
234
|
+
def until=(new_date)
|
235
|
+
d = com.google.ical.values.DateTimeValueImpl.new(new_date.year, new_date.month, new_date.day, new_date.hour, new_date.min, new_date.sec)
|
236
|
+
@rrule.setUntil(d)
|
237
|
+
self
|
238
|
+
end
|
239
|
+
|
240
|
+
# We should consider getting rid of this or implement this using meta-programming
|
241
|
+
def method_missing(key, *params)
|
242
|
+
@rrule.send(key, *params)
|
243
|
+
end
|
244
|
+
end
|
data/lib/weekday.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'java'
|
2
|
+
require File.dirname(__FILE__) + '/rfc2445.jar'
|
3
|
+
|
4
|
+
class Weekday
|
5
|
+
include_class('com.google.ical.values.Weekday') {|package,name| "J#{name}" }
|
6
|
+
MAP = {
|
7
|
+
'0' => JWeekday::SU, 'sun' => JWeekday::SU, 'su' => JWeekday::SU,
|
8
|
+
'1' => JWeekday::MO, 'mon' => JWeekday::MO, 'mo' => JWeekday::MO,
|
9
|
+
'2' => JWeekday::TU, 'tue' => JWeekday::TU, 'tu' => JWeekday::TU,
|
10
|
+
'3' => JWeekday::WE, 'wed' => JWeekday::WE, 'we' => JWeekday::WE,
|
11
|
+
'4' => JWeekday::TH, 'thu' => JWeekday::TH, 'th' => JWeekday::TH,
|
12
|
+
'5' => JWeekday::FR, 'fri' => JWeekday::FR, 'fr' => JWeekday::FR,
|
13
|
+
'6' => JWeekday::SA, 'sat' => JWeekday::SA, 'sa' => JWeekday::SA,
|
14
|
+
JWeekday::SU => 0,
|
15
|
+
JWeekday::MO => 1,
|
16
|
+
JWeekday::TU => 2,
|
17
|
+
JWeekday::WE => 3,
|
18
|
+
JWeekday::TH => 4,
|
19
|
+
JWeekday::FR => 5,
|
20
|
+
JWeekday::SA => 6,
|
21
|
+
}
|
22
|
+
|
23
|
+
end
|
data/lib/weekday_num.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'java'
|
2
|
+
require File.dirname(__FILE__) + '/rfc2445.jar'
|
3
|
+
|
4
|
+
class WeekdayNum
|
5
|
+
include_class('com.google.ical.values.WeekdayNum'){|package,name| "J#{name}" }
|
6
|
+
|
7
|
+
# Initializes a WeekdayNum objects.
|
8
|
+
# It accepts a Java WeekdayNum object (com.google.ical.values.WeekdayNum) or
|
9
|
+
# the number of the week and the day of the week
|
10
|
+
def initialize(*args)
|
11
|
+
if args.size == 1
|
12
|
+
@weekdaynum = args[0]
|
13
|
+
elsif args.size == 2
|
14
|
+
num = args[0]
|
15
|
+
wday = args[1]
|
16
|
+
@weekdaynum = JWeekdayNum.new(num, Weekday::MAP[wday.to_s.downcase])
|
17
|
+
end
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_ical
|
22
|
+
@weekdaynum.toIcal
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
@weekdaynum.toString
|
27
|
+
end
|
28
|
+
|
29
|
+
def ==(weekdaynum)
|
30
|
+
@weekdaynum.equals(weekdaynum.to_java)
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_java
|
34
|
+
@weekdaynum
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,501 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'spec'
|
3
|
+
require File.dirname(__FILE__) + '/../lib/rfc2445'
|
4
|
+
|
5
|
+
describe JTime do
|
6
|
+
it "should able to initialize a new JTime with the current time" do
|
7
|
+
now = Time.now
|
8
|
+
time = JTime.new
|
9
|
+
time.should_not be_nil
|
10
|
+
time.to_java.getYear.should == now.year
|
11
|
+
time.to_java.getDayOfMonth.should == now.day
|
12
|
+
time.to_java.getMonthOfYear.should == now.month
|
13
|
+
time.to_java.getHourOfDay.should == now.hour
|
14
|
+
time.to_java.getMinuteOfHour.should == now.min
|
15
|
+
|
16
|
+
time = JTime.now
|
17
|
+
time.should_not be_nil
|
18
|
+
time.to_java.getYear.should == now.year
|
19
|
+
time.to_java.getDayOfMonth.should == now.day
|
20
|
+
time.to_java.getMonthOfYear.should == now.month
|
21
|
+
time.to_java.getHourOfDay.should == now.hour
|
22
|
+
time.to_java.getMinuteOfHour.should == now.min
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should able to initialize a new JTime with epoch second" do
|
26
|
+
now = Time.now
|
27
|
+
time = JTime.at(now.to_i)
|
28
|
+
time.to_java.getYear.should == now.year
|
29
|
+
time.to_java.getDayOfMonth.should == now.day
|
30
|
+
time.to_java.getMonthOfYear.should == now.month
|
31
|
+
time.to_java.getHourOfDay.should == now.hour
|
32
|
+
time.to_java.getMinuteOfHour.should == now.min
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should able to initialize a new JTime with utc" do
|
36
|
+
time = JTime.utc(2000, "dec", 25, 20, 15, 1)
|
37
|
+
time.to_java.getYear.should == 2000
|
38
|
+
time.to_java.getMonthOfYear.should == 12
|
39
|
+
time.to_java.getDayOfMonth.should == 25
|
40
|
+
time.to_java.getHourOfDay.should == 20
|
41
|
+
time.to_java.getMinuteOfHour.should == 15
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should able to initialize a new JTime with local" do
|
45
|
+
time = JTime.local(2000, "dec", 25, 20, 15, 1)
|
46
|
+
time.to_java.getYear.should == 2000
|
47
|
+
time.to_java.getMonthOfYear.should == 12
|
48
|
+
time.to_java.getDayOfMonth.should == 25
|
49
|
+
time.to_java.getHourOfDay.should == 20
|
50
|
+
time.to_java.getMinuteOfHour.should == 15
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should able to initialize a new JTime with DateTimeValue" do
|
54
|
+
dtv = com.google.ical.values.DateTimeValueImpl.new(2000, 12, 25, 20, 15, 1)
|
55
|
+
time = JTime.from_date_time_value(dtv)
|
56
|
+
time.to_java.getYear.should == 2000
|
57
|
+
time.to_java.getMonthOfYear.should == 12
|
58
|
+
time.to_java.getDayOfMonth.should == 25
|
59
|
+
time.to_java.getHourOfDay.should == 20
|
60
|
+
time.to_java.getMinuteOfHour.should == 15
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should able to initialize a new JTime object from Ruby Time" do
|
64
|
+
now = Time.now
|
65
|
+
jtime = JTime.from_time(now)
|
66
|
+
jtime.should be_instance_of(JTime)
|
67
|
+
jtime.year.should == now.year
|
68
|
+
jtime.month.should == now.month
|
69
|
+
jtime.day.should == now.day
|
70
|
+
jtime.hour.should == now.hour
|
71
|
+
jtime.min.should == now.min
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should return a Ruby time object" do
|
75
|
+
now = Time.now
|
76
|
+
time = JTime.new
|
77
|
+
rtime = time.to_time
|
78
|
+
rtime.should be_instance_of(Time)
|
79
|
+
rtime.year.should == now.year
|
80
|
+
rtime.month.should == now.month
|
81
|
+
rtime.day.should == now.day
|
82
|
+
rtime.hour.should == now.hour
|
83
|
+
rtime.min.should == now.min
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should return a Java DateTime object" do
|
87
|
+
time = JTime.new
|
88
|
+
jtime = time.to_java
|
89
|
+
jtime.java_kind_of?(org.joda.time.DateTime).should == true
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should return a date time value object" do
|
93
|
+
time = JTime.new
|
94
|
+
dtv = time.to_date_time_value
|
95
|
+
dtv.java_kind_of?(com.google.ical.values.DateTimeValueImpl).should == true
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should able to return a UTC time" do
|
99
|
+
time = JTime.now
|
100
|
+
utc_time = time.utc
|
101
|
+
ruby_utc_time = time.to_time.utc
|
102
|
+
utc_time.to_java.getHourOfDay.should == ruby_utc_time.hour
|
103
|
+
utc_time.to_java.getMinuteOfHour.should == ruby_utc_time.min
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should return if dst" do
|
107
|
+
time1 = JTime.local(2008, "dec", 25, 20, 15, 1)
|
108
|
+
time2 = JTime.local(2008, "jul", 1, 20, 15, 1)
|
109
|
+
time1.dst?.should == false
|
110
|
+
time2.isdst.should == true
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should able to compare with another JTime" do
|
114
|
+
time1 = JTime.new
|
115
|
+
time2 = JTime.local(2000, "dec", 25, 20, 15, 1)
|
116
|
+
(time1 > time2).should == true
|
117
|
+
(time1 < time2).should == false
|
118
|
+
(time1 == time1).should == true
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should return the year for time" do
|
122
|
+
time = JTime.local(2008, "dec", 25, 20, 15, 1)
|
123
|
+
time.year.should == 2008
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should return the month of the year" do
|
127
|
+
time = JTime.local(2008, "dec", 25, 20, 15, 1)
|
128
|
+
time.month.should == 12
|
129
|
+
time.mon.should == 12
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should return the day of the month" do
|
133
|
+
time = JTime.local(2008, "dec", 25, 20, 15, 1)
|
134
|
+
time.day.should == 25
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should return the hour of the day" do
|
138
|
+
time = JTime.local(2008, "dec", 25, 20, 15, 1)
|
139
|
+
time.hour.should == 20
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should return the minute of the hour" do
|
143
|
+
time = JTime.local(2008, "dec", 25, 20, 15, 1)
|
144
|
+
time.min.should == 15
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should return the second of the minute" do
|
148
|
+
time = JTime.local(2008, "dec", 25, 20, 15, 1)
|
149
|
+
time.day.should == 25
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should return the day of the week"do
|
153
|
+
time = JTime.local(2008, "dec", 25, 20, 15, 1)
|
154
|
+
time.wday.should == 4
|
155
|
+
end
|
156
|
+
|
157
|
+
it "should return the day of the year"do
|
158
|
+
time = JTime.local(2008, "dec", 25, 20, 15, 1)
|
159
|
+
time.yday.should == 360
|
160
|
+
end
|
161
|
+
|
162
|
+
it "should return the week number of the year"do
|
163
|
+
time = JTime.local(2008, "dec", 25, 20, 15, 1)
|
164
|
+
time.week.should == 52
|
165
|
+
end
|
166
|
+
|
167
|
+
it "should return a value of time as a floating-point number of seconds since epoch" do
|
168
|
+
time = JTime.new
|
169
|
+
rtime = time.to_time
|
170
|
+
time.to_f.should == rtime.to_f
|
171
|
+
end
|
172
|
+
|
173
|
+
it "should return a value of time as an integer number of seconds since epoch" do
|
174
|
+
time = JTime.new
|
175
|
+
rtime = time.to_time
|
176
|
+
time.to_i.should == rtime.to_i
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should return a string representing time" do
|
180
|
+
time = JTime.new
|
181
|
+
time.should respond_to(:to_s)
|
182
|
+
end
|
183
|
+
|
184
|
+
it "should return the name of the time zone" do
|
185
|
+
# Notice that it is different than the Ruby Time object, it returns the real ID 'America/Los_Angeles' instead of "PST"
|
186
|
+
time = JTime.new.utc
|
187
|
+
time.should respond_to(:zone)
|
188
|
+
time.zone.should == 'UTC'
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
describe RRule do
|
193
|
+
before(:each) do
|
194
|
+
@rrule = RRule.new
|
195
|
+
end
|
196
|
+
|
197
|
+
it "should initialize a RRule object with ical string" do
|
198
|
+
ical_string = "RRULE:FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13;COUNT=13"
|
199
|
+
rrule = RRule.new(ical_string)
|
200
|
+
rrule.should_not be_nil
|
201
|
+
end
|
202
|
+
|
203
|
+
it "should return an ical string" do
|
204
|
+
ical_string = "RRULE:FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13;COUNT=13"
|
205
|
+
rrule = RRule.new(ical_string)
|
206
|
+
(rrule.to_ical =~ /FREQ=MONTHLY/).should_not be_nil
|
207
|
+
(rrule.to_ical =~ /BYDAY=FR/).should_not be_nil
|
208
|
+
(rrule.to_ical =~ /BYMONTHDAY=13/).should_not be_nil
|
209
|
+
(rrule.to_ical =~ /COUNT=13/).should_not be_nil
|
210
|
+
end
|
211
|
+
|
212
|
+
it "should return extra parameters" do
|
213
|
+
ical_string = "RRULE;X-FOO=BAR:FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13;COUNT=13;"
|
214
|
+
rrule = RRule.new(ical_string)
|
215
|
+
ext_params = rrule.ext_params
|
216
|
+
ext_params['X-FOO'].should == 'BAR'
|
217
|
+
end
|
218
|
+
|
219
|
+
it "should set and get the count" do
|
220
|
+
@rrule.count = 13
|
221
|
+
@rrule.count.should == 13
|
222
|
+
end
|
223
|
+
|
224
|
+
it "should set and get the days" do
|
225
|
+
wday = WeekdayNum.new(5, 'Fri')
|
226
|
+
@rrule.days = [wday]
|
227
|
+
(@rrule.days.first == wday).should == true
|
228
|
+
end
|
229
|
+
|
230
|
+
it "should set and get the hours" do
|
231
|
+
@rrule.hours = [1, 13]
|
232
|
+
@rrule.hours.include?(1).should == true
|
233
|
+
@rrule.hours.include?(13).should == true
|
234
|
+
end
|
235
|
+
|
236
|
+
it "should set and get the minutes" do
|
237
|
+
@rrule.minutes = [1, 13]
|
238
|
+
@rrule.minutes.include?(1).should == true
|
239
|
+
@rrule.minutes.include?(13).should == true
|
240
|
+
end
|
241
|
+
|
242
|
+
it "should set and get the monthdays" do
|
243
|
+
@rrule.mdays = [1, 13]
|
244
|
+
@rrule.mdays.include?(1).should == true
|
245
|
+
@rrule.mdays.include?(13).should == true
|
246
|
+
end
|
247
|
+
|
248
|
+
it "should set and get the seconds" do
|
249
|
+
@rrule.seconds = [1, 13]
|
250
|
+
@rrule.seconds.include?(1).should == true
|
251
|
+
@rrule.seconds.include?(13).should == true
|
252
|
+
end
|
253
|
+
|
254
|
+
it "should set and get the week numbers" do
|
255
|
+
@rrule.weeknums = [1, 13]
|
256
|
+
@rrule.weeknums.include?(1).should == true
|
257
|
+
@rrule.weeknums.include?(13).should == true
|
258
|
+
end
|
259
|
+
|
260
|
+
it "should set and get the year days" do
|
261
|
+
@rrule.ydays = [1, 360]
|
262
|
+
@rrule.ydays.include?(1).should == true
|
263
|
+
@rrule.ydays.include?(360).should == true
|
264
|
+
end
|
265
|
+
|
266
|
+
it "should set and get the frequency" do
|
267
|
+
@rrule.frequency = Frequency::MONTHLY
|
268
|
+
@rrule.frequency.should == Frequency::MONTHLY
|
269
|
+
end
|
270
|
+
|
271
|
+
it "should set and get the starting weekday" do
|
272
|
+
@rrule.wdaystart = 'Fri'
|
273
|
+
@rrule.wdaystart.should == 5
|
274
|
+
@rrule.wdaystart = 3
|
275
|
+
@rrule.wdaystart.should == 3
|
276
|
+
end
|
277
|
+
|
278
|
+
it "should set and get the interval" do
|
279
|
+
@rrule.interval = 10
|
280
|
+
@rrule.interval.should == 10
|
281
|
+
end
|
282
|
+
|
283
|
+
it "should set and get the object name, such as RRULE, EXRULE, VEVENT" do
|
284
|
+
@rrule.name = RRule::EXRULE
|
285
|
+
@rrule.name.should == RRule::EXRULE
|
286
|
+
end
|
287
|
+
|
288
|
+
it "should set and get the until date" do
|
289
|
+
now = JTime.new
|
290
|
+
@rrule.until = now
|
291
|
+
@rrule.until.year.should == now.year
|
292
|
+
@rrule.until.month.should == now.month
|
293
|
+
@rrule.until.day.should == now.day
|
294
|
+
@rrule.until.hour.should == now.hour
|
295
|
+
@rrule.until.min.should == now.min
|
296
|
+
@rrule.until.sec.should == now.sec
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
describe RDateList do
|
301
|
+
before(:each) do
|
302
|
+
@rdatelist = RDateList.new
|
303
|
+
end
|
304
|
+
|
305
|
+
it "should initialize a RDateList object with no params" do
|
306
|
+
@rdatelist.should_not be_nil
|
307
|
+
end
|
308
|
+
|
309
|
+
it "should initialize a RDatelist object with a timezone" do
|
310
|
+
rdatelist = RDateList.new('UTC')
|
311
|
+
@rdatelist.should_not be_nil
|
312
|
+
end
|
313
|
+
|
314
|
+
it "should initialize a RDateList object with ical string" do
|
315
|
+
ical_string = "RDATE:19960402T010000,19960403T010000,19960404T010000"
|
316
|
+
rdatelist = RDateList.new(nil, ical_string)
|
317
|
+
rdatelist.should_not be_nil
|
318
|
+
end
|
319
|
+
|
320
|
+
it "should return an ical string" do
|
321
|
+
ical_string = "RDATE:19960402T010000,19960403T010000,19960404T010000"
|
322
|
+
rdatelist = RDateList.new(nil, ical_string)
|
323
|
+
(rdatelist.to_ical =~ /TZID=/).should_not be_nil
|
324
|
+
(rdatelist.to_ical =~ /VALUE=DATE-TIME:/).should_not be_nil
|
325
|
+
(rdatelist.to_ical =~ /19960402/).should_not be_nil
|
326
|
+
(rdatelist.to_ical =~ /19960403/).should_not be_nil
|
327
|
+
(rdatelist.to_ical =~ /19960404/).should_not be_nil
|
328
|
+
end
|
329
|
+
|
330
|
+
it "should return extra parameters" do
|
331
|
+
ical_string = "RDATE;X-FOO=BAR:19960402T010000,19960403T010000,19960404T010000"
|
332
|
+
rdatelist = RDateList.new(nil, ical_string)
|
333
|
+
ext_params = rdatelist.ext_params
|
334
|
+
ext_params['X-FOO'].should == 'BAR'
|
335
|
+
end
|
336
|
+
|
337
|
+
it "should set and get the object name, such as RRULE, EXRULE, VEVENT" do
|
338
|
+
@rdatelist.name = RRule::EXRULE
|
339
|
+
@rdatelist.name.should == RRule::EXRULE
|
340
|
+
end
|
341
|
+
|
342
|
+
it "should set and get timezone" do
|
343
|
+
@rdatelist.zone = 'UTC'
|
344
|
+
@rdatelist.zone.should == 'UTC'
|
345
|
+
end
|
346
|
+
|
347
|
+
it "should set array of utc dates and get array of utc dates" do
|
348
|
+
utc_date = JTime.utc(2008, 12, 25)
|
349
|
+
@rdatelist.utc_dates = [utc_date]
|
350
|
+
@rdatelist.utc_dates.first.year.should == 2008
|
351
|
+
@rdatelist.utc_dates.first.month.should == 12
|
352
|
+
@rdatelist.utc_dates.first.day.should == 25
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
describe ICalParseUtil do
|
357
|
+
it "should parse an ical string and timezone to a date time value" do
|
358
|
+
dtv = ICalParseUtil.parse_date_value('20090327T180000', 'America/Los_Angeles')
|
359
|
+
dtv.java_kind_of?(com.google.ical.values.DateTimeValueImpl).should == true
|
360
|
+
dtv.hour.should == 1
|
361
|
+
dtv.day.should == 28
|
362
|
+
end
|
363
|
+
|
364
|
+
it "should return nil if passing nil to parse_date_value" do
|
365
|
+
dtv = ICalParseUtil.parse_date_value(nil)
|
366
|
+
dtv.should be_nil
|
367
|
+
end
|
368
|
+
|
369
|
+
it "should parse an ical string and timezone to a JTime object" do
|
370
|
+
jtime = ICalParseUtil.parse_jtime('20090327T180000', 'America/Los_Angeles')
|
371
|
+
jtime.should be_instance_of(JTime)
|
372
|
+
jtime.hour.should == 1
|
373
|
+
jtime.day.should == 28
|
374
|
+
end
|
375
|
+
|
376
|
+
it "should return nil if passing nil to parse_jtime" do
|
377
|
+
jtime = ICalParseUtil.parse_jtime(nil)
|
378
|
+
jtime.should be_nil
|
379
|
+
end
|
380
|
+
|
381
|
+
it "should parse a recurrence block" do
|
382
|
+
string = <<-end_src
|
383
|
+
DTSTART;TZID=America/Los_Angeles:20090320T170000
|
384
|
+
DTEND;TZID=America/Los_Angeles:20090320T180000
|
385
|
+
RRULE:FREQ=WEEKLY;BYDAY=FR;WKST=SU
|
386
|
+
EXRULE:FREQ=MONTHLY;BYDAY=1FR
|
387
|
+
RDATE;TZID=America/Los_Angeles:20090321T170000
|
388
|
+
BEGIN:VTIMEZONE
|
389
|
+
TZID:America/Los_Angeles
|
390
|
+
X-LIC-LOCATION:America/Los_Angeles
|
391
|
+
BEGIN:DAYLIGHT
|
392
|
+
TZOFFSETFROM:-0800
|
393
|
+
TZOFFSETTO:-0700
|
394
|
+
TZNAME:PDT
|
395
|
+
DTSTART:19700308T020000
|
396
|
+
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
|
397
|
+
END:DAYLIGHT
|
398
|
+
BEGIN:STANDARD
|
399
|
+
TZOFFSETFROM:-0700
|
400
|
+
TZOFFSETTO:-0800
|
401
|
+
TZNAME:PST
|
402
|
+
DTSTART:19701101T020000
|
403
|
+
RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
|
404
|
+
END:STANDARD
|
405
|
+
END:VTIMEZONE
|
406
|
+
end_src
|
407
|
+
|
408
|
+
r = ICalParseUtil.parse_recurrence(string)
|
409
|
+
r[:dtstart].should == "DTSTART;TZID=America/Los_Angeles:20090320T170000"
|
410
|
+
r[:dtend].should == "DTEND;TZID=America/Los_Angeles:20090320T180000"
|
411
|
+
r[:rrule].should == "RRULE:FREQ=WEEKLY;BYDAY=FR;WKST=SU"
|
412
|
+
r[:exrule].should == "EXRULE:FREQ=MONTHLY;BYDAY=1FR"
|
413
|
+
r[:rdate].should == "RDATE;TZID=America/Los_Angeles:20090321T170000"
|
414
|
+
r[:exdate].should == nil
|
415
|
+
end
|
416
|
+
|
417
|
+
it "should parse datetime into JTime" do
|
418
|
+
jtime1 = ICalParseUtil.parse_datetime('DTSTART;TZID=America/Los_Angeles:20090320T170000')
|
419
|
+
jtime1.should be_instance_of(JTime)
|
420
|
+
jtime1.hour.should == 0
|
421
|
+
|
422
|
+
jtime2 = ICalParseUtil.parse_datetime('DTEND;TZID=America/Los_Angeles:20090320T170000')
|
423
|
+
jtime2.should be_instance_of(JTime)
|
424
|
+
jtime2.hour.should == 0
|
425
|
+
|
426
|
+
jtime3 = ICalParseUtil.parse_datetime(nil)
|
427
|
+
jtime3.should be_nil
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
describe RecurrenceTime do
|
432
|
+
before(:each) do
|
433
|
+
@ical_string = "RRULE:FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13;COUNT=13"
|
434
|
+
@start_date = JTime.local(2001, 4, 13)
|
435
|
+
@rtime = RecurrenceTime.new(@ical_string, @start_date)
|
436
|
+
end
|
437
|
+
|
438
|
+
it "should be initialized by RRule object" do
|
439
|
+
rrule = RRule.new(@ical_string)
|
440
|
+
rtime = RecurrenceTime.new(rrule, @start_date)
|
441
|
+
rtime.should be_instance_of(RecurrenceTime)
|
442
|
+
end
|
443
|
+
|
444
|
+
it "should be initialized by an array of RRules" do
|
445
|
+
rrule1 = RRule.new(@ical_string)
|
446
|
+
# The first date is excluded
|
447
|
+
rrule2 = RRule.new("EXRULE:FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13;COUNT=1")
|
448
|
+
rtime = RecurrenceTime.new([rrule1, rrule2], @start_date)
|
449
|
+
rtime.should be_instance_of(RecurrenceTime)
|
450
|
+
rtime.next.should > @start_date
|
451
|
+
end
|
452
|
+
|
453
|
+
it "should initialized by an array of RRules and RDateLists" do
|
454
|
+
rrule = RRule.new(@ical_string)
|
455
|
+
rdatelist = RDateList.new
|
456
|
+
rdatelist.utc_dates = [JTime.utc(2001, 4, 14)]
|
457
|
+
rtime = RecurrenceTime.new([rdatelist, rrule], @start_date)
|
458
|
+
rtime.should be_instance_of(RecurrenceTime)
|
459
|
+
rtime.next
|
460
|
+
first_next = rtime.next
|
461
|
+
first_next.mon.should == 4
|
462
|
+
first_next.day.should == 14
|
463
|
+
first_next.year.should == 2001
|
464
|
+
end
|
465
|
+
|
466
|
+
it "should able to generate a JTime by invoking next" do
|
467
|
+
nexttime = @rtime.next
|
468
|
+
nexttime.should be_instance_of(JTime)
|
469
|
+
(nexttime <=> @start_date).should == 0
|
470
|
+
end
|
471
|
+
|
472
|
+
it "should able to advance to a specific date" do
|
473
|
+
# It skips 2 dates 4/13 and 7/13
|
474
|
+
@rtime.advance_to(JTime.utc(2001, 7, 15))
|
475
|
+
third_next = @rtime.next
|
476
|
+
third_next.mon.should == 9
|
477
|
+
third_next.day.should == 13
|
478
|
+
third_next.year.should == 2002
|
479
|
+
end
|
480
|
+
|
481
|
+
it "should return true if there is more time for the recurrence time" do
|
482
|
+
13.times do
|
483
|
+
@rtime.has_next?.should == true
|
484
|
+
@rtime.next
|
485
|
+
end
|
486
|
+
@rtime.has_next?.should == false
|
487
|
+
end
|
488
|
+
|
489
|
+
it "should return the java iterator" do
|
490
|
+
@rtime.to_java.java_kind_of?(com.google.ical.compat.jodatime.DateTimeIterator).should == true
|
491
|
+
end
|
492
|
+
|
493
|
+
it "should able to iterate" do
|
494
|
+
i = 0
|
495
|
+
@rtime.each do |t|
|
496
|
+
i += 1
|
497
|
+
t.should be_instance_of(JTime)
|
498
|
+
end
|
499
|
+
i.should == 13
|
500
|
+
end
|
501
|
+
end
|
metadata
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jruby-rfc2445
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jerry Luk
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-03-24 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: A JRuby implementation of RFC 2445 (ical) recurrence rule
|
17
|
+
email: jerryluk@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- README
|
26
|
+
- MIT-LICENSE
|
27
|
+
- lib/ical_parse_util.rb
|
28
|
+
- lib/jtime.rb
|
29
|
+
- lib/rdate_list.rb
|
30
|
+
- lib/recurrence_time.rb
|
31
|
+
- lib/rfc2445.rb
|
32
|
+
- lib/rfc2445.jar
|
33
|
+
- lib/rrule.rb
|
34
|
+
- lib/weekday.rb
|
35
|
+
- lib/weekday_num.rb
|
36
|
+
- spec/rfc2445_spec.rb
|
37
|
+
has_rdoc: true
|
38
|
+
homepage: http://www.linkedin.com/in/jerryluk
|
39
|
+
licenses: []
|
40
|
+
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: "0"
|
51
|
+
version:
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
version:
|
58
|
+
requirements: []
|
59
|
+
|
60
|
+
rubyforge_project:
|
61
|
+
rubygems_version: 1.3.5
|
62
|
+
signing_key:
|
63
|
+
specification_version: 3
|
64
|
+
summary: A JRuby implementation of RFC 2445 (ical) recurrence rule
|
65
|
+
test_files:
|
66
|
+
- spec/rfc2445_spec.rb
|