Class: Availability::AbstractAvailability Abstract

Inherits:
Object
  • Object
show all
Extended by:
ClassMethods, FactoryMethods
Defined in:
lib/availability/abstract_availability.rb,
lib/availability.rb

Overview

This class is abstract.

see concrete classes: Once, Daily, Weekly, Monthly and Yearly

Direct Known Subclasses

Daily, Monthly, Once, Weekly, Yearly

Instance Attribute Summary collapse

Testing collapse

Occurrences collapse

Accessors collapse

Helpers collapse

Subclass Responsibilities collapse

Instance Method Summary collapse

Methods included from FactoryMethods

create, once

Methods included from ClassMethods

availability?, default_args, subclass_for

Constructor Details

#initialize(capacity: Float::INFINITY, exclusions: nil, stops_by: nil, duration:, interval:, start_time:) ⇒ AbstractAvailability

Required arguments: Optional arguements:

Parameters:

  • interval (Fixnum)

    an integer that is the interval of occurrences per frequency

  • start_time (Time)

    a Time, Date, or DateTime that indicates when the availability begins

  • duration (Fixnum)

    an integer indicating how long the availability lasts in seconds

  • stops_by (Time) (defaults to: nil)

    specific Date, Time, or DateTime by which the availability ends

Raises:

  • (ArgumentError)


18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/availability/abstract_availability.rb', line 18

def initialize(capacity: Float::INFINITY, exclusions: nil, stops_by: nil, duration: , interval: , start_time: )
  raise ArgumentError, "start_time is required" if start_time.nil?
  raise ArgumentError, "duration is required" if duration.nil?
  raise ArgumentError, "interval is required" if interval.nil?
  @capacity = capacity
  @duration = duration
  @interval = interval
  @start_time = start_time.to_time
  @stops_by = stops_by
  self.exclusions = exclusions
  compute_residue
end

Instance Attribute Details

#capacityObject

Returns the value of attribute capacity.



6
7
8
# File 'lib/availability/abstract_availability.rb', line 6

def capacity
  @capacity
end

#durationObject

Returns the value of attribute duration.



6
7
8
# File 'lib/availability/abstract_availability.rb', line 6

def duration
  @duration
end

#exclusionsObject

Returns the value of attribute exclusions.



7
8
9
# File 'lib/availability/abstract_availability.rb', line 7

def exclusions
  @exclusions
end

#intervalObject

Returns the value of attribute interval.



7
8
9
# File 'lib/availability/abstract_availability.rb', line 7

def interval
  @interval
end

#residueObject (readonly)

Returns the value of attribute residue.



7
8
9
# File 'lib/availability/abstract_availability.rb', line 7

def residue
  @residue
end

#start_timeObject

Returns the value of attribute start_time.



7
8
9
# File 'lib/availability/abstract_availability.rb', line 7

def start_time
  @start_time
end

#stops_byObject

Returns the value of attribute stops_by.



6
7
8
# File 'lib/availability/abstract_availability.rb', line 6

def stops_by
  @stops_by
end

Instance Method Details

#beginningObject



40
41
42
# File 'lib/availability/abstract_availability.rb', line 40

def beginning
  self.class.beginning
end

#corresponds_to?(availability) ⇒ Boolean

Whether or not the availability is covered by the receiver

Parameters:

Returns:

  • (Boolean)

    true or false



53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/availability/abstract_availability.rb', line 53

def corresponds_to?(availability)
  return false unless occurs_at?(availability.start_time) && occurs_at?(availability.start_time + availability.duration)
  if !!stops_by
    that_last = availability.last_occurrence
    !that_last.nil? &&
      occurs_at?(that_last) &&
      occurs_at?(that_last + availability.duration) &&
      that_last.to_date <= self.last_occurrence.to_date
  else
    true
  end
end

#end_timeObject



139
140
141
# File 'lib/availability/abstract_availability.rb', line 139

def end_time
  start_time + duration
end

#initialize_copy(orig) ⇒ Object

The copy constructor that Ruby calls when cloning or duping an object.



34
35
36
37
38
# File 'lib/availability/abstract_availability.rb', line 34

def initialize_copy(orig)
  super
  @exclusions = orig.exclusions
  compute_residue
end

#interval_difference(first, second) ⇒ Object



186
187
188
# File 'lib/availability/abstract_availability.rb', line 186

def interval_difference(first, second)
  raise 'subclass responsibility'
end

#last_occurrenceTime

Calculates the last occurrence of an availability

Returns:

  • (Time)

    the last occurrence of the receiver, or nil if stops_by is not set



86
87
88
89
90
91
92
93
94
# File 'lib/availability/abstract_availability.rb', line 86

def last_occurrence
  return nil unless stops_by
  unless @last_occurrence
    next_date = move_by start_time, interval_difference(start_time, stops_by)
    next_date = move_by next_date, -1 * interval while next_date >= stops_by && residue_for(next_date) != residue
    @last_occurrence = next_occurrence next_date
  end
  @last_occurrence
end

#move_by(time, amount) ⇒ Object



190
191
192
# File 'lib/availability/abstract_availability.rb', line 190

def move_by(time, amount)
  raise 'subclass responsibility'
end

#next_n_occurrences(n, from_date) ⇒ Enumerable

Calculates occurrences for n <= 1000; where n > 1000, it returns a lazy enumerator

Parameters:

  • n (Fixnum)

    how many occurrences to get

  • from_date (Date, Time, DateTime)

    time from which to start calculating

Returns:

  • (Enumerable)

    an array of [Time] or lazy enumeration for n > 1000



127
128
129
130
131
132
133
# File 'lib/availability/abstract_availability.rb', line 127

def next_n_occurrences(n, from_date)
  first_next_occurrence = next_occurrence(from_date)
  blk = proc { |i| move_by first_next_occurrence, interval * i }
  range = 0.upto(n - 1)
  range = range.lazy if n > 1000
  range.map &blk
end

#next_occurrence(from_date) ⇒ Time

Calculates a time for the next occurrence on or after the given date or time. If no occurrence exists, nil is returned.

from_date: a Date, Time, or DateTime from which to start calculating

Returns:

  • (Time)

    the next occurrence (or nil)



104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/availability/abstract_availability.rb', line 104

def next_occurrence(from_date)
  residue = @residue - residue_for(from_date)
  date = move_by from_date, residue.modulo(interval)
  time = Time.new(date.year, date.month, date.day, start_time.hour, start_time.min, start_time.sec)
  if exclusions.any? {|rule| rule.violated_by? time}
    if stops_by && time > stops_by
      nil
    else
      next_occurrence(move_by time, 1)
    end
  else
    time
  end
end

#occurs_at?(time) ⇒ Boolean

Whether or not the given time is covered by the receiver

Parameters:

  • time (Time)

    the Date, Time, or DateTime to test for coverage

Returns:

  • (Boolean)

    true or false



73
74
75
# File 'lib/availability/abstract_availability.rb', line 73

def occurs_at?(time)
  residue_for(time) == @residue && time_overlaps?(time, start_time, start_time + duration)
end

#residue_for(time) ⇒ Object



194
195
196
# File 'lib/availability/abstract_availability.rb', line 194

def residue_for(time)
  raise 'subclass responsibility'
end

#time_overlaps?(time, start_time, end_time) ⇒ Boolean

Returns:

  • (Boolean)


175
176
177
178
179
180
# File 'lib/availability/abstract_availability.rb', line 175

def time_overlaps?(time, start_time, end_time)
  that_start = time.seconds_since_midnight.to_i
  this_start = start_time.seconds_since_midnight.to_i
  this_end   = end_time.seconds_since_midnight.to_i
  (this_start..this_end).include?(that_start)
end