Class: Recurring::Schedule

Inherits:
Object
  • Object
show all
Defined in:
lib/schedule.rb

Overview

Initialize a Schedule object with the proper options to calculate occurances in that schedule. Schedule#new take a hash of options :unit, :frequency, :anchor, :weeks, :monthdays, :weekdays, :times

Yearly

Every two years from an anchor time

Recurring::Schedule.new :unit => 'years', :frequency => 2, :anchor => Time.utc(2006,4,15,10,30)

Every year in February and May on the 1st and 15th

Recurring::Schedule.new :unit => 'years', :months => ['feb', 'may'], :monthdays => [1,15]

Every year in February and May on the 1st and 15th

Recurring::Schedule.new :unit => 'years', :months => ['feb', 'may'], :monthdays => [1,15]

Monthly

Every two months from an anchor time

Recurring::Schedule.new :unit => 'months', :frequency => 2, :anchor => Time.utc(2006,4,15,10,30)

The first and fifteenth of every month

Recurring::Schedule.new :unit => 'months', :monthdays => [1,15]

The first and eighteenth of every third month

Recurring::Schedule.new :unit => 'months', :frequency => 3, :anchor => Time.utc(2006,4,15,10,30), :monthdays => [10,18]

The third Monday of every month at 6:30pm

Recurring::Schedule.new :unit => 'months', :weeks => 3, :weekdays => :monday, :times => '6:30pm'

Weekly

Monday, Wednesday, and Friday of every week

Recurring::Schedule.new :unit => 'weeks', :weekdays => %w{monday weds friday}

Every week at the same time on the same day of the week as the anchor (Weds at 5:30pm)

Recurring::Schedule.new :unit => 'weeks', :anchor => Time.utc(2006,12,6,17,30)

Equivalently, Every Wednesday at 5:30

Recurring::Schedule.new :unit => 'weeks', :weekdays => 'weds', :times => '5:30pm'

Daily

Everyday at the time of the anchor

Recurring::Schedule.new :unit => 'days', :anchor => Time.utc(2006,11,1,10,15,22)

Everyday at 7am and 5:45:20pm

Recurring::Schedule.new :unit => 'days', :times => '7am 5:45:20pm'

Hourly

Every hour at 15 minutes, 30 minutes, and 45 minutes and 30 seconds

Recurring::Schedule.new :unit => 'hours', :times => '0:15 4:30 0:45:30'

Offset every 2 hours from the anchor

Recurring::Schedule.new :unit => 'hours', :anchor => Time.utc(2001,5,15,11,17)

Minutely

Every five minutes offset from the anchor

Recurring::Schedule.new :unit => 'minutes', :frequency => 5, :anchor => Time.utc(2006,9,1,10,30)

Every minute at second 15

Recurring::Schedule.new :unit => 'minutes', :times => '0:0:15'

See the specs using “rake spec” for even more examples.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ Schedule

Options hash has keys :unit, :frequency, :anchor, :weeks, :monthdays, :weekdays, :times

  • valid values for :unit are years, months, weeks, days, hours, minutes

  • :frequency defaults to 1

  • :anchor is required if the frequency is other than one

  • :weeks alongside :weekdays is used to specify the nth instance of a weekday in a month.

  • :weekdays takes an array of strings like %w{monday weds friday}

  • :monthdays takes an array of days of the month, eg. [1,7,15]

  • :times takes a string with a simple format. "4pm 5:15pm 6:45:30pm"

Raises:

  • (ArgumentError)


63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/schedule.rb', line 63

def initialize options
  raise ArgumentError, 'specify a valid unit' unless options[:unit] &&
    %w{years months weeks days hours minutes}.include?(options[:unit])
  raise ArgumentError, 'frequency > 1 requires an anchor Time' if options[:frequency] && options[:frequency] != 1 && !options[:anchor]
  @unit = options[:unit].to_sym
  raise ArgumentError, 'weekdays are required with the weeks param, if there are times params' if @unit == :weeks && 
	options[:times] && 
	!options[:weekdays]
  @frequency = options[:frequency] || 1
  @anchor = options[:anchor]
  @times = parse_times options[:times]
  if options[:months]
  	@month_args = Array(options[:months]).collect{|d|d.to_s.downcase.to_sym}
  	raise ArgumentError, 'provide valid months' unless @month_args.all?{|m|ordinal_month(m)}
  	@months = @month_args.collect{|m|ordinal_month(m)}
  end
  
  @weeks = Array(options[:weeks]).collect{|n|n.to_i} if options[:weeks]
  if options[:weekdays]
  	@weekdays_args = Array(options[:weekdays]).collect{|d|d.to_s.downcase.to_sym}
  	raise ArgumentError, 'provide valid weekdays' unless @weekdays_args.all?{|w|ordinal_weekday(w)}
    @weekdays = @weekdays_args.collect{|w|ordinal_weekday(w)}
  end
  @monthdays = Array(options[:monthdays]).collect{|n|n.to_i} if options[:monthdays]
  
 
  @anchor_multiple = options[:times].nil? && options[:weeks].nil? && options[:weekdays].nil? && options[:monthdays].nil?
end

Instance Attribute Details

#anchorObject (readonly)

Returns the value of attribute anchor.



53
54
55
# File 'lib/schedule.rb', line 53

def anchor
  @anchor
end

#frequencyObject (readonly)

Returns the value of attribute frequency.



53
54
55
# File 'lib/schedule.rb', line 53

def frequency
  @frequency
end

#monthdaysObject (readonly)

Returns the value of attribute monthdays.



53
54
55
# File 'lib/schedule.rb', line 53

def monthdays
  @monthdays
end

#monthsObject (readonly)

Returns the value of attribute months.



53
54
55
# File 'lib/schedule.rb', line 53

def months
  @months
end

#timesObject (readonly)

Returns the value of attribute times.



53
54
55
# File 'lib/schedule.rb', line 53

def times
  @times
end

#unitObject (readonly)

Returns the value of attribute unit.



53
54
55
# File 'lib/schedule.rb', line 53

def unit
  @unit
end

#weekdaysObject (readonly)

Returns the value of attribute weekdays.



53
54
55
# File 'lib/schedule.rb', line 53

def weekdays
  @weekdays
end

#weeksObject (readonly)

Returns the value of attribute weeks.



53
54
55
# File 'lib/schedule.rb', line 53

def weeks
  @weeks
end

Instance Method Details

#==(other) ⇒ Object

Two Schedules are equal if they have the same attributes.



172
173
174
175
176
177
# File 'lib/schedule.rb', line 172

def == other
  return false unless self.class == other.class
  [:unit, :frequency, :anchor, :weeks, :monthdays, :weekdays, :times].all? do |attribute|
    self.send(attribute) == other.send(attribute)
  end
end

#find_in_range(*args) ⇒ Object

Takes a range which responds to first and last, returning Time objects. The arguments need only to be duck-type compatible with Time#year, #month, #day, #hour, #min, #sec, #wday etc.

rs.find_in_range(Time.now, Time.now+24*60*60)

or

range = (Time.now..Time.now+24*60*60)

rs.find_in_range(range)



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/schedule.rb', line 146

def find_in_range *args
  if args[0].respond_to?(:first) && args[0].respond_to?(:last)
	t_start = args[0].first
	t_end = args[0].last
  else
	t_start = args[0]
	t_end = args[1]
  end
  opts = args.last if args.last.respond_to?(:keys)
  if opts
	limit = opts[:limit]
  end
  result = []
  count = 1
  loop do
    rnext = find_next t_start
    break if count > limit if limit
	break if rnext > t_end
    result << rnext
    t_start = rnext + 1
	count += 1
  end
  result
end

#find_next(date) ⇒ Object

Starts from the argument time, and returns the next included time. Returns the argument if it is included in the schedule.



120
121
122
123
124
125
126
# File 'lib/schedule.rb', line 120

def find_next date
  loop do
  	return date if include?(date)
  	#puts "#{@resolution} : #{date}"
  	date = beginning_of_next @resolution, date
  end
end

#find_previous(date) ⇒ Object

Starts from the argument time, and works backwards until it hits a time that is included



129
130
131
132
133
134
135
# File 'lib/schedule.rb', line 129

def find_previous date
  loop do
  	return date if include?(date)
  	#puts "#{@resolution} : #{date}"
  	date = end_of_previous @resolution, date
  end
end

#include?(date) ⇒ Boolean

Returns true or false depending on whether or not the time is included in the schedule.

Returns:

  • (Boolean)


97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/schedule.rb', line 97

def include? date
  @resolution = nil	
  return true if check_anchor? && date == @anchor 
  return mismatch(:year) unless year_matches?(date) if @unit == :years
  return mismatch(:month) unless month_matches?(date) if [:months, :years].include?(@unit)
  return mismatch(:week) unless week_matches?(date) if [:years, :months, :weeks].include?(@unit)
  if [:years, :months, :weeks, :days].include?(@unit)
    return mismatch(:day) unless day_matches?(date)
   return mismatch(:time) unless time_matches?(date)
  end
  if @unit == :hours
   return mismatch(:hour) unless hour_matches?(date)
   return mismatch(:sub_hour) unless sub_hour_matches?(date)
  end
  if @unit == :minutes
   return mismatch(:minute) unless minute_matches?(date)
   return mismatch(:second) unless second_matches?(date)
  end
  @resolution = nil	
  true
end

#timeout!(time) ⇒ Object



92
93
94
# File 'lib/schedule.rb', line 92

def timeout! time
  @timeout = time
end