recurring 0.3.2 → 0.3.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +4 -0
- data/Rakefile +12 -13
- data/lib/recurring.rb +48 -14
- data/spec/recurring_spec.rb +79 -2
- metadata +2 -2
data/History.txt
CHANGED
data/Rakefile
CHANGED
@@ -25,7 +25,6 @@ Hoe.new('recurring', Recurring::VERSION) do |p|
|
|
25
25
|
p.description =<<-DESC
|
26
26
|
Recurring allows you to define Schedules, which can tell you whether or not a given Time falls in the Schedule, as well as being able to return a list of times which match the Schedule within a given range.
|
27
27
|
DESC
|
28
|
-
puts p.changes
|
29
28
|
end
|
30
29
|
|
31
30
|
# specification = Gem::Specification.new do |s|
|
@@ -52,17 +51,17 @@ end
|
|
52
51
|
# pkg.need_tar = true
|
53
52
|
# end
|
54
53
|
#
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
#
|
64
|
-
|
65
|
-
|
66
|
-
|
54
|
+
Rake::RDocTask.new(:docs) do |rd|
|
55
|
+
rd.main = "README.txt"
|
56
|
+
rd.options << '-d' if RUBY_PLATFORM !~ /win32/ and `which dot` =~ /\/dot/
|
57
|
+
rd.rdoc_dir = 'doc'
|
58
|
+
files = ["History.txt", "README.txt", "Rakefile", "lib/recurring.rb", "spec/recurring_spec.rb"]
|
59
|
+
rd.rdoc_files.push(*files)
|
60
|
+
|
61
|
+
title = "Recurring-#{VERSION} Documentation"
|
62
|
+
#title = "#{rubyforge_name}'s " + title if rubyforge_name != title
|
63
|
+
|
64
|
+
rd.options << "-t #{title}"
|
65
|
+
end
|
67
66
|
|
68
67
|
|
data/lib/recurring.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Recurring
|
2
|
-
VERSION = '0.3.
|
3
|
-
|
2
|
+
VERSION = '0.3.10'
|
4
3
|
class << self
|
4
|
+
|
5
5
|
# returns a number starting with 1
|
6
6
|
def week_in_month date
|
7
7
|
(((date.day - 1).to_f / 7.0) + 1).floor
|
@@ -45,8 +45,8 @@ module Recurring
|
|
45
45
|
|
46
46
|
attr_reader :unit, :frequency, :anchor, :months, :weeks, :monthdays, :weekdays, :times
|
47
47
|
|
48
|
-
#
|
49
|
-
# * valid
|
48
|
+
# Options hash has keys <tt>:unit, :frequency, :anchor, :weeks, :monthdays, :weekdays, :times</tt>
|
49
|
+
# * valid values for :unit are <tt>years, months, weeks, days, hours, minutes</tt>
|
50
50
|
# * :frequency defaults to 1
|
51
51
|
# * :anchor is required if the frequency is other than one
|
52
52
|
# * :weeks alongside :weekdays is used to specify the nth instance of a weekday in a month.
|
@@ -64,11 +64,19 @@ module Recurring
|
|
64
64
|
@frequency = options[:frequency] || 1
|
65
65
|
@anchor = options[:anchor]
|
66
66
|
@times = parse_times options[:times]
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
67
|
+
if options[:months]
|
68
|
+
@months = Array(options[:months]).collect{|d|d.to_s.downcase.to_sym}
|
69
|
+
raise ArgumentError, 'provide valid months' unless @months.all?{|m|ordinal_month(m)}
|
70
|
+
end
|
71
|
+
|
72
|
+
@weeks = Array(options[:weeks]).collect{|n|n.to_i} if options[:weeks]
|
73
|
+
if options[:weekdays]
|
74
|
+
@weekdays = Array(options[:weekdays]).collect{|d|d.to_s.downcase.to_sym}
|
75
|
+
raise ArgumentError, 'provide valid weekdays' unless @weekdays.all?{|w|ordinal_weekday(w)}
|
76
|
+
end
|
77
|
+
@monthdays = Array(options[:monthdays]).collect{|n|n.to_i} if options[:monthdays]
|
71
78
|
|
79
|
+
|
72
80
|
@anchor_multiple = options[:times].nil? && options[:weeks].nil? && options[:weekdays].nil? && options[:monthdays].nil?
|
73
81
|
end
|
74
82
|
|
@@ -100,6 +108,7 @@ module Recurring
|
|
100
108
|
def find_next date
|
101
109
|
loop do
|
102
110
|
return date if include?(date)
|
111
|
+
#puts "#{@resolution} : #{date}"
|
103
112
|
date = beginning_of_next @resolution, date
|
104
113
|
end
|
105
114
|
end
|
@@ -108,6 +117,7 @@ module Recurring
|
|
108
117
|
def find_previous date
|
109
118
|
loop do
|
110
119
|
return date if include?(date)
|
120
|
+
#puts "#{@resolution} : #{date}"
|
111
121
|
date = end_of_previous @resolution, date
|
112
122
|
end
|
113
123
|
end
|
@@ -153,7 +163,7 @@ module Recurring
|
|
153
163
|
when :week
|
154
164
|
to_sunday = date.wday
|
155
165
|
previous_week = (date - to_sunday*24*60*60)
|
156
|
-
Time.utc(previous_week.year, previous_week.month, previous_week.day)
|
166
|
+
Time.utc(previous_week.year, previous_week.month, previous_week.day) - 1
|
157
167
|
when :day
|
158
168
|
Time.utc(date.year, date.month, date.day) - 1
|
159
169
|
when :time
|
@@ -179,6 +189,10 @@ module Recurring
|
|
179
189
|
Time.utc(dayp.year, dayp.month, dayp.day)
|
180
190
|
when :time
|
181
191
|
next_time date
|
192
|
+
when :hour
|
193
|
+
date.hour < 23 ? Time.utc(date.year, date.month, date.day, date.hour+1) : beginning_of_next(:day, date)
|
194
|
+
when :sub_hour
|
195
|
+
next_sub_hour date
|
182
196
|
else
|
183
197
|
date + 1
|
184
198
|
end
|
@@ -221,6 +235,23 @@ module Recurring
|
|
221
235
|
end
|
222
236
|
end
|
223
237
|
|
238
|
+
def next_sub_hour date
|
239
|
+
me = {:minute => date.min, :second => date.sec, :me => true}
|
240
|
+
my_times = times + [me]
|
241
|
+
my_times += [{:minute => @anchor.min, :second => @anchor.sec}] if check_anchor?
|
242
|
+
my_times.sort! do |a,b|
|
243
|
+
v = a[:minute] <=> b[:minute]
|
244
|
+
v = a[:second] <=> b[:second] if v == 0
|
245
|
+
v
|
246
|
+
end
|
247
|
+
ntime = my_times[my_times.index(me)+1]
|
248
|
+
if ntime
|
249
|
+
Time.utc(date.year, date.month, date.day, date.hour, ntime[:minute], ntime[:second])
|
250
|
+
else
|
251
|
+
beginning_of_next :hour, date
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
224
255
|
def mismatch unit
|
225
256
|
@resolution = unit
|
226
257
|
false
|
@@ -246,9 +277,9 @@ module Recurring
|
|
246
277
|
end
|
247
278
|
|
248
279
|
def week_matches? date
|
249
|
-
|
280
|
+
if @unit == :weeks
|
250
281
|
return true if @frequency == 1
|
251
|
-
return (Recurring.week_of_year(date) - Recurring.week_of_year(@anchor)) % @frequency == 0
|
282
|
+
return ((Recurring.week_of_year(date) - Recurring.week_of_year(@anchor)) % @frequency) == 0
|
252
283
|
end
|
253
284
|
if @weeks
|
254
285
|
@weeks.include?(Recurring.week_in_month(date))
|
@@ -325,7 +356,8 @@ module Recurring
|
|
325
356
|
4 => [:thursday, :thurs],
|
326
357
|
5 => [:friday, :fri],
|
327
358
|
6 => [:saturday, :sat]}
|
328
|
-
lookup.select{|k,v| v.include?(symbol)}.first
|
359
|
+
pair = lookup.select{|k,v| v.include?(symbol)}.first
|
360
|
+
pair.first if pair
|
329
361
|
end
|
330
362
|
|
331
363
|
def ordinal_month symbol
|
@@ -341,7 +373,8 @@ module Recurring
|
|
341
373
|
10 => [:october, :oct],
|
342
374
|
11 => [:november, :nov],
|
343
375
|
12 => [:december, :dec]}
|
344
|
-
|
376
|
+
pair = lookup.select{|k,v| v.include?(symbol)}.first
|
377
|
+
pair.first if pair
|
345
378
|
end
|
346
379
|
|
347
380
|
def parse_times string
|
@@ -356,7 +389,8 @@ module Recurring
|
|
356
389
|
time[:hour], time[:minute], time[:second] = st.split(':').collect {|n| n.to_i}
|
357
390
|
time[:minute] ||= 0
|
358
391
|
time[:second] ||= 0
|
359
|
-
time[:hour] = time[:hour] + 12 if am_pm == 'pm'
|
392
|
+
time[:hour] = time[:hour] + 12 if am_pm == 'pm' && time[:hour] < 12
|
393
|
+
time[:hour] = 0 if am_pm == 'am' && time[:hour] == 12
|
360
394
|
time
|
361
395
|
end
|
362
396
|
#this is an implementation of Array#uniq required because Hash#eql? is not a synonym for Hash#==
|
data/spec/recurring_spec.rb
CHANGED
@@ -34,6 +34,18 @@ context "Initializing a Schedule" do
|
|
34
34
|
rs.times.should == [{:hour => 16, :minute => 30, :second => 0}, {:hour => 17, :minute => 0, :second => 0}, {:hour => 3, :minute => 30, :second => 30}]
|
35
35
|
end
|
36
36
|
|
37
|
+
specify "should not add 12 hours to '12pm'" do
|
38
|
+
rs = Recurring::Schedule.new :unit => 'days', :times => '12pm'
|
39
|
+
rs.times.should == [{:hour => 12, :minute => 0, :second => 0}]
|
40
|
+
end
|
41
|
+
|
42
|
+
specify "should subtract 12 hours from '12am'" do
|
43
|
+
rs = Recurring::Schedule.new :unit => 'days', :times => '12am'
|
44
|
+
rs.times.should == [{:hour => 0, :minute => 0, :second => 0}]
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
|
37
49
|
specify "should be graceful about a duplicate times string" do
|
38
50
|
rs = Recurring::Schedule.new :unit => 'days', :times => '4:30 4:30'
|
39
51
|
rs.times.should == [{:hour => 4, :minute => 30, :second => 0}]
|
@@ -64,12 +76,25 @@ context "Initializing a Schedule" do
|
|
64
76
|
rs.weekdays.should == [:monday, :wednesday]
|
65
77
|
end
|
66
78
|
|
79
|
+
specify "should flip out if weekdays aren't in the white list" do
|
80
|
+
lambda{Recurring::Schedule.new :unit => 'months', :weeks => [1,2], :weekdays => %w{garbage_day thanksgiving}}.should_raise ArgumentError
|
81
|
+
end
|
82
|
+
|
83
|
+
specify "should flip out if months aren't in the white list" do
|
84
|
+
lambda{Recurring::Schedule.new :unit => 'years', :months => %w{monsoon ramadan}, :weeks => [1,2], :weekdays => %w{mon}}.should_raise ArgumentError
|
85
|
+
end
|
86
|
+
|
67
87
|
specify "should accept months params" do
|
68
88
|
rs = Recurring::Schedule.new :unit => 'years', :months => 'feb', :monthdays => [4]
|
69
89
|
rs.months.should == [:feb]
|
70
90
|
end
|
71
91
|
|
72
|
-
specify "should accept
|
92
|
+
specify "should accept monthdays as strings" do
|
93
|
+
rs = Recurring::Schedule.new :unit => 'months', :monthdays => ['1','15']
|
94
|
+
rs.monthdays.should == [1,15]
|
95
|
+
end
|
96
|
+
|
97
|
+
specify "should accept monthdays as integers" do
|
73
98
|
rs = Recurring::Schedule.new :unit => 'months', :monthdays => [1,15]
|
74
99
|
rs.monthdays.should == [1,15]
|
75
100
|
end
|
@@ -320,6 +345,49 @@ end
|
|
320
345
|
|
321
346
|
#WEEKLY
|
322
347
|
|
348
|
+
context "A bi-weekly schedule with weekdays and a midnight time" do
|
349
|
+
setup do
|
350
|
+
@rs = Recurring::Schedule.new :unit => 'weeks', :weekdays => %w{sat sunday}, :times => '12am', :frequency => 2, :anchor => Time.utc(2001)
|
351
|
+
@danger = Time.utc(2006,12,17,18)
|
352
|
+
end
|
353
|
+
|
354
|
+
specify "should include midnights of every other weekend" do
|
355
|
+
@rs.should_include Time.utc(2006,12,16)
|
356
|
+
@rs.should_include Time.utc(2006,12,10)
|
357
|
+
end
|
358
|
+
|
359
|
+
specify "should not include other midnights" do
|
360
|
+
@rs.should_not_include Time.utc(2006,12,22)
|
361
|
+
@rs.should_not_include Time.utc(2006,12,25)
|
362
|
+
end
|
363
|
+
|
364
|
+
specify "should find the previous time from a dangerous time" do
|
365
|
+
@rs.find_previous(@danger).should == Time.utc(2006,12,16)
|
366
|
+
end
|
367
|
+
|
368
|
+
end
|
369
|
+
|
370
|
+
context "A bi-weekly schedule with weekdays and a noon time" do
|
371
|
+
setup do
|
372
|
+
@rs = Recurring::Schedule.new :unit => 'weeks', :weekdays => %w{sat sunday}, :times => '12pm', :frequency => 2, :anchor => Time.utc(2001)
|
373
|
+
@danger = Time.utc(2006,12,17,18)
|
374
|
+
end
|
375
|
+
|
376
|
+
specify "should include noons of every other weekend" do
|
377
|
+
@rs.should_include Time.utc(2006,12,10,12)
|
378
|
+
@rs.should_include Time.utc(2006,12,16,12)
|
379
|
+
end
|
380
|
+
|
381
|
+
specify "should not include other midnights" do
|
382
|
+
@rs.should_not_include Time.utc(2006,12,22,12)
|
383
|
+
@rs.should_not_include Time.utc(2006,12,25,12)
|
384
|
+
end
|
385
|
+
|
386
|
+
specify "should find the previous time from a dangerous time" do
|
387
|
+
@rs.find_previous(@danger).should == Time.utc(2006,12,16,12)
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
323
391
|
context "A weekly schedule with weekday params" do
|
324
392
|
|
325
393
|
setup do
|
@@ -406,6 +474,11 @@ context "A third-weekly schedule with weekday and times params" do
|
|
406
474
|
@rs.find_next(Time.utc(2006,12,4)).should == Time.utc(2006,12,18,15)
|
407
475
|
@rs.find_next(Time.utc(2006,12,18)).should == Time.utc(2006,12,18,15)
|
408
476
|
end
|
477
|
+
|
478
|
+
specify "should find the previous date" do
|
479
|
+
@rs.find_previous(Time.utc(2006,12,4)).should == Time.utc(2006,12,2,15)
|
480
|
+
@rs.find_previous(Time.utc(2006,12,18,20)).should == Time.utc(2006,12,18,15)
|
481
|
+
end
|
409
482
|
|
410
483
|
end
|
411
484
|
|
@@ -574,7 +647,11 @@ context "An hourly schedule with an anchor" do
|
|
574
647
|
|
575
648
|
specify "should not include any times with different sub hour parts" do
|
576
649
|
end
|
577
|
-
|
650
|
+
|
651
|
+
specify "should find in range" do
|
652
|
+
@rs.find_in_range(Time.utc(2006), Time.utc(2007)).length.should == 24*365
|
653
|
+
end
|
654
|
+
|
578
655
|
end
|
579
656
|
|
580
657
|
context "An bi-hourly schedule with time params" do
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: recurring
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.3.
|
7
|
-
date: 2006-12-
|
6
|
+
version: 0.3.10
|
7
|
+
date: 2006-12-18 00:00:00 -08:00
|
8
8
|
summary: A scheduling library for recurring events
|
9
9
|
require_paths:
|
10
10
|
- lib
|