Module: Indexable

Included in:
Array, String
Defined in:
lib/core/facets/indexable.rb

Overview

Indexable is a mixin that provides index based methods, working solely with four methods: #index, #slice, #splice and #size.

These methods work in harmony. Where #index returns a position of a given element, #slice returns elements for given positions. #splice is like #slice but replaces the given position with new values. This method is not part of ruby core, but it generally just an alias for #[]=, just as #slice is an alias of #[]. #size of course simply returns the total length of the indexable object.

NOTE: To test the following methods Indexable needs to be included into Array and array must have #splice defined.

require 'facets/array/splice'

class ::Array
  include Indexable
end

CREDIT: Thomas Sawyer

Instance Method Summary collapse

Instance Method Details

#bodyObject

Returns an array of the first element up to, but not including, the last element.

[1,2,3].body  #=> [1,2]

– Better name for this? (bulk, perhaps?) ++



61
62
63
# File 'lib/core/facets/indexable.rb', line 61

def body
  slice(0,size-1)
end

#endsObject Also known as: last_index

A shortening of “ends at”. Returns the last index of the indexable object, or nil if there are no elements.

[1,2,3,4,5].ends  #=> 4

This is nearly equivalent to size - 1.



210
211
212
213
# File 'lib/core/facets/indexable.rb', line 210

def ends
  return nil if size == 0
  size - 1
end

#first(n = 1) ⇒ Object

Returns first n elements.

%w{H e l l o}.first(3)  #=> %w{H e l}


148
149
150
# File 'lib/core/facets/indexable.rb', line 148

def first(n=1)
  slice(0, n.to_i)
end

#first!Object

Remove and return the first element.

a = [1,2,3]
a.first!      #=> 1
a             #=> [2,3]


188
189
190
# File 'lib/core/facets/indexable.rb', line 188

def first!
  splice(0)
end

#first=(x) ⇒ Object

Change the first element.

a = ["a","y","z"]
a.first = "x"
a           #=> ["x","y","z"]


168
169
170
# File 'lib/core/facets/indexable.rb', line 168

def first=(x)
  splice(0,x)
end

#footObject

Like #last, returning the last element in an array.

[1,2,3].foot  #=> [3]


48
49
50
# File 'lib/core/facets/indexable.rb', line 48

def foot
  slice(-1,1)
end

#from(i) ⇒ Object

Returns last n elements.

%w{W o r l d}.from(3)  #=> %w{l d}


130
131
132
133
# File 'lib/core/facets/indexable.rb', line 130

def from(i)
  return [] if i >= size
  slice(i, size - i) #slice(-n..-1)
end

#headObject

Like #first but returns the first element in a new array.

[1,2,3].head  #=> [1]


31
32
33
# File 'lib/core/facets/indexable.rb', line 31

def head
  slice(0,1)
end

#index(obj = nil, &block) ⇒ Object Also known as: index_of

Returns the index of the first element equal to the given object or satisfying the block condition.

[1,2,3,4].index{ |e| e == 3 }  #=> 2
[1,2,3,4].index{ |e| e > 3 }   #=> 3


237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/core/facets/indexable.rb', line 237

def index(obj=nil, &block)
  if block_given?
    size.times do |i|
      return i if yield(slice(i))
    end
  else
    size.times do |i|
      return i if obj == slice(i)
    end
  end
  nil
end

#last(n = 1) ⇒ Object

Returns last n elements.

%w{H e l l o}.last(3)  #=> %w{l l o}


156
157
158
159
160
# File 'lib/core/facets/indexable.rb', line 156

def last(n=1)
  n = n.to_i
  return self if n > size
  slice(-n, n) #slice(-n..-1)
end

#last!Object

Remove and return the last element.

a = [1,2,3]
a.last!       #=> 3
a             #=> [1,2]


198
199
200
# File 'lib/core/facets/indexable.rb', line 198

def last!
  splice(-1)
end

#last=(x) ⇒ Object

Change the last element.

a = [1,2,5]
a.last = 3
a           #=> [1,2,3]


178
179
180
# File 'lib/core/facets/indexable.rb', line 178

def last=(x)
  splice(-1,x)
end

#mid(offset = 0) ⇒ Object

Returns the middle element of an array, or the element offset from middle if the parameter is given. Even-sized arrays, not having an exact middle, return the middle-right element.

[1,2,3,4,5].mid        #=> 3
[1,2,3,4,5,6].mid      #=> 4
[1,2,3,4,5,6].mid(-1)  #=> 3
[1,2,3,4,5,6].mid(-2)  #=> 2
[1,2,3,4,5,6].mid(1)   #=> 5

In other words, If there are an even number of elements the higher-indexed of the two center elements is indexed as origin (0).



79
80
81
# File 'lib/core/facets/indexable.rb', line 79

def mid(offset=0)
  slice((size / 2) + offset)
end

#middle(birth = 0) ⇒ Object

Returns an Array of the middle element(s) of an array. Even-sized arrays, not having an exact middle, return a two-element array of the two middle elements.

[1,2,3,4,5].middle        #=> [3]
[1,2,3,4,5,6].middle      #=> [3,4]

A birth can be give to widen the middle on either side.

[1,2,3,4,5].middle(1)   #=> [2,3,4]
[1,2,3,4,5,6].middle(1)   #=> [2,3,4,5]

In contrast to #mid which utilizes an offset.



97
98
99
100
101
102
103
104
# File 'lib/core/facets/indexable.rb', line 97

def middle(birth=0)
  i = size / 2 - birth
  if size % 2 == 0
    slice(i - 1, 2 + (2 * birth))
  else
    slice(i, 1 + (2 * birth))
  end
end

#pos(i) ⇒ Object

Returns the positive ordinal index given a cardinal position, 1 to n or -n to -1.

[1,2,3,4,5].pos(1)   #=> 0
[1,2,3,4,5].pos(-1)  #=> 4


223
224
225
226
227
228
229
# File 'lib/core/facets/indexable.rb', line 223

def pos(i)
  if i > 0
    return i - 1
  else
    size + i
  end
end

#range(a = nil, z = -1)) ⇒ Object

Returns the index range between two elements. If no elements are given, returns the range from first to last.

['a','b','c','d'].range            #=> (0..3)
['a','b','c','d'].range('b','d')   #=> (1..3)


261
262
263
264
265
266
267
# File 'lib/core/facets/indexable.rb', line 261

def range(a=nil,z=-1)
  if a
    index(a)..index(z)
  else
    (0..(size-1))
  end
end

#tailObject

Returns an array from second element to last element.

[1,2,3].tail  #=> [2,3]


39
40
41
# File 'lib/core/facets/indexable.rb', line 39

def tail
  slice(1,length-1)
end

#thru(from, to = nil) ⇒ Object

Fetch values from a start index through an end index.

[1,2,3,4,5].thru(0,2)  #=> [1,2,3]
[1,2,3,4,5].thru(2,4)  #=> [3,4,5]

[1,2,3,4,5].thru(2)  #=> [1,2,3]
[1,2,3,4,5].thru(4)  #=> [1,2,3,4,5]


114
115
116
117
118
119
120
121
122
123
124
# File 'lib/core/facets/indexable.rb', line 114

def thru(from, to=nil)
  from, to = 0, from unless to
  to = size - 1 if to >= size
  a = []
  i = from
  while i <= to
    a << slice(i)
    i += 1
  end
  a
end