Permalink
Browse files

FREQ=weekly support

  • Loading branch information...
1 parent 9f9dfbf commit f7c4385ba44f25b26737eac55423437598d5ec07 @sam-github committed Feb 25, 2008
View
@@ -2,7 +2,7 @@
SHELL:=/bin/sh
-RUBY=/opt/local/bin/ruby
+RUBY=/usr/bin/ruby
.PHONY: default doc test other
@@ -118,7 +118,7 @@ stamp:
gem:
mkdir -p releases
- ruby18 vpim.gemspec
+ ruby vpim.gemspec
mv vpim-$V.gem releases/
pkg:
@@ -131,7 +131,7 @@ pkg:
mkdir -p $R/samples
mkdir -p $R/test
mkdir -p $R/etc
- cp COPYING README CHANGES install.rb $R/
+ cp COPYING README CHANGES setup.rb $R/
cp lib/*.rb $R/lib/
cp lib/vpim/*.rb $R/lib/vpim/
cp lib/vpim/maker/*.rb $R/lib/vpim/maker/
View
4 TODO
@@ -4,8 +4,12 @@ Output a graph of the connections in address book, spouses, etc.
http://serveringhaus.org/projects/icv - ical validator
+http://wiki.mozilla.org/Calendar:QA_Test_Servers
ical2 support
+ical3 support
+
+http://www.kanzaki.com/docs/ical/
vpim rrule encoding APIs
View
@@ -10,10 +10,10 @@ D/property////
/icalendar.rb/1.1/Sat Mar 10 01:16:32 2007//
/rfc2425.rb/1.2/Tue Oct 30 05:55:54 2007//
/rrule.rb/1.2/Fri Sep 21 03:10:53 2007//
-/time.rb/1.1/Sat Mar 10 01:16:32 2007//
/vcard.rb/1.1/Sat Mar 10 01:16:32 2007//
/version.rb/1.1/Sat Feb 16 22:27:14 2008//
/vevent.rb/1.1/Sat Mar 10 01:16:32 2007//
/vjournal.rb/1.1/Sat Mar 10 01:16:32 2007//
/vpim.rb/1.1/Sat Mar 10 01:16:32 2007//
/vtodo.rb/1.2/Wed Oct 24 03:24:22 2007//
+/time.rb/1.1/Sun Feb 17 22:10:04 2008//
View
@@ -77,8 +77,8 @@ def Date.str2wday(wdaystr)
# - Date.bywday(2004, -2, 3, -2) => second last Wednesday in the second last month of 2004
#
# Compare this to Date.new, which allows a Date to be created by
- # day-of-the-month, mday, to Date.new2, which allows a Date to be created by
- # day-of-the-year, yday, and to Date.neww, which allows a Date to be created
+ # day-of-the-month, mday, to Date.ordinal, which allows a Date to be created by
+ # day-of-the-year, yday, and to Date.commercial, which allows a Date to be created
# by day-of-the-week, but within a specific week.
def Date.bywday(year, mon, wday, n = 1, sg=Date::ITALY)
# Normalize mon to 1-12.
@@ -120,10 +120,36 @@ def Date.bywday(year, mon, wday, n = 1, sg=Date::ITALY)
end
d
end
+
+ # Return the first day of the week for the specified date. Commercial weeks
+ # start on Monday, but the weekstart can be specified (as 0-6, where 0 is
+ # sunday, or in formate of Date.str2day).
+ def Date.weekstart(year, mon, day, weekstart="MO")
+ wkst = Date.str2wday(weekstart)
+ d = Date.new(year, mon, day)
+ until d.wday == wkst
+ d = d - 1
+ end
+ d
+ end
end
# DateGen generates arrays of dates matching simple criteria.
class DateGen
+
+ # Generate an array of a week's dates, where week is specified by year, mon,
+ # day, and the weekstart (the day-of-week that is considered the "first" day
+ # of that week, 0-6, where 0 is sunday).
+ def DateGen.weekofdate(year, mon, day, weekstart)
+ d = Date.weekstart(year, mon, day, weekstart)
+ week = []
+ 7.times do
+ week << d
+ d = d + 1
+ end
+ week
+ end
+
# Generate an array of dates on +wday+ (the day-of-week,
# 0-6, where 0 is Sunday).
#
View
@@ -16,6 +16,12 @@
$debug = ENV['DEBUG']
+class Date
+ def inspect
+ self.to_s
+ end
+end
+
def debug(*objs)
if $debug
pp(*objs)
@@ -30,14 +36,14 @@ module Vpim
# syntax description and examples from RFC 2445. The description is pretty
# hard to understand, but the examples are more helpful.
#
- # The implementation is pretty complete, but still lacks support for:
+ # The implementation is reasonably complete, but still lacks support for:
#
- # TODO - BYWEEKLY, BYWEEKNO, WKST: rules that recur by the week, or are
- # limited to particular weeks, not hard, but not trivial, I'll do it for the
- # next release
+ # Recurrence by date (RDATE) and exclusions (EXDATE, EXRULE).
+ #
+ # TODO - BYWEEKNO: rules that are limited to particular weeks in a year.
#
# TODO - BYHOUR, BYMINUTE, BYSECOND: trivial to do, but I don't have an
- # immediate need for them, I'll do it for the next release
+ # immediate need for them.
#
# TODO - BYSETPOS: limiting to only certain recurrences in a set (what does
# -1, last occurence, mean for an infinitely occuring rule?)
@@ -139,16 +145,18 @@ def each_until(dountil)
# most systems.
def each(dountil = nil) #:yield: ytime
t = @dtstart.clone
- count = 1
# Time.to_a => [ sec, min, hour, day, month, year, wday, yday, isdst, zone ]
- # Every event occurs at least once, at its start time, but only if the start
- # time is earlier than DOUNTIL...
+ # Every event occurs at its start time, but only if the start time is
+ # earlier than DOUNTIL...
+ if !dountil || t < dountil
+ yield t
+ end
+ count = 1
+
+ # With no recurrence, DTSTART is the only occurence.
if !@rrule
- if !dountil || t < dountil
- yield t
- end
return self
end
@@ -168,20 +176,21 @@ def each(dountil = nil) #:yield: ytime
#when 'YEARLY' then
# Don't need to keep track of year, all occurences are within t's
# year.
- when 'MONTHLY' then days.month = t.month #month = { t.month => nil }
- # when 'WEEKLY' then days.mday = t.month, t.mday
+ when 'MONTHLY' then days.month = t.month
+ when 'WEEKLY' then #days.month = t.month
# TODO - WEEKLY
- when 'DAILY' then days.mday = t.month, t.mday #month = { t.month => [ t.mday ] }
- when 'HOURLY' then hour = [t.hour]
- when 'MINUTELY' then min = [t.min]
- when 'SECONDLY' then sec = [t.sec]
+ when 'DAILY' then days.mday = t.month, t.mday
+ when 'HOURLY' then hour = [t.hour]
+ when 'MINUTELY' then min = [t.min]
+ when 'SECONDLY' then sec = [t.sec]
end
+ # debug [t, days]
# Process the BY* modifiers in RFC defined order:
# BYMONTH, BYWEEKNO, BYYEARDAY, BYMONTHDAY, BYDAY,
# BYHOUR, BYMINUTE, BYSECOND and BYSETPOS
-
- bymon = [nil]
+
+ bymon = [nil]
if @by['BYMONTH']
bymon = @by['BYMONTH'].split(',')
@@ -220,7 +229,6 @@ def each(dountil = nil) #:yield: ytime
if @by['BYDAY']
byday = @by['BYDAY'].scan(/,?([+-]?[1-9]?\d*)?(SU|MO|TU|WE|TH|FR|SA)/i)
- # debug byday
# BYDAY means different things in different frequencies. The +n+
# is only meaningful when freq is yearly or monthly.
@@ -231,7 +239,7 @@ def each(dountil = nil) #:yield: ytime
when 'MONTHLY'
dates = byday_in_monthly(t.year, t.month, byday)
when 'WEEKLY'
- # dates = byday_in_weekly(t.year, wkstart, t.month, t.day, byday)
+ dates = byday_in_weekly(t.year, t.month, t.mday, @wkst, byday)
when 'DAILY', 'HOURLY', 'MINUTELY', 'SECONDLY'
# Reuse the byday_in_monthly. Current day is already specified,
# so this will just eliminate the current day if its not allowed
@@ -248,29 +256,34 @@ def each(dountil = nil) #:yield: ytime
# TODO - BYSETPOS
- # Yield the time, if we haven't gone over COUNT, or past UNTIL, or past
- # the end of representable time.
-
hour = [@dtstart.hour] if !hour
min = [@dtstart.min] if !min
sec = [@dtstart.sec] if !sec
# debug days
+ # Yield the time, if we haven't gone over COUNT, or past UNTIL, or past
+ # the end of representable time.
+
days.each do |m,d|
hour.each do |h|
min.each do |n|
sec.each do |s|
- if(@count && (count > @count))
- return self
- end
y = Time.local(t.year, m, d, h, n, s, 0)
next if y.hour != h
# The generated set can sometimes generate results earlier
- # than the DTSTART, skip them.
- next if y < @dtstart
+ # than the DTSTART, skip them. Also, we already yielded
+ # DTSTART, skip it.
+ next if y <= @dtstart
+
+ count += 1
+
+ # We are done if current count is past @count.
+ if(@count && (count > @count))
+ return self
+ end
# We are done if current time is past @until.
if @until && (y > @until)
@@ -282,7 +295,6 @@ def each(dountil = nil) #:yield: ytime
return self
end
yield y
- count += 1
end
end
end
@@ -363,30 +375,30 @@ def intersect_bymon(bymon) #:nodoc:
end
def intersect_dates(dates) #:nodoc:
- if dates
- # If no months are in the dayset, add all the ones in dates
- if !@month
- @month = {}
+ return unless dates
- dates.each do |d|
- @month[d.mon] = nil
- end
+ # If no months are in the dayset, add all the ones in dates
+ if !@month
+ @month = {}
+
+ dates.each do |d|
+ @month[d.mon] = nil
end
+ end
- # In each month,
- # if there are days,
- # eliminate those not in dates
- # otherwise
- # add all those in dates
- @month.each do |mon, days|
- days_in_mon = dates.find_all { |d| d.mon == mon }
- days_in_mon = days_in_mon.collect { |d| d.day }
-
- if days
- days_in_mon = days_in_mon & days
- end
- @month[mon] = days_in_mon
+ # In each month,
+ # if there are days,
+ # eliminate those not in dates
+ # otherwise
+ # add all those in dates
+ @month.each do |mon, days|
+ days_in_mon = dates.find_all { |d| d.mon == mon }
+ days_in_mon = days_in_mon.collect { |d| d.day }
+
+ if days
+ days_in_mon = days_in_mon & days
end
+ @month[mon] = days_in_mon
end
end
@@ -451,7 +463,7 @@ def byyearday(year, byyday) #:nodoc:
dates = []
byyday.each do |yday|
- dates << Date.new2(year, yday[0].to_i)
+ dates << Date.ordinal(year, yday[0].to_i)
end
dates.sort!
dates
@@ -472,6 +484,17 @@ def byday_in_monthly(year, mon, byday) #:nodoc:
dates
end
+ def byday_in_weekly(year, mon, day, wkst, byday)
+ # debug ["day", year,mon,day,wkst,byday]
+ days = byday.map{ |_, byday| Date.str2wday(byday) }
+ week = DateGen.weekofdate(year, mon, day, wkst)
+ # debug [ "week", dates ]
+ week.delete_if do |d|
+ !days.include?(d.wday)
+ end
+ week
+ end
+
end
end
View
@@ -1,5 +1,7 @@
#!/usr/bin/env ruby
+$-w = true
+
$:.unshift File.dirname($0)
require 'rmail'
View
@@ -1,6 +1,7 @@
#!/usr/bin/env ruby
-$:.unshift File.dirname($0) + '/lib'
+$-w = true
+$:.unshift File.dirname($0) + '/../lib'
require 'osx-wrappers'
View
@@ -1,6 +1,7 @@
#!/usr/bin/env ruby
-$:.unshift File.dirname($0)
+$-w = true
+$:.unshift File.dirname($0) + '/../lib'
require 'getoptlong'
@@ -109,9 +110,9 @@
puts e.description
end
- if e.comment
+ if e.comments
puts finish="-- Comment --"
- puts " comment=#{e.comment}"
+ puts " comment=#{e.comments}"
end
if e.attendees.first
View
@@ -2,7 +2,8 @@
#
# Calendars are in ~/Library/Calendars/
-$:.unshift File.dirname($0) + "/lib"
+$-w = true
+$:.unshift File.dirname($0) + '/../lib'
require 'getoptlong'
require 'pp'
@@ -1,6 +1,7 @@
#!/usr/bin/env ruby
-$:.unshift File.dirname($0)
+$-w = true
+$:.unshift File.dirname($0) + '/../lib'
require 'vpim/vcard'
Oops, something went wrong.

0 comments on commit f7c4385

Please sign in to comment.