Class: Functional::Tuple

Inherits:
Synchronization::Object
  • Object
show all
Defined in:
lib/functional/tuple.rb

Overview

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.

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.

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.

Instance Method Summary collapse

Constructor Details

#initialize(data = []) ⇒ Tuple

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

Parameters:

  • data (Array) (defaults to: [])

    the data items to insert into the new tuple

Raises:

  • (ArgumentError)

    if data is not an array or does not implement ‘to_a`



38
39
40
41
42
43
44
# 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

Instance Method Details

#at(index) ⇒ Object Also known as: nth, []

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.

Parameters:

  • index (Fixnum)

    the index of the item to be retrieved

Returns:

  • (Object)

    the item at the given index or nil when index is out of bounds



53
54
55
# File 'lib/functional/tuple.rb', line 53

def at(index)
  @data[index]
end

#concat(other) ⇒ Functional::Tuple Also known as: +

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

Parameters:

  • other (Array)

    the tuple or array-like object (responds to ‘to_a`) to operate on

Returns:



108
109
110
# File 'lib/functional/tuple.rb', line 108

def concat(other)
  Tuple.new(@data + other.to_a)
end

#diff(other) ⇒ Functional::Tuple Also known as: -

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.

Parameters:

  • other (Array)

    the tuple or array-like object (responds to ‘to_a`) to operate on

Returns:



117
118
119
# File 'lib/functional/tuple.rb', line 117

def diff(other)
  Tuple.new(@data - other.to_a)
end

#each {|item| ... } ⇒ Enumerable

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.

Yield Parameters:

  • item (Object)

    the current item

Returns:

  • (Enumerable)

    when no block is given



147
148
149
150
151
152
# 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| ... } ⇒ Enumerable

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.

Yield Parameters:

  • item (Object)

    the current item

  • index (Fixnum)

    the index of the current item

Returns:

  • (Enumerable)

    when no block is given



160
161
162
163
164
165
# 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?Boolean

Returns true if self contains no items.

Returns:

  • (Boolean)

    true when empty else false



204
205
206
# File 'lib/functional/tuple.rb', line 204

def empty?
  @data.empty?
end

#eql?(other) ⇒ Boolean Also known as: ==

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.

Parameters:

  • other (Object)

    the other tuple to compare for equality

Returns:

  • (Boolean)

    true when equal else false



196
197
198
# File 'lib/functional/tuple.rb', line 196

def eql?(other)
  @data == other.to_a
end

#fetch(index, default) ⇒ Object

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.

Parameters:

  • index (Fixnum)

    the index of the item to be retrieved

  • default (Object)

    the value to return when given an out of bounds index

Returns:

  • (Object)

    the item at the given index or default when index is out of bounds

See Also:



68
69
70
71
72
73
74
# File 'lib/functional/tuple.rb', line 68

def fetch(index, default)
  if index >= length || -index > length
    default
  else
    at(index)
  end
end

#firstObject Also known as: head

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

Returns:

  • (Object)

    the first element or nil



211
212
213
# File 'lib/functional/tuple.rb', line 211

def first
  @data.first
end

#intersect(other) ⇒ Functional::Tuple Also known as: &

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

Parameters:

  • other (Array)

    the tuple or array-like object (responds to ‘to_a`) to operate on

Returns:



90
91
92
# File 'lib/functional/tuple.rb', line 90

def intersect(other)
  Tuple.new(@data & other.to_a)
end

#lengthFixnum Also known as: size

The number of items in the tuple.

Returns:

  • (Fixnum)

    the number of items in the tuple



79
80
81
# File 'lib/functional/tuple.rb', line 79

def length
  @data.length
end

#repeat(multiple) ⇒ Functional::Tuple Also known as: *

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

Parameters:

  • multiple (Fixnum)

    the number of times to concatenate self

Returns:

Raises:

  • (ArgumentError)

    when multiple is a negative number



128
129
130
131
132
# 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

#restFunctional::Tuple Also known as: tail

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.

Returns:



220
221
222
223
224
225
226
# 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

#sequence {|head, tail| ... } ⇒ Enumerable

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.

Yield Parameters:

  • head (Object)

    the current item for this iteration

  • tail (Tuple)

    the remaining items (tail) or an empty tuple when processing the last item

Returns:

  • (Enumerable)

    when no block is given



177
178
179
180
181
182
183
184
185
186
187
# 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

#to_aArray Also known as: to_ary

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

Returns:

  • (Array)

    the new array created from the tuple



233
234
235
# File 'lib/functional/tuple.rb', line 233

def to_a
  @data.dup
end

#union(other) ⇒ Functional::Tuple Also known as: |

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

Parameters:

  • other (Array)

    the tuple or array-like object (responds to ‘to_a`) to operate on

Returns:



99
100
101
# File 'lib/functional/tuple.rb', line 99

def union(other)
  Tuple.new(@data | other.to_a)
end

#uniqFunctional::Tuple

Returns a new tuple by removing duplicate values in self.

Returns:



138
139
140
# File 'lib/functional/tuple.rb', line 138

def uniq
  Tuple.new(@data.uniq)
end