Class: Interval
- Includes:
- EnumerablePass, Multiton
- Defined in:
- lib/more/facets/interval.rb
Overview
Interval
While Ruby support the Range class out of the box, is does not quite fullfil the role od a real Interval class. For instance, it does not support excluding the front sentinel. This is because Range also tries to do triple duty as a simple Sequence and as a simple Tuple-Pair, thus limiting its potential as an Interval. The Interval class remedies the situation by commiting to interval behavior, and then extends the class’ capabilites beyond that of the standard Range in ways that naturally fall out of that.
Range depends on two methods: #succ and #<=>. If numeric ranges were the only concern, those could just as well be #+ and #<=>, but esoteric forms make that unfeasible –the obvious example being a String range. But a proper Interval class requires mathematical continuation, thus the Interval depends on #+ and #<=>, as well as #- as the inverse of #+.
Synopsis
i = Interval.new(1,5)
i.to_a #=> [1,2,3,4,5]
i = Interval[0,5]
i.to_a(2) #=> [0,2,4]
i = Interval[1,5]
i.to_a(-1) #=> [5,4,3,2,1]
i = Interval[1,3]
i.to_a(1,2) #=> [1.0,1.5,2.0,2.5,3.0]
Class Method Summary collapse
Instance Method Summary collapse
-
#+@ ⇒ Object
Unary shorthands.
- #-@ ⇒ Object
-
#closed ⇒ Object
Returns a new interval inclusive of of both sentinels.
-
#degenerate? ⇒ Boolean
Returns
trueif the start and end sentinels are equal and the interval is closed; otherwisefalse. -
#direction ⇒ Object
Returns the direction of the interval indicated by +1, 0 or -1.
-
#distance ⇒ Object
(also: #length, #size)
Returns the length of the interval as the difference between the first and last elements.
-
#each(n = 1, d = nil) ⇒ Object
(also: #step)
Iterates over the interval, passing each _n_th element to the block.
-
#eql?(other) ⇒ Boolean
Compares two intervals to see if they are equal.
- #exclude_first? ⇒ Boolean (also: #exclude_begin?)
- #exclude_last? ⇒ Boolean (also: #exclude_end?)
-
#first ⇒ Object
(also: #begin)
Returns the first or last sentinal of the interval.
-
#first_closed ⇒ Object
Returns a new interval with one of the two sentinels opened or closed.
- #first_opened ⇒ Object
-
#half_closed(e = false) ⇒ Object
Returns a new interval with either the first or the last sentinel exclusive.
-
#include?(x) ⇒ Boolean
(also: #===, #member?)
Returns true or false if the element is part of the interval.
-
#initialize(first, last, exclude_first = false, exclude_last = false) ⇒ Interval
constructor
A new instance of Interval.
- #last ⇒ Object (also: #end)
- #last_closed ⇒ Object
- #last_opened ⇒ Object
-
#max ⇒ Object
Returns the greater of the first and last sentinals.
-
#min ⇒ Object
Returns the lesser of the first and last sentinals.
-
#null? ⇒ Boolean
Returns
trueif the start and end sentinels are equal and the interval is open; otherwisefalse. -
#opened ⇒ Object
Returns a new interval exclusive of both sentinels.
-
#reversed ⇒ Object
Returns a new interval with the sentinels reversed.
-
#sentinels ⇒ Object
Returns a two element array of first and last sentinels.
- #~@ ⇒ Object
Methods included from EnumerablePass
Methods included from Multiton
Constructor Details
#initialize(first, last, exclude_first = false, exclude_last = false) ⇒ Interval
Returns a new instance of Interval.
77 78 79 80 81 82 83 84 |
# File 'lib/more/facets/interval.rb', line 77 def initialize(first, last, exclude_first=false, exclude_last=false ) raise ArgumentError, "bad value for interval" if first.class != last.class @first = first @last = last @exclude_first = exclude_first @exclude_last = exclude_last @direction = (@last <=> @first) end |
Class Method Details
.[](*args) ⇒ Object
73 74 75 |
# File 'lib/more/facets/interval.rb', line 73 def self.[]( *args ) self.new( *args ) end |
Instance Method Details
#+@ ⇒ Object
Unary shorthands. These return a new interval exclusive of first, last or both sentinels, repectively.
143 |
# File 'lib/more/facets/interval.rb', line 143 def +@ ; Interval.new(first, last, true, false) ; end |
#-@ ⇒ Object
144 |
# File 'lib/more/facets/interval.rb', line 144 def -@ ; Interval.new(first, last, false, true) ; end |
#closed ⇒ Object
Returns a new interval inclusive of of both sentinels.
123 |
# File 'lib/more/facets/interval.rb', line 123 def closed; Interval.new(@first, @last, true, true) ; end |
#degenerate? ⇒ Boolean
Returns true if the start and end sentinels are equal and the interval is closed; otherwise false.
109 |
# File 'lib/more/facets/interval.rb', line 109 def degenerate? ; @direction == 0 and ! (@exclusive_first or @exclusive_last) ; end |
#direction ⇒ Object
Returns the direction of the interval indicated by +1, 0 or -1.
(1..5).direction #=> 1
(5..1).direction #=> -1
(1..1).direction #=> 0
120 |
# File 'lib/more/facets/interval.rb', line 120 def direction ; @direction ; end |
#distance ⇒ Object Also known as: length, size
Returns the length of the interval as the difference between the first and last elements. Returns nil if the sentinal objects do not support distance comparison (#distance). TODO: Add n parameter to count segmentations like those produced by #each.
159 160 161 162 163 164 165 166 |
# File 'lib/more/facets/interval.rb', line 159 def distance @last - @first #if @last.respond_to?( :distance ) # @last.distance( @first ) #else # #self.to_a.length #end end |
#each(n = 1, d = nil) ⇒ Object Also known as: step
Iterates over the interval, passing each _n_th element to the block. If n is not given then n defaults to 1. Each _n_th step is determined by invoking + or \- n, depending on the direction of the interval. If n is negative the iteration is preformed in reverse form end sentinal to front sentinal. A second parameter, d, can be given in which case the applied step is calculated as a fraction of the interval’s length times n / d. This allows iteration over the whole interval in equal sized segments.
1..5.each { |e| ... } #=> 1 2 3 4 5
1..5.each(2) { |e| ... } #=> 1 3 5
1..5.each(1,2) { |e| ... } #=> 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
# File 'lib/more/facets/interval.rb', line 223 def each(n=1, d=nil) # :yield: return (n < 0 ? @last : @first) if degenerate? # is this right for all values of n ? s = d ? self.length.to_f * (n.to_f / d.to_f) : n.abs raise "Cannot iterate over zero length steps." if s == 0 s = s * @direction if n < 0 e = @exclude_last ? @last - s : @last #e = @exclude_last ? @last.pred(s) : @last t = @exlude_last ? 1 : 0 #while e.cmp(@first) >= t while (e <=> @first) >= t yield(e) e -= s #e = e.pred(s) end else e = @exclude_first ? @first + s : @first #e = @exclude_first ? @first.succ(s) : @first t = @exlude_last ? -1 : 0 #while e.cmp(@last) <= t while (e <=> @last) <= t yield(e) e += s #e = e.succ(s) end end end |
#eql?(other) ⇒ Boolean
Compares two intervals to see if they are equal
258 259 260 261 262 263 264 |
# File 'lib/more/facets/interval.rb', line 258 def eql?(other) return false unless @first == other.first return false unless @last == other.last return false unless @exclude_first == other.exclude_first? return false unless @exclude_last == other.exclude_last? true end |
#exclude_first? ⇒ Boolean Also known as: exclude_begin?
99 |
# File 'lib/more/facets/interval.rb', line 99 def exclude_first? ; @exclude_first ; end |
#exclude_last? ⇒ Boolean Also known as: exclude_end?
100 |
# File 'lib/more/facets/interval.rb', line 100 def exclude_last? ; @exclude_last ; end |
#first ⇒ Object Also known as: begin
Returns the first or last sentinal of the interval.
95 |
# File 'lib/more/facets/interval.rb', line 95 def first ; @first ; end |
#first_closed ⇒ Object
Returns a new interval with one of the two sentinels opened or closed
136 |
# File 'lib/more/facets/interval.rb', line 136 def first_closed ; Interval.new(@first, @last, false, true) ; end |
#first_opened ⇒ Object
138 |
# File 'lib/more/facets/interval.rb', line 138 def first_opened ; Interval.new(@first, @last, true, false) ; end |
#half_closed(e = false) ⇒ Object
Returns a new interval with either the first or the last sentinel exclusive. If the parameter is false, the deafult, then the first sentinel is excluded; if the parameter is true, the last sentinel is excluded.
131 132 133 |
# File 'lib/more/facets/interval.rb', line 131 def half_closed(e=false) e ? Interval.new(@first, @last, true, false) : Interval.new(@first, @last, false, true) end |
#include?(x) ⇒ Boolean Also known as: ===, member?
Returns true or false if the element is part of the interval.
181 182 183 184 185 186 |
# File 'lib/more/facets/interval.rb', line 181 def include?(x) # todo: infinity? tf = exclude_first? ? 1 : 0 tl = exclude_last? ? -1 : 0 (x <=> first) >= tf and (x <=> last) <= tl end |
#last ⇒ Object Also known as: end
96 |
# File 'lib/more/facets/interval.rb', line 96 def last ; @last ; end |
#last_closed ⇒ Object
137 |
# File 'lib/more/facets/interval.rb', line 137 def last_closed ; Interval.new(@first, @last, true, false) ; end |
#last_opened ⇒ Object
139 |
# File 'lib/more/facets/interval.rb', line 139 def last_opened ; Interval.new(@first, @last, false, true) ; end |
#max ⇒ Object
Returns the greater of the first and last sentinals.
176 177 178 |
# File 'lib/more/facets/interval.rb', line 176 def max ((@first <=> @last) == 1) ? @first : @last end |
#min ⇒ Object
Returns the lesser of the first and last sentinals.
171 172 173 |
# File 'lib/more/facets/interval.rb', line 171 def min ((@first <=> @last) == -1) ? @first : @last end |
#null? ⇒ Boolean
Returns true if the start and end sentinels are equal and the interval is open; otherwise false.
112 |
# File 'lib/more/facets/interval.rb', line 112 def null? ; @direction == 0 and @exclusive_first and @exclusive_last ; end |
#opened ⇒ Object
Returns a new interval exclusive of both sentinels.
126 |
# File 'lib/more/facets/interval.rb', line 126 def opened; Interval.new(@first, @last, true, true) ; end |
#reversed ⇒ Object
Returns a new interval with the sentinels reversed.
(0..10).reversed #=> 10..0
151 152 153 |
# File 'lib/more/facets/interval.rb', line 151 def reversed Interval.new(@last, @first, true, true) end |
#sentinels ⇒ Object
Returns a two element array of first and last sentinels.
(0..10).sentinels #=> [0,10]
90 91 92 |
# File 'lib/more/facets/interval.rb', line 90 def sentinels return [@first, @last] end |
#~@ ⇒ Object
145 |
# File 'lib/more/facets/interval.rb', line 145 def ~@ ; Interval.new(first, last, true, true) ; end |