class Functional::Tuple

A tuple is a pure functional data strcture that is similar to an array but is immutable and of fixed length. Tuples support many of the same operations as array/list/vector.

@note The current implementation uses simple Ruby arrays. This is likely to be

very inefficient for all but the smallest tuples. The more items the tuple
contains, the less efficient it will become. A future version will use a fast,
immutable, persistent data structure such as a finger tree or a trie.

@see en.wikipedia.org/wiki/Tuple @see msdn.microsoft.com/en-us/library/system.tuple.aspx @see www.tutorialspoint.com/python/python_tuples.htm @see en.cppreference.com/w/cpp/utility/tuple @see docs.oracle.com/javaee/6/api/javax/persistence/Tuple.html @see www.erlang.org/doc/reference_manual/data_types.html @see www.erlang.org/doc/man/erlang.html#make_tuple-2 @see en.wikibooks.org/wiki/Haskell/Lists_and_tuples#Tuples

@!macro [new] thread_safe_immutable_object

@note This is a write-once, read-many, thread safe object that can be
  used in concurrent systems. Thread safety guarantees *cannot* be made
  about objects contained *within* this object, however. Ruby variables
  are mutable references to mutable objects. This cannot be changed. The
  best practice it to only encapsulate immutable, frozen, or thread safe
  objects. Ultimately, thread safety is the responsibility of the
  programmer.

Public Class Methods

new(data = []) click to toggle source

Create a new tuple with the given data items in the given order.

@param [Array] data the data items to insert into the new tuple @raise [ArgumentError] if data is not an array or does not implement ‘to_a`

# File lib/functional/tuple.rb, line 38
def initialize(data = [])
  raise ArgumentError.new('data is not an array') unless data.respond_to?(:to_a)
  super
  @data = data.to_a.dup.freeze
  self.freeze
  ensure_ivar_visibility!
end

Public Instance Methods

&(other)
Alias for: intersect
*(multiple)
Alias for: repeat
+(other)
Alias for: concat
-(other)
Alias for: diff
==(other)
Alias for: eql?
[](index)
Alias for: at
at(index) click to toggle source

Retrieve the item at the given index. Indices begin at zero and increment up, just like Ruby arrays. Negative indicies begin at -1, which represents the last item in the tuple, and decrement toward the first item. If the given index is out of range then ‘nil` is returned.

@param [Fixnum] index the index of the item to be retrieved @return [Object] the item at the given index or nil when index is out of bounds

# File lib/functional/tuple.rb, line 53
def at(index)
  @data[index]
end
Also aliased as: nth, []
concat(other) click to toggle source

Returns a new tuple built by concatenating the two tuples together to produce a third tuple.

@!macro tuple_method_param_other_return_tuple

# File lib/functional/tuple.rb, line 108
def concat(other)
  Tuple.new(@data + other.to_a)
end
Also aliased as: +
diff(other) click to toggle source

Returns a new tuple that is a copy of the original tuple, removing any items that also appear in other. The order is preserved from the original tuple.

@!macro tuple_method_param_other_return_tuple

# File lib/functional/tuple.rb, line 117
def diff(other)
  Tuple.new(@data - other.to_a)
end
Also aliased as: -
each() { |item| ... } click to toggle source

Calls the given block once for each element in self, passing that element as a parameter. An Enumerator is returned if no block is given.

@yieldparam [Object] item the current item @return [Enumerable] when no block is given

# File lib/functional/tuple.rb, line 147
def each
  return enum_for(:each) unless block_given?
  @data.each do |item|
    yield(item)
  end
end
each_with_index() { |item, index| ... } click to toggle source

Calls the given block once for each element in self, passing that element and the current index as parameters. An Enumerator is returned if no block is given.

@yieldparam [Object] item the current item @yieldparam [Fixnum] index the index of the current item @return [Enumerable] when no block is given

# File lib/functional/tuple.rb, line 160
def each_with_index
  return enum_for(:each_with_index) unless block_given?
  @data.each_with_index do |item, index|
    yield(item, index)
  end
end
empty?() click to toggle source

Returns true if self contains no items.

@return [Boolean] true when empty else false

# File lib/functional/tuple.rb, line 204
def empty?
  @data.empty?
end
eql?(other) click to toggle source

Compares this object and other for equality. A tuple is ‘eql?` to other when other is a tuple or an array-like object (any object that responds to `to_a`) and the two objects have identical values in the same foxed order.

@param [Object] other the other tuple to compare for equality @return [Boolean] true when equal else false

# File lib/functional/tuple.rb, line 196
def eql?(other)
  @data == other.to_a
end
Also aliased as: ==
fetch(index, default) click to toggle source

Retrieve the item at the given index or return the given default value if the index is out of bounds. The behavior of indicies follows the rules for the ‘at` method.

@param [Fixnum] index the index of the item to be retrieved @param [Object] default the value to return when given an out of bounds index @return [Object] the item at the given index or default when index is out of bounds

@see Functional::Tuple#at

# File lib/functional/tuple.rb, line 68
def fetch(index, default)
  if index >= length || -index > length
    default
  else
    at(index)
  end
end
first() click to toggle source

Returns the first element of the tuple or nil when empty.

@return [Object] the first element or nil

# File lib/functional/tuple.rb, line 211
def first
  @data.first
end
Also aliased as: head
head()
Alias for: first
inspect() click to toggle source

Describe the contents of this object in a string.

@return [String] the string representation of this object

@!visibility private

# File lib/functional/tuple.rb, line 243
def inspect
  "#<#{self.class}: #{@data.to_s}>"
end
intersect(other) click to toggle source

Returns a new tuple containing elements common to the two tuples, excluding any duplicates. The order is preserved from the original tuple.

@!macro [attach] tuple_method_param_other_return_tuple

@param [Array] other the tuple or array-like object (responds to `to_a`) to operate on
@return [Functional::Tuple] a new tuple with the appropriate items
# File lib/functional/tuple.rb, line 90
def intersect(other)
  Tuple.new(@data & other.to_a)
end
Also aliased as: &
length() click to toggle source

The number of items in the tuple.

@return [Fixnum] the number of items in the tuple

# File lib/functional/tuple.rb, line 79
def length
  @data.length
end
Also aliased as: size
nth(index)
Alias for: at
repeat(multiple) click to toggle source

Returns a new tuple built by concatenating the given number of copies of self. Returns an empty tuple when the multiple is zero.

@param [Fixnum] multiple the number of times to concatenate self @return [Functional::Tuple] a new tuple with the appropriate items @raise [ArgumentError] when multiple is a negative number

# File lib/functional/tuple.rb, line 128
def repeat(multiple)
  multiple = multiple.to_i
  raise ArgumentError.new('negative argument') if multiple < 0
  Tuple.new(@data * multiple)
end
Also aliased as: *
rest() click to toggle source

Returns a tuple containing all the items in self after the first item. Returns an empty tuple when empty or there is only one item.

@return [Functional::Tuple] the tail of the tuple

# File lib/functional/tuple.rb, line 220
def rest
  if @data.length <= 1
    Tuple.new
  else
    Tuple.new(@data.slice(1..@data.length-1))
  end
end
Also aliased as: tail
sequence() { |data, tuple| ... } click to toggle source

Calls the given block once for each element in self, passing that element and a tuple with all the remaining items in the tuple. When the last item is reached ab empty tuple is passed as the second parameter. This is the classic functional programming ‘head|tail` list processing idiom. An Enumerator is returned if no block is given.

@yieldparam [Object] head the current item for this iteration @yieldparam [Tuple] tail the remaining items (tail) or an empty tuple when

processing the last item

@return [Enumerable] when no block is given

# File lib/functional/tuple.rb, line 177
def sequence
  return enum_for(:sequence) unless block_given?
  @data.length.times do |index|
    last = @data.length - 1
    if index == last
      yield(@data[index], Tuple.new)
    else
      yield(@data[index], Tuple.new(@data.slice(index+1..last)))
    end
  end
end
size()
Alias for: length
tail()
Alias for: rest
to_a() click to toggle source

Create a standard Ruby mutable array containing the tuple items in the same order.

@return [Array] the new array created from the tuple

# File lib/functional/tuple.rb, line 233
def to_a
  @data.dup
end
Also aliased as: to_ary
to_ary()
Alias for: to_a
to_s() click to toggle source

Describe the contents of this object in a string that exactly matches the string that would be created from an identical array.

@return [String] the string representation of this object

@!visibility private

# File lib/functional/tuple.rb, line 253
def to_s
  @data.to_s
end
union(other) click to toggle source

Returns a new tuple by joining self with other, excluding any duplicates and preserving the order from the original tuple.

@!macro tuple_method_param_other_return_tuple

# File lib/functional/tuple.rb, line 99
def union(other)
  Tuple.new(@data | other.to_a)
end
Also aliased as: |
uniq() click to toggle source

Returns a new tuple by removing duplicate values in self.

@return [Functional::Tuple] the new tuple with only unique items

# File lib/functional/tuple.rb, line 138
def uniq
  Tuple.new(@data.uniq)
end
|(other)
Alias for: union