class Schedulability::Schedule

A schedule object representing one or more abstract ranges of times.

Attributes

negative_periods[R]

The periods that express which times are not in the schedule

positive_periods[R]

The periods that express which times are in the schedule

Public Class Methods

new( positive_periods=[], negative_periods=[] ) click to toggle source

Create a new Schedule using the specified periods.

# File lib/schedulability/schedule.rb, line 28
def initialize( positive_periods=[], negative_periods=[] )
        positive_periods ||= []
        negative_periods ||= []

        @positive_periods = positive_periods.flatten.uniq
        @positive_periods.freeze
        @negative_periods = negative_periods.flatten.uniq
        @negative_periods.freeze
end
parse( expression ) click to toggle source

Parse one or more periods from the specified expression and return a Schedule created with them.

# File lib/schedulability/schedule.rb, line 21
def self::parse( expression )
        positive, negative = Schedulability::Parser.extract_periods( expression )
        return new( positive, negative )
end

Public Instance Methods

&( other_schedule ) click to toggle source

Return a new Schedulability::Schedule object that is the intersection of the receiver and other_schedule.

# File lib/schedulability/schedule.rb, line 127
def &( other_schedule )
        positive = intersect_periods( self.positive_periods, other_schedule.positive_periods )
        negative = self.negative_periods + other_schedule.negative_periods

        return self.class.new( positive, negative )
end
+( other_schedule )
Alias for: |
==( other_schedule ) click to toggle source

Returns true if the time periods for other_schedule are the same as those for the receiver.

# File lib/schedulability/schedule.rb, line 105
def ==( other_schedule )
        other_schedule.is_a?( self.class ) &&
                self.positive_periods.all? {|period| other_schedule.positive_periods.include?(period) } &&
                other_schedule.positive_periods.all? {|period| self.positive_periods.include?(period) } &&
                self.negative_periods.all? {|period| other_schedule.negative_periods.include?(period) } &&
                other_schedule.negative_periods.all? {|period| self.negative_periods.include?(period) }
end
empty?() click to toggle source

Returns true if the schedule doesn't have any time periods.

# File lib/schedulability/schedule.rb, line 47
def empty?
        return self.positive_periods.empty? && self.negative_periods.empty?
end
exclusive?( other_schedule ) click to toggle source

Returns true if the schedule does not have any times which overlap those of other_schedule.

# File lib/schedulability/schedule.rb, line 96
def exclusive?( other_schedule )
        return ( self & other_schedule ).empty?
end
Also aliased as: exclusive_of?, is_exclusive_of?
exclusive_of?( other_schedule )
Alias for: exclusive?
include?( time ) click to toggle source

Returns true if the specified time is in the schedule.

# File lib/schedulability/schedule.rb, line 59
def include?( time )
        time_obj = if time.respond_to?( :to_time )
                        time.to_time
                else
                        time_obj = Time.parse( time.to_s )
                        time_obj
                end

        return ! self.negative_periods_include?( time_obj ) &&
                self.positive_periods_include?( time_obj )
end
is_exclusive_of?( other_schedule )
Alias for: exclusive?
negative_periods_include?( time ) click to toggle source

Returns true if any of the schedule's negative periods include the specified time.

# File lib/schedulability/schedule.rb, line 82
def negative_periods_include?( time )
        return find_matching_period_for( time, self.negative_periods )
end
now?() click to toggle source

Returns true if the current time is within one of the Schedule's periods.

# File lib/schedulability/schedule.rb, line 53
def now?
        return self.include?( Time.now )
end
overlaps?( other_schedule ) click to toggle source

Returns true if the schedule has any times which overlap those of other_schedule.

# File lib/schedulability/schedule.rb, line 88
def overlaps?( other_schedule )
        return ! self.exclusive?( other_schedule )
end
Also aliased as: overlaps_with?
overlaps_with?( other_schedule )
Alias for: overlaps?
positive_periods_include?( time ) click to toggle source

Returns true if any of the schedule's positive periods include the specified time.

# File lib/schedulability/schedule.rb, line 74
def positive_periods_include?( time )
        return self.positive_periods.empty? ||
                find_matching_period_for( time, self.positive_periods )
end
to_s() click to toggle source

Return a string from previously parsed Schedule period objects.

# File lib/schedulability/schedule.rb, line 143
def to_s
        str = Schedulability::Parser.stringify( self.positive_periods )
        unless self.negative_periods.empty?
                str << ", not %s" % [ Schedulability::Parser.stringify(self.negative_periods) ]
        end

        return str
end
|( other_schedule ) click to toggle source

Return a new Schedulability::Schedule object that is the union of the receiver and other_schedule.

# File lib/schedulability/schedule.rb, line 116
def |( other_schedule )
        positive = self.positive_periods + other_schedule.positive_periods
        negative = intersect_periods( self.negative_periods, other_schedule.negative_periods )

        return self.class.new( positive, negative )
end
Also aliased as: +

Private Instance Methods

explode( periods ) click to toggle source

Return the specified periods exploded into integer arrays instead of Ranges.

# File lib/schedulability/schedule.rb, line 198
def explode( periods )
        return periods.map do |per|
                per.each_with_object({}) do |(scale,ranges), hash|
                        hash[ scale ] = ranges.flat_map( &:to_a )
                end
        end
end
find_matching_period_for( time, periods ) click to toggle source

Returns true if any of the specified periods contains the specified time.

# File lib/schedulability/schedule.rb, line 158
def find_matching_period_for( time, periods )
        periods.any? do |period|
                period.all? do |scale, ranges|
                        val = value_for_scale( time, scale )
                        ranges.any? {|rng| rng.cover?(val) }
                end
        end
end
intersect_periods( left, right ) click to toggle source

Return the intelligent merge of the left and right period hashes, only retaining values that exist on both sides.

# File lib/schedulability/schedule.rb, line 209
def intersect_periods( left, right )
        new_periods = []
        explode( left ).product( explode(right) ) do |p1, p2|
                new_period = {}
                common_scales = p1.keys & p2.keys

                # Keys exist on both sides, diff+merge identical values
                common_scales.each do |scale|
                        vals = p1[ scale ] & p2[ scale ]
                        new_period[ scale ] = Schedulability::Parser.coalesce_ranges( vals, scale )
                end
                next if new_period.values.any?( &:empty? )

                # Keys exist only on one side, sync between sides because
                # the other side is implicitly infinite.
                (p1.keys - common_scales).each do |scale|
                        new_period[ scale ] = Schedulability::Parser.coalesce_ranges( p1[scale], scale )
                end
                (p2.keys - common_scales).each do |scale|
                        new_period[ scale ] = Schedulability::Parser.coalesce_ranges( p2[scale], scale )
                end

                new_periods << new_period
        end

        return new_periods
end
value_for_scale( time, scale ) click to toggle source

Return the appropriate numeric value for the specified scale from the given time.

# File lib/schedulability/schedule.rb, line 170
def value_for_scale( time, scale )
        case scale
        when :mo
                return time.mon
        when :md
                return time.day
        when :wd
                return time.wday
        when :hr
                return time.hour
        when :min
                return time.min
        when :sec
                return time.sec
        when :yd
                return time.yday
        when :wk
                return ( time.day / 7.0 ).ceil
        when :yr
                return time.year
        else
                # If this happens, it's likely a bug in the parser.
                raise ScriptError, "unknown scale %p" % [ scale ]
        end
end