Class: EDTF::Interval
- Inherits:
-
Object
- Object
- EDTF::Interval
- Extended by:
- Forwardable
- Includes:
- Comparable, Enumerable
- Defined in:
- lib/edtf/interval.rb
Overview
An interval behaves like a regular Range but is dedicated to EDTF dates. Most importantly, intervals use the date’s precision when generating the set of contained values and for membership tests. All tests are implemented without iteration and should therefore be considerably faster than if you were to use a regular Range.
For example, the interval “2003/2006” covers the years 2003, 2004, 2005 and 2006. Converting the interval to an array would result in a an array containing exactly four dates with year precision. This is also reflected in membership tests.
Date.edtf('2003/2006').length -> 4
Date.edtf('2003/2006').include? Date.edtf('2004') -> true
Date.edtf('2003/2006').include? Date.edtf('2004-03') -> false
Date.edtf('2003/2006').cover? Date.edtf('2004-03') -> true
Instance Attribute Summary collapse
-
#from ⇒ Object
Returns the value of attribute from.
-
#to ⇒ Object
Returns the value of attribute to.
Instance Method Summary collapse
- #<=>(other) ⇒ Object
- #===(other) ⇒ Object
- #begin ⇒ Object
-
#cover?(other) ⇒ Boolean
Returns true if other is an element of the Interval, false otherwise.
- #each(&block) ⇒ Object
-
#edtf ⇒ Object
(also: #to_s)
Returns the Interval as an EDTF string.
- #end ⇒ Object
-
#exclude_end? ⇒ Boolean
This method always returns false for Range compatibility.
-
#first(n = 1) ⇒ Object
call-seq: interval.first -> Date or nil interval.first(n) -> Array.
-
#include?(other) ⇒ Boolean
(also: #member?)
Returns true if other is an element of the Interval, false otherwise.
-
#initialize(from = Date.today, to = :open) ⇒ Interval
constructor
A new instance of Interval.
-
#last(n = 1) ⇒ Object
call-seq: interval.last -> Date or nil interval.last(n) -> Array.
-
#max(&block) ⇒ Object
call-seq: interval.max -> Date or nil interval.max { |a,b| block } -> Date or nil.
-
#min(&block) ⇒ Object
call-seq: interval.min -> Date or nil interval.min { |a,b| block } -> Date or nil.
-
#mixed_precision? ⇒ Boolean
Returns true if the precisions of start and end date are not the same.
-
#precision ⇒ Object
Returns the intervals precision.
-
#step(by = 1) ⇒ Object
call-seq: interval.step(by=1) { |date| block } -> self interval.step(by=1) -> Enumerator.
-
#to_range ⇒ Object
Returns the Interval as a Range.
- #unknown? ⇒ Boolean
- #unknown_start! ⇒ Object
- #unknown_start? ⇒ Boolean
Constructor Details
Instance Attribute Details
#from ⇒ Object
Returns the value of attribute from.
32 33 34 |
# File 'lib/edtf/interval.rb', line 32 def from @from end |
#to ⇒ Object
Returns the value of attribute to.
32 33 34 |
# File 'lib/edtf/interval.rb', line 32 def to @to end |
Instance Method Details
#<=>(other) ⇒ Object
268 269 270 271 272 273 274 275 276 277 |
# File 'lib/edtf/interval.rb', line 268 def <=>(other) case other when Interval, Season, Epoch [min, max] <=> [other.min, other.max] when Date cover?(other) ? min <=> other : 0 else nil end end |
#===(other) ⇒ Object
279 280 281 282 283 284 285 286 287 288 |
# File 'lib/edtf/interval.rb', line 279 def ===(other) case other when Interval cover?(other.min) && cover?(other.max) when Date cover?(other) else false end end |
#begin ⇒ Object
231 232 233 |
# File 'lib/edtf/interval.rb', line 231 def begin min end |
#cover?(other) ⇒ Boolean
Returns true if other is an element of the Interval, false otherwise. In contrast to #include? and #member? this method does not take into account the date’s precision.
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/edtf/interval.rb', line 163 def cover?(other) return false unless other.is_a?(Date) other = other.day_precision case when unknown_start? max.day_precision! == other when unknown_end? min.day_precision! == other when open_end? min.day_precision! <= other else min.day_precision! <= other && other <= max.day_precision! end end |
#each(&block) ⇒ Object
94 95 96 |
# File 'lib/edtf/interval.rb', line 94 def each(&block) step(1, &block) end |
#edtf ⇒ Object Also known as: to_s
Returns the Interval as an EDTF string.
292 293 294 295 296 297 |
# File 'lib/edtf/interval.rb', line 292 def edtf [ from.send(from.respond_to?(:edtf) ? :edtf : :to_s), to.send(to.respond_to?(:edtf) ? :edtf : :to_s) ] * '/' end |
#end ⇒ Object
264 265 266 |
# File 'lib/edtf/interval.rb', line 264 def end max end |
#exclude_end? ⇒ Boolean
This method always returns false for Range compatibility. EDTF intervals always include the last date.
134 135 136 |
# File 'lib/edtf/interval.rb', line 134 def exclude_end? false end |
#first(n = 1) ⇒ Object
call-seq:
interval.first -> Date or nil
interval.first(n) -> Array
Returns the first date in the interval, or the first n dates.
185 186 187 188 189 190 191 |
# File 'lib/edtf/interval.rb', line 185 def first(n = 1) if n > 1 (ds = Array(min)).empty? ? ds : ds.concat(ds[0].next(n - 1)) else min end end |
#include?(other) ⇒ Boolean Also known as: member?
Returns true if other is an element of the Interval, false otherwise. Comparision is done according to the Interval’s min/max date and precision.
155 156 157 |
# File 'lib/edtf/interval.rb', line 155 def include?(other) cover?(other) && precision == other.precision end |
#last(n = 1) ⇒ Object
call-seq:
interval.last -> Date or nil
interval.last(n) -> Array
Returns the last date in the interval, or the last n dates.
198 199 200 201 202 203 204 |
# File 'lib/edtf/interval.rb', line 198 def last(n = 1) if n > 1 (ds = Array(max)).empty? ? ds : ds.concat(ds[0].prev(n - 1)) else max end end |
#max(&block) ⇒ Object
call-seq:
interval.max -> Date or nil
interval.max { |a,b| block } -> Date or nil
Returns the maximum value in the interval. If a block is given, it is used to compare values (slower). Returns nil if the first date of the interval is larger than the last or if the interval has an unknown or open end.
To calculate the dates, precision is taken into account. Thus, the max Date of “2007/2008” would be 2008-12-31, whilst the max Date of “2007-12/2008-10” would be 2009-10-31.
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
# File 'lib/edtf/interval.rb', line 247 def max(&block) if block_given? to_a.max(&block) else case when open_end?, unknown_end?, !unknown_start? && to < from nil when to.day_precision? to when to.month_precision? to.end_of_month else to.end_of_year end end end |
#min(&block) ⇒ Object
call-seq:
interval.min -> Date or nil
interval.min { |a,b| block } -> Date or nil
Returns the minimum value in the interval. If a block is given, it is used to compare values (slower). Returns nil if the first date of the interval is larger than the last or if the interval has an unknown or open start.
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
# File 'lib/edtf/interval.rb', line 214 def min(&block) if block_given? to_a.min(&block) else case when unknown_start?, !unknown_end? && !open? && to < from nil when from.day_precision? from when from.month_precision? from.beginning_of_month else from.beginning_of_year end end end |
#mixed_precision? ⇒ Boolean
Returns true if the precisions of start and end date are not the same.
90 91 92 |
# File 'lib/edtf/interval.rb', line 90 def mixed_precision? min.precision != max.precision end |
#precision ⇒ Object
Returns the intervals precision. Mixed precisions are currently not supported; in that case, the start date’s precision takes precedence.
85 86 87 |
# File 'lib/edtf/interval.rb', line 85 def precision min.precision || max.precision end |
#step(by = 1) ⇒ Object
call-seq:
interval.step(by=1) { |date| block } -> self
interval.step(by=1) -> Enumerator
Iterates over the interval by passing by elements at each step and yielding each date to the passed-in block. Note that the semantics of by are precision dependent: e.g., a value of 2 can mean 2 days, 2 months, or 2 years.
If not block is given, returns an enumerator instead.
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/edtf/interval.rb', line 110 def step(by = 1) raise ArgumentError unless by.respond_to?(:to_i) if block_given? f, t, by = min, max, by.to_i unless f.nil? || t.nil? || by < 1 by = { Date::PRECISIONS[precision] => by } until f > t do yield f f = f.advance(by) end end self else enum_for(:step, by) end end |
#to_range ⇒ Object
Returns the Interval as a Range.
143 144 145 146 147 148 149 150 |
# File 'lib/edtf/interval.rb', line 143 def to_range case when open?, unknown? nil else Range.new(unknown_start? ? Date.new : @from, max) end end |
#unknown? ⇒ Boolean
79 80 81 |
# File 'lib/edtf/interval.rb', line 79 def unknown? unknown_start? || unknown_end? end |
#unknown_start! ⇒ Object
74 75 76 77 |
# File 'lib/edtf/interval.rb', line 74 def unknown_start! @from = :unknown self end |
#unknown_start? ⇒ Boolean
70 71 72 |
# File 'lib/edtf/interval.rb', line 70 def unknown_start? from == :unknown end |