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 CHANGED
@@ -1,3 +1,7 @@
1
+ == 0.3.5 / 2006-12-14
2
+
3
+ * documentation / hoe
4
+
1
5
  == 0.3.2 / 2006-12-13
2
6
 
3
7
  * initialization bugfixes
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
- # Rake::RDocTask.new(:docs) do |rd|
56
- # rd.main = "README.txt"
57
- # rd.options << '-d' if RUBY_PLATFORM !~ /win32/ and `which dot` =~ /\/dot/
58
- # rd.rdoc_dir = 'doc'
59
- # files = ["History.txt", "README.txt", "Rakefile", "lib/recurring.rb", "spec/recurring_spec.rb"]
60
- # rd.rdoc_files.push(*files)
61
- #
62
- # title = "#{specification.name}-#{specification.version} Documentation"
63
- # #title = "#{rubyforge_name}'s " + title if rubyforge_name != title
64
- #
65
- # rd.options << "-t #{title}"
66
- # end
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.2'
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
- # * options is a hash with keys <tt>:unit, :frequency, :anchor, :weeks, :monthdays, :weekdays, :times</tt>
49
- # * valid units are <tt>years, months, weeks, days, hours, and minutes</tt>
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
- @months = Array(options[:months]).collect{|d|d.to_s.downcase.to_sym} if options[:months]
68
- @weeks = Array(options[:weeks]) if options[:weeks]
69
- @weekdays = Array(options[:weekdays]).collect{|d|d.to_s.downcase.to_sym} if options[:weekdays]
70
- @monthdays = Array(options[:monthdays]) if options[:monthdays]
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
- if @unit == :weeks
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.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
- lookup.select{|k,v| v.include?(symbol)}.first.first
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#==
@@ -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 days as integers" do
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.2
7
- date: 2006-12-14 00:00:00 -08:00
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