Class: Availability::AbstractAvailability

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

Direct Known Subclasses

Daily, Monthly, Once, Weekly, Yearly

Instance Attribute Summary 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, frequency: :daily, stops_by: nil, duration:, interval:, start_time:) ⇒ AbstractAvailability

Required arguments:

interval: an integer that is the interval of occurrences per frequency
start_time: a Time, Date, or DateTime that indicates when the availability begins
duration: an integer indicating how long the availability lasts in seconds

Optional arguements:

frequency: a symbol, one of [:once, :daily, :monthly, :yearly]; defaults to :daily
stops_by: specific date by which the availability ends

Raises:

  • (ArgumentError)


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

def initialize(capacity: Float::INFINITY, exclusions: nil, frequency: :daily, 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
  @frequency = frequency
  @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.



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

def capacity
  @capacity
end

#durationObject

Returns the value of attribute duration.



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

def duration
  @duration
end

#exclusionsObject

Returns the value of attribute exclusions.



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

def exclusions
  @exclusions
end

#frequencyObject

Returns the value of attribute frequency.



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

def frequency
  @frequency
end

#intervalObject

Returns the value of attribute interval.



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

def interval
  @interval
end

#residueObject (readonly)

Returns the value of attribute residue.



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

def residue
  @residue
end

#start_timeObject

Returns the value of attribute start_time.



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

def start_time
  @start_time
end

#stops_byObject

Returns the value of attribute stops_by.



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

def stops_by
  @stops_by
end

Instance Method Details

#beginningObject



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

def beginning
  self.class.beginning
end

#corresponds_to?(availability) ⇒ Boolean

Returns:

  • (Boolean)


45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/availability/abstract_availability.rb', line 45

def corresponds_to?(availability)
  return 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



58
59
60
# File 'lib/availability/abstract_availability.rb', line 58

def end_time
  start_time + duration
end

#initialize_copy(orig) ⇒ Object

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



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

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

#interval_difference(first, second) ⇒ Object



87
88
89
# File 'lib/availability/abstract_availability.rb', line 87

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

#last_occurrenceObject



91
92
93
94
95
96
97
98
99
# File 'lib/availability/abstract_availability.rb', line 91

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



101
102
103
# File 'lib/availability/abstract_availability.rb', line 101

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

#next_n_occurrences(n, from_date) ⇒ Object

Returns an array of occurrences for n <= 1000, otherwise it returns a lazy enumerator

n: Fixnum, how many occurrences to get from_date: a Date, Time, or DateTime from which to start calculating



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

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) ⇒ Object



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

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

Returns:

  • (Boolean)


134
135
136
# File 'lib/availability/abstract_availability.rb', line 134

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

#residue_for(time) ⇒ Object



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

def residue_for(time)
  raise 'subclass responsibility'
end

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

Returns:

  • (Boolean)


148
149
150
151
152
153
# File 'lib/availability/abstract_availability.rb', line 148

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