Class: LucidWorks::Datasource::Schedule
- Defined in:
- lib/lucid_works/datasource/schedule.rb
Overview
Datasource::Schedule supplies numerous convenience methods to make it easy and clean to display and set schedules in simple formats
The simple formats supported are:
hourly at 15 minutes past the hour # => {:frequency => 'hourly', :start => {:minutes => 15}}
daily at 3:15 # => {:frequency => 'daily', :start => {:hours => 3, :minutes => 15}}
weekly at 3:15 on Tuesday # => {:frequency => 'weekly', :start => {:days => 1, :hours => 3, :minutes => 15}}
Notes:
day of week is specified as the # of days from Monday b/c Rails day of week helpers are monday-based
:start hash keys are pluralized b/c we feed them direcly to Time.advance, e.g. Time.now.advance(:days => 3)
Constant Summary
Constants included from Utils::BoolConverter
Utils::BoolConverter::FALSE_VALUES, Utils::BoolConverter::TRUE_VALUES
Instance Attribute Summary
Attributes inherited from Base
#attributes, #id, #parent, #persisted, #raw_response, #response_data
Instance Method Summary collapse
-
#custom? ⇒ Boolean
convenience method for detecting whether schedule can be represented in simple format or should be described as custom (meaning it is beyond the capabilities of the convenience methods).
-
#day_of_week ⇒ Object
convenince method for setting the current value in a view selector.
-
#frequency ⇒ Object
returns hourly, daily, weekly based on period returns custom if it doesn’t fit a supported interval.
-
#frequency=(frequency) ⇒ Object
accepts hourly, daily, weekly, and sets period to respective # of seconds.
-
#hour ⇒ Object
convenince method for setting the current value in a view selector.
-
#min ⇒ Object
convenince method for setting the current value in a view selector.
-
#next_start ⇒ Object
predict when action will occur next if active at that time.
-
#schedule=(all_attributes) ⇒ Object
phantom attribute for compiling real start time and frequency from appropriate form data Allows the user to specify a schedule simply with repeat interval (hourly, daily, weekly) and time within the interval to run (e.g 5 past, or Tuesdays at 2:15).
- #start_is_more_than_one_period_in_the_future? ⇒ Boolean
-
#ui_appropriate_defaults! ⇒ Object
convenience method for setting defaults in a UI that make sense for a user.
Methods inherited from Base
all, collection_url, #collection_url, create, #destroy, extract_parent_from_options, find, first, human_attribute_value, #human_attribute_value, #initialize, #inspect, last, member_url, #member_url, #persisted?, #read_attribute_for_validation, #save, schema, singleton_name, to_select, #update_attributes
Methods included from SimpleNaming
Methods included from Utils::BoolConverter
Constructor Details
This class inherits a constructor from LucidWorks::Base
Instance Method Details
#custom? ⇒ Boolean
convenience method for detecting whether schedule can be represented in simple format or should be described as custom (meaning it is beyond the capabilities of the convenience methods)
167 168 169 170 171 172 |
# File 'lib/lucid_works/datasource/schedule.rb', line 167 def custom? return true if self.frequency == 'custom' return false unless self.start_time return true if self.start_is_more_than_one_period_in_the_future? return false end |
#day_of_week ⇒ Object
convenince method for setting the current value in a view selector
152 153 154 155 |
# File 'lib/lucid_works/datasource/schedule.rb', line 152 def day_of_week # subract 1 because '%u' returns 1-7, and this is working with zero-indexed ruby arrays self.start_time.localtime.strftime('%u').to_i - 1 rescue nil end |
#frequency ⇒ Object
returns hourly, daily, weekly based on period returns custom if it doesn’t fit a supported interval
32 33 34 35 36 37 38 39 40 41 |
# File 'lib/lucid_works/datasource/schedule.rb', line 32 def frequency case period when 1.minute.seconds..59.minutes.seconds then 'every' when 1.weeks.seconds then 'weekly' when 1.days.seconds then 'daily' when 1.hours.seconds then 'hourly' when 0 then nil else 'custom' end end |
#frequency=(frequency) ⇒ Object
accepts hourly, daily, weekly, and sets period to respective # of seconds
46 47 48 49 50 51 52 53 54 55 |
# File 'lib/lucid_works/datasource/schedule.rb', line 46 def frequency=(frequency) self.period = case frequency when 'every' then period when 'hourly' then 1.hours.seconds.to_i when 'daily' then 1.days.seconds.to_i when 'weekly' then 1.weeks.seconds.to_i when 'custom' then period # don't change anything else raise "unknown frequency" end end |
#hour ⇒ Object
convenince method for setting the current value in a view selector
138 139 140 |
# File 'lib/lucid_works/datasource/schedule.rb', line 138 def hour self.start_time.localtime.hour rescue nil end |
#min ⇒ Object
convenince method for setting the current value in a view selector
145 146 147 |
# File 'lib/lucid_works/datasource/schedule.rb', line 145 def min self.start_time.localtime.min rescue nil end |
#next_start ⇒ Object
predict when action will occur next if active at that time
60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/lucid_works/datasource/schedule.rb', line 60 def next_start return start_time if (now = Time.now) <= start_time time_since_start = now - start_time last_interval_num = (time_since_start / period).to_i next_interval_num = if (time_since_start % period) == 0 # this is sort of a stupid condition b/c time precision is millisecond or less # for human purposes we wouldn't care if the result were as though the call # happened a millisecond later. But whatever. last_interval_num # the next interval *is* the last interval if it is exactly now else last_interval_num + 1 end start_time + period * next_interval_num end |
#schedule=(all_attributes) ⇒ Object
phantom attribute for compiling real start time and frequency from appropriate form data Allows the user to specify a schedule simply with repeat interval (hourly, daily, weekly) and time within the interval to run (e.g 5 past, or Tuesdays at 2:15)
We have to figure out when the actual start time will be because we are not asking the user for this. It needs to be:
* at the requested time relative to the interval chosen
* as soon as possible
* in the future
This is obvious to humans, but when computing it, you run into the following problem. It happens with all interval sizes, but for the sake of example, we’ll use weekly:
Problem 1) If today is Thursday, and the user asks for “weekly on Wednesdays,” Wednesday has already happened this week. We have to make sure we pick the nearest wednesday that is in the future
Problem 2) If today is Tuesday, and the user asks for “weekly on Wednesdays,”, the simple solution to problem 1 (start next week instead of this week) causes you to skip this Tuesday, even though it is valid and is what the user would expect
The algorith to solve both problems at once is this:
* From Time.now, back up to the beginning of the interval even if it is in the past.
* Fast forward to the requested siimple start time
* If you are still in the past, advance by one interval
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/lucid_works/datasource/schedule.rb', line 102 def schedule=(all_attributes) # convert to format accepted by Time.advance if all_attributes['start'] all_attributes['start']. all_attributes['start'].each{|k,v| all_attributes['start'][k]=v.to_i} end self.active = all_attributes['active'] if all_attributes.keys.include?('active') now = Time.now self.frequency = all_attributes['frequency'] self.start_time = case all_attributes['frequency'] when 'every' self.period = all_attributes['period'].to_i now.ceil(period) when 'weekly' start = now.beginning_of_week.advance(all_attributes['start']) start < now ? start.advance(:weeks => 1) : start when 'daily' start = now.beginning_of_day.advance(all_attributes['start']) start < now ? start.advance(:days => 1) : start when 'hourly' start = now.change(:min => 0).advance(all_attributes['start']) start < now ? start.advance(:hours => 1) : start when 'custom' # don't change this schedule's start_time else puts "*** frequency: <#{all_attributes[:frequency]}>" raise "unexpected frequency encountered" end end |
#start_is_more_than_one_period_in_the_future? ⇒ Boolean
157 158 159 160 161 |
# File 'lib/lucid_works/datasource/schedule.rb', line 157 def start_is_more_than_one_period_in_the_future? # This works fine with start times that are multiple periods in the past # because that gives a negative difference, and period is always >= 0 (self.start_time - Time.now) > self.period end |
#ui_appropriate_defaults! ⇒ Object
convenience method for setting defaults in a UI that make sense for a user
177 178 179 180 181 |
# File 'lib/lucid_works/datasource/schedule.rb', line 177 def ui_appropriate_defaults! if self.start_time.blank? || self.period == 0 self.active = true end end |