Class: ActivePeriod::Period

Inherits:
Range
  • Object
show all
Includes:
Comparable, HasMany::Holidays
Defined in:
lib/active_period/period.rb

Direct Known Subclasses

FreePeriod, StandardPeriod

Instance Method Summary collapse

Methods included from HasMany::Holidays

#holidays

Methods included from Comparable

#<=>, #include?

Methods inherited from Range

#to_period

Constructor Details

#initialize(range, allow_beginless: true, allow_endless: true) ⇒ self

Returns A new instance of ActivePeriod::Period.

Parameters:

  • range (Range)

    A valid range

  • allow_beginless (Boolean) (defaults to: true)

    Is it allow to creat a beginless range

  • allow_endless (Boolean) (defaults to: true)

    Is it allow to creat an endless range

Raises:

  • ArgumentError if the params range is not a Range

  • ArgumentError if the params range is invalid

Author:

  • Lucas Billaudot <billau_l@modulotech.fr>



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/active_period/period.rb', line 15

def initialize(range, allow_beginless: true, allow_endless: true)
  I18n.t(:base_class_is_abstract, scope: %i[active_period period]) if self.class == ActivePeriod::Period

  raise ::ArgumentError, I18n.t(:param_must_be_a_range, scope: %i[active_period period]) unless range.class.ancestors.include?(Range)

  from = time_parse(range.begin, I18n.t(:begin_date_is_invalid, scope: %i[active_period period]))
  raise ::ArgumentError, I18n.t(:begin_date_is_invalid, scope: %i[active_period period]) if !allow_beginless && from.nil?
  from = from.try(:beginning_of_day) || from

  to = time_parse(range.end, I18n.t(:end_date_is_invalid, scope: %i[active_period period]))
  raise ::ArgumentError, I18n.t(:end_date_is_invalid, scope: %i[active_period period]) if !allow_endless && to.nil?
  to = to.try(:end_of_day) || to

  if range.exclude_end? && from && to && from.to_date == to.to_date
    raise ::ArgumentError, I18n.t(:start_is_equal_to_end_excluded, scope: %i[active_period period])
  end

  if from && to && from > to
    raise ::ArgumentError, I18n.t(:start_is_greater_than_end, scope: %i[active_period period])
  end

  super(from, to, range.exclude_end?)
end

Instance Method Details

#&(other) ⇒ ActivePeriod::Period?

Returns Any kind of ActivePeriod::FreePeriod if period overlap, nil otherwise.

Parameters:

Returns:

  • (ActivePeriod::Period, nil)

    Any kind of ActivePeriod::FreePeriod if period overlap, nil otherwise

Raises:

  • ArgumentError if params other is not a ActivePeriod::Period of some kind



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/active_period/period.rb', line 96

def &(other)
  raise ArgumentError, I18n.t(:incomparable_error, scope: %i[active_period comparable]) unless other.class.ancestors.include?(ActivePeriod::Period)

  # self            9------12
  # other  1-----------10
  if self.begin.in?(other) && !calculated_end.in?(other)
    Period.new( Range.new(self.begin, other.to, other.exclude_end?) )
  # self    1-----------10
  # other            9------12
  elsif !self.begin.in?(other) && calculated_end.in?(other)
    Period.new( Range.new(other.begin, to, exclude_end?) )
  # self      5-----8
  # other  1-----------10
  elsif other.include?(self)
    other
  # self   1-----------10
  # other      5-----8
  elsif self.include?(other)
    self
  else
    nil
  end
end

#+(duration) ⇒ Object

Raises:

  • NotImplementedError This method should be implemented in daughter class



67
68
69
# File 'lib/active_period/period.rb', line 67

def +(duration)
  raise NotImplementedError
end

#-(duration) ⇒ Object

Raises:

  • NotImplementedError This method should be implemented in daughter class



62
63
64
# File 'lib/active_period/period.rb', line 62

def -(duration)
  raise NotImplementedError
end

#==(other) ⇒ Boolean

Returns true if period are equals, false otherwise.

Parameters:

  • other (ActivePeriod::Period, ActiveSupport::Duration, Numeric)

    Any kind of ActivePeriod::Period, ActiveSupport::Duration or Numeric (in seconds)

Returns:

  • (Boolean)

    true if period are equals, false otherwise

Raises:

  • ArgumentError if params other is not a ActivePeriod::Period of some kind



74
75
76
77
78
79
80
81
82
83
84
# File 'lib/active_period/period.rb', line 74

def ==(other)
  if other.class.ancestors.include?(ActivePeriod::Period)
    from == other.from && self.calculated_end == other.calculated_end
  elsif other.is_a?(ActiveSupport::Duration)
    super(other)
  elsif other.is_a?(Numeric)
    super(other.seconds)
  else
    raise ArgumentError
  end
end

#===(other) ⇒ Boolean

Returns true if period and class are the same, false otherwise.

Parameters:

Returns:

  • (Boolean)

    true if period and class are the same, false otherwise

Raises:

  • ArgumentError if params other is not a ActivePeriod::Period of some kind



89
90
91
# File 'lib/active_period/period.rb', line 89

def ===(other)
  self == other && self.class == other.class
end

#beginless?Boolean

Returns:

  • (Boolean)


185
186
187
# File 'lib/active_period/period.rb', line 185

def beginless?
  self.begin.nil?
end

#boundless?Boolean

Returns:

  • (Boolean)


189
190
191
# File 'lib/active_period/period.rb', line 189

def boundless?
  beginless? && endless?
end

#calculated_beginObject



173
174
175
176
177
178
179
# File 'lib/active_period/period.rb', line 173

def calculated_begin
  if beginless?
    -Date::Infinity.new
  else
    self.begin
  end
end

#calculated_endDateTime

Returns The real value of end acording to exclude_end.

Returns:

  • (DateTime)

    The real value of end acording to exclude_end

Author:

  • Lucas Billaudot <billau_l@modulotech.fr>



161
162
163
164
165
166
167
168
169
170
171
# File 'lib/active_period/period.rb', line 161

def calculated_end
  if endless?
    Date::Infinity.new
  else
    if exclude_end?
      self.end.prev_day
    else
      self.end
    end
  end
end

#endless?Boolean

Returns:

  • (Boolean)


181
182
183
# File 'lib/active_period/period.rb', line 181

def endless?
  self.end.nil?
end

#i18nObject

Raises:

  • NotImplementedError This method must be implemented in daughter class



155
156
157
# File 'lib/active_period/period.rb', line 155

def i18n
  raise NotImplementedError
end

#infinite?Boolean

Returns:

  • (Boolean)


193
194
195
# File 'lib/active_period/period.rb', line 193

def infinite?
  beginless? || endless?
end

#nextObject Also known as: succ

Raises:

  • NotImplementedError This method cen be implemented in daughter class



46
47
48
# File 'lib/active_period/period.rb', line 46

def next
  raise NotImplementedError
end

#prevObject

Raises:

  • NotImplementedError This method cen be implemented in daughter class



52
53
54
# File 'lib/active_period/period.rb', line 52

def prev
  raise NotImplementedError
end

#strftimeObject

Raises:

  • NotImplementedError This method should be implemented in daughter class



145
146
147
# File 'lib/active_period/period.rb', line 145

def strftime
  raise NotImplementedError
end

#to_iObject

Raises:

  • NotImplementedError This method should be implemented in daughter class



57
58
59
# File 'lib/active_period/period.rb', line 57

def to_i
  raise NotImplementedError
end

#to_sObject

Raises:

  • NotImplementedError This method should be implemented in daughter class



150
151
152
# File 'lib/active_period/period.rb', line 150

def to_s
  raise NotImplementedError
end

#|(other) ⇒ ActivePeriod::Period?

Returns Any kind of ActivePeriod::FreePeriod if period overlap, nil otherwise.

Parameters:

Returns:

  • (ActivePeriod::Period, nil)

    Any kind of ActivePeriod::FreePeriod if period overlap, nil otherwise

Raises:

  • ArgumentError if params other is not a ActivePeriod::Period of some kind



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/active_period/period.rb', line 123

def |(other)
  raise ArgumentError, I18n.t(:incomparable_error, scope: %i[active_period comparable]) unless other.class.ancestors.include?(ActivePeriod::Period)

  # overlapping or tail to head
  if self.begin.in?(other) || self.calculated_end.in?(other) || (
      ((self.calculated_end+1.day).beginning_of_day == other.from) ^
      ((other.calculated_end+1.day).beginning_of_day == self.from)
    )
    Period.new(
      Range.new(
        [self.begin, other.begin].min,
        [self.to, other.to].max,
        self.calculated_end > other.calculated_end ? self.exclude_end? : other.exclude_end?
      )
    )
  # no overlapping
  else
    nil
  end
end