jruby-rfc2445 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|