Parent

Included Modules

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 #+.

i = Interval.new(1,5)
i.to_a            #=> [1,2,3,4,5]

i = Interval[0,5]
i..step(2).to_a   #=> [0,2,4]

i = Interval[1,5]
i.step(-1).to_a   #=> [5,4,3,2,1]

i = Interval[1,3]
i.step(1,2).to_a  #=> [1.0,1.5,2.0,2.5,3.0]

Public Class Methods

[]( *args ) click to toggle source
# File lib/standard/facets/interval.rb, line 40
def self.[]( *args )
  self.new( *args )
end
new(first, last, exclude_first=false, exclude_last=false ) click to toggle source
# File lib/standard/facets/interval.rb, line 45
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

Public Instance Methods

+@() click to toggle source

Unary shorthands. These return a new interval exclusive of first, last or both sentinels, repectively.

# File lib/standard/facets/interval.rb, line 111
def +@ ; Interval.new(first, last, true, false) ; end
-@() click to toggle source
# File lib/standard/facets/interval.rb, line 112
def -@ ; Interval.new(first, last, false, true) ; end
===(x) click to toggle source
Alias for: include?
begin() click to toggle source

(IMHO) these should be deprectated

Alias for: first
closed() click to toggle source

Returns a new interval inclusive of of both sentinels.

# File lib/standard/facets/interval.rb, line 91
def closed; Interval.new(@first, @last, true, true) ; end
degenerate?() click to toggle source

Returns true if the start and end sentinels are equal and the interval is closed; otherwise false.

# File lib/standard/facets/interval.rb, line 77
def degenerate? ; @direction == 0 and ! (@exclusive_first or @exclusive_last) ;  end
direction() click to toggle source

Returns the direction of the interval indicated by +1, 0 or -1.

(1..5).direction  #=> 1
(5..1).direction  #=> -1
(1..1).direction  #=> 0
# File lib/standard/facets/interval.rb, line 88
def direction ; @direction ; end
distance() click to toggle source

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.

# File lib/standard/facets/interval.rb, line 128
def distance
  @last - @first
  #if @last.respond_to?( :distance )
  #  @last.distance( @first )
  #else
  #  #self.to_a.length
  #end
end
Also aliased as: length, size
each(n=nil, d=nil) click to toggle source
def include?(x)
  tf = exclude_first? ? 1 : 0
  tl = exclude_last? ? -1 : 0
  # if other classes handled Infinity in their <=> method
  # (which probably they should) this clause would not be required
  if first.kind_of?(InfinityClass)
    ft = ((first <=> x) <= tf)
  else
    ft = (x <=> first) >= tf
  end
  if last.kind_of?(InfinityClass)
    fl = ((last <=> x) >= tl)
  else
    fl = (x <=> last) <= tl
  end
  ft && fl
end

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

@todo Deprecate arguments and simplify each definition accordingly.

# File lib/standard/facets/interval.rb, line 193
def each(n=nil, d=nil)  # :yield:
  if n
    warn "FACETS: `interval.each(n,d){...}` will be deprecated.\n" +
         "Use `interval.step(n,d).each{...}` instead."
  else
    n = 1
  end

  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 = @exclude_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 = @exclude_last ? -1 : 0
    #while e.cmp(@last) <= t
    while (e <=> @last) <= t
      yield(e)
      e += s
      #e = e.succ(s)
    end
  end
end
end() click to toggle source
Alias for: last
eql?(other) click to toggle source

Compares two intervals to see if they are equal

# File lib/standard/facets/interval.rb, line 269
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_begin?() click to toggle source
Alias for: exclude_first?
exclude_end?() click to toggle source
Alias for: exclude_last?
exclude_first?() click to toggle source
# File lib/standard/facets/interval.rb, line 67
def exclude_first? ; @exclude_first ; end
Also aliased as: exclude_begin?
exclude_last?() click to toggle source
# File lib/standard/facets/interval.rb, line 68
def exclude_last? ; @exclude_last ; end
Also aliased as: exclude_end?
first() click to toggle source

Returns the first or last sentinal of the interval.

# File lib/standard/facets/interval.rb, line 63
def first ; @first ; end
Also aliased as: begin
first_closed() click to toggle source

Returns a new interval with one of the two sentinels opened or closed

# File lib/standard/facets/interval.rb, line 104
def first_closed ; Interval.new(@first, @last, false, true) ; end
first_opened() click to toggle source
# File lib/standard/facets/interval.rb, line 106
def first_opened ; Interval.new(@first, @last, true, false) ; end
half_closed(e=false) click to toggle source

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.

# File lib/standard/facets/interval.rb, line 99
def half_closed(e=false)
  e ? Interval.new(@first, @last, true, false) : Interval.new(@first, @last, false, true)
end
include?(x) click to toggle source

Returns true or false if the element is part of the interval.

# File lib/standard/facets/interval.rb, line 150
def include?(x)
  # todo: infinity?
  tf = exclude_first? ? 1 : 0
  tl = exclude_last? ? -1 : 0
  (x <=> first) >= tf and (x <=> last) <= tl
end
Also aliased as: ===, member?
last() click to toggle source
# File lib/standard/facets/interval.rb, line 64
def last ; @last ; end
Also aliased as: end
last_closed() click to toggle source
# File lib/standard/facets/interval.rb, line 105
def last_closed  ; Interval.new(@first, @last, true, false) ; end
last_opened() click to toggle source
# File lib/standard/facets/interval.rb, line 107
def last_opened  ; Interval.new(@first, @last, false, true) ; end
length() click to toggle source
Alias for: distance
max() click to toggle source

Returns the greater of the first and last sentinals.

# File lib/standard/facets/interval.rb, line 145
def max
  ((@first <=> @last) == 1) ? @first : @last
end
member?(x) click to toggle source
Alias for: include?
min() click to toggle source

Returns the lesser of the first and last sentinals.

# File lib/standard/facets/interval.rb, line 140
def min
  ((@first <=> @last) == -1) ? @first : @last
end
null?() click to toggle source

Returns true if the start and end sentinels are equal and the interval is open; otherwise false.

# File lib/standard/facets/interval.rb, line 80
def null? ; @direction == 0 and @exclusive_first and @exclusive_last ; end
opened() click to toggle source

Returns a new interval exclusive of both sentinels.

# File lib/standard/facets/interval.rb, line 94
def opened; Interval.new(@first, @last, true, true) ; end
reversed() click to toggle source

Returns a new interval with the sentinels reversed.

(0..10).reversed  #=> 10..0
# File lib/standard/facets/interval.rb, line 119
def reversed
  Interval.new(@last, @first, true, true)
end
sentinels() click to toggle source

Returns a two element array of first and last sentinels.

(0..10).sentinels   #=> [0,10]
# File lib/standard/facets/interval.rb, line 58
def sentinels
  return [@first, @last]
end
size() click to toggle source
Alias for: distance
step(n=1, d=nil) click to toggle source
# File lib/standard/facets/interval.rb, line 230
def step(n=1, d=nil)  # :yield:
  return (n < 0 ? @last : @first) if degenerate?  # is this right for all values of n ?

  if block_given?
    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 = @exclude_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 = @exclude_last ? -1 : 0
      #while e.cmp(@last) <= t
      while (e <=> @last) <= t
        yield(e)
        e += s
        #e = e.succ(s)
      end
    end
  else
    Enumerator.new(self, :step, n, d)
  end
end
~() click to toggle source
# File lib/standard/facets/interval.rb, line 113
def ~ ; Interval.new(first, last, true, true) ; end

[Validate]

Generated with the Darkfish Rdoc Generator 2.