Class: Availability::AbstractAvailability Abstract

Inherits:
InstanceVariableComparability 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

Methods inherited from InstanceVariableComparability

#<=>

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
65
# File 'lib/availability/abstract_availability.rb', line 53

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

#end_timeObject



143
144
145
# File 'lib/availability/abstract_availability.rb', line 143

def end_time
  start_time + duration
end

#includes?(time) ⇒ Boolean

Whether or not the given time is covered by the receiver

Parameters:

  • time (Time)

    the Time to test for coverage

Returns:

  • (Boolean)

    true or false



74
75
76
77
78
79
# File 'lib/availability/abstract_availability.rb', line 74

def includes?(time)
  next_occurrence = next_occurrence(time) || last_occurrence
  residue_for(time) == @residue \
    && !next_occurrence.nil? \
    && time_overlaps?(time, next_occurrence, next_occurrence + 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



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

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



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

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



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

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



131
132
133
134
135
136
137
# File 'lib/availability/abstract_availability.rb', line 131

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)



108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/availability/abstract_availability.rb', line 108

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 (exx = exclusions.detect {|rule| rule.violated_by? time})
    if stops_by && time > stops_by
      nil
    else
      next_occurrence(move_by time, 1)
    end
  else
    time
  end
end

#residue_for(time) ⇒ Object



198
199
200
# File 'lib/availability/abstract_availability.rb', line 198

def residue_for(time)
  raise 'subclass responsibility'
end

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

Returns:

  • (Boolean)


179
180
181
182
183
184
# File 'lib/availability/abstract_availability.rb', line 179

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