Class: FlexArray

Inherits:
Object show all
Includes:
Enumerable, InArrayAlready
Defined in:
lib/flex_array.rb,
lib/flex_array/version.rb,
lib/flex_array/flex_array_new.rb,
lib/flex_array/flex_array_each.rb,
lib/flex_array/flex_array_index.rb,
lib/flex_array/flex_array_append.rb,
lib/flex_array/flex_array_forever.rb,
lib/flex_array/flex_array_process.rb,
lib/flex_array/flex_array_reshape.rb,
lib/flex_array/flex_array_validate.rb,
lib/flex_array/flex_array_transpose.rb

Overview

The flexible array class transpose and related methods.

Defined Under Namespace

Classes: ForEver

Constant Summary collapse

VERSION =

The version string for flex array.

"0.3.7".freeze
FOREVER =

Create a forever constant for use where infinite looping is needed.

ForEver.new

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(array_specs, default = nil, &init_block) ⇒ FlexArray

Construct a flexible array object.



4
5
6
7
8
9
10
11
12
13
14
15
# File 'lib/flex_array/flex_array_new.rb', line 4

def initialize(array_specs, default=nil, &init_block)
  @array_specs = SpecArray.new(array_specs.in_array)
  @transposed = false

  # Allocate the data for the array.
  @array_data = Array.new(@array_specs.spec_count, default)

  # Set up the array with the optional init_block.
  if init_block
    process_all {|index, posn| @array_data[posn] = init_block.call(index)}
  end
end

Instance Attribute Details

#array_dataObject

The underlying array data used by the flex array.



40
41
42
# File 'lib/flex_array.rb', line 40

def array_data
  @array_data
end

#array_specsObject

The array specifications. An array of spec components.



37
38
39
# File 'lib/flex_array.rb', line 37

def array_specs
  @array_specs
end

#transposedObject (readonly)

Is this flex array transposed?



55
56
57
# File 'lib/flex_array.rb', line 55

def transposed
  @transposed
end

Class Method Details

.new_from(array_specs, other) ⇒ Object

Construct a flex array using other as a template or data source.



28
29
30
31
# File 'lib/flex_array/flex_array_new.rb', line 28

def self.new_from(array_specs, other)
  iterator = other.array_data.cycle
  FlexArray.new(array_specs) {iterator.next}
end

.new_from_array(other) ⇒ Object

Construct a flex array as a duplicate of a source array or flex array.



41
42
43
44
45
46
# File 'lib/flex_array/flex_array_new.rb', line 41

def self.new_from_array(other)
  result = FlexArray.new(0)
  result.array_specs = other.array_specs.dup
  result.array_data = other.array_data
  result
end

.new_from_selection(array_specs, other, selection) ⇒ Object

Construct a flex array using a all or a portion of portion of another flex array as a data source.



35
36
37
38
# File 'lib/flex_array/flex_array_new.rb', line 35

def self.new_from_selection(array_specs, other, selection)
  iterator = other.select_cycle(selection)
  FlexArray.new(array_specs) {iterator.next}
end

.versionObject

The version of this class. “<major>.<minor>.<step>”



27
28
29
# File 'lib/flex_array.rb', line 27

def self.version
  FlexArray::VERSION
end

Instance Method Details

#<<(data) ⇒ Object

Append to the flex array.



5
6
7
8
9
10
11
# File 'lib/flex_array/flex_array_append.rb', line 5

def << (data)
  fail "Cannot append to a transposed array." if @transposed
  specs = get_append_specs(data = data.in_array)
  @array_data += data.array_data
  @array_specs.enlarge(specs[0].span)
  self
end

#<=>(other) ⇒ Object

Make FlexArrays comparable with the compariositality method.



73
74
75
# File 'lib/flex_array.rb', line 73

def <=>(other)
  @array_data <=> other.array_data
end

#==(other) ⇒ Object

Are these FlexArrays equal?



68
69
70
# File 'lib/flex_array.rb', line 68

def ==(other)
  self.compatible?(other) && @array_data == other.array_data
end

#[](*indexes) ⇒ Object

Retrieve the selected data from the flex array.



5
6
7
8
9
10
# File 'lib/flex_array/flex_array_index.rb', line 5

def [](*indexes)
  validate_index_count(indexes)
  result = []
  process_indexes(indexes) {|_index, posn| result << @array_data[posn]}
  result.length == 1 ? result[0] : result
end

#[]=(*indexes, value) ⇒ Object

Store the value data into the flex array.



13
14
15
16
17
18
# File 'lib/flex_array/flex_array_index.rb', line 13

def []=(*indexes, value)
  validate_index_count(indexes)
  source = value.in_array.cycle
  process_indexes(indexes) {|_index, posn| @array_data[posn] = source.next}
  value
end

#_each_raw(&block) ⇒ Object

A specialized each variant that passes the low level data, the index and the position to the block.



95
96
97
98
99
100
101
102
# File 'lib/flex_array/flex_array_each.rb', line 95

def _each_raw(&block)
  if block_given?
    process_all {|index, posn| block.call(index, posn)}
    self
  else
    self.to_enum(:_each_raw)
  end
end

#_select_each_raw(indexes, &block) ⇒ Object

An enhanced specialized each variant that passes the low level data, the index and the position to the block.



106
107
108
109
110
111
112
113
114
115
# File 'lib/flex_array/flex_array_each.rb', line 106

def _select_each_raw(indexes, &block)
  validate_index_count(indexes)

  if block_given?
    process_indexes(indexes) {|index, posn| block.call(index, posn)}
    self
  else
    self.to_enum(:_select_each_raw, indexes)
  end
end

#collect(&block) ⇒ Object

The flex array version of collect that returns a flex array.



120
121
122
123
# File 'lib/flex_array/flex_array_each.rb', line 120

def collect(&block)
  result = self.dup
  result.collect!(&block)
end

#collect!(&block) ⇒ Object

The flex array version of collect!



147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/flex_array/flex_array_each.rb', line 147

def collect!(&block)
  fail ArgumentError, "A block is required." unless block_given?

  if @transposed
    process_all {|_index, posn| @array_data[posn] =
      block.call(@array_data[posn])}
  else
    @array_data = @array_data.collect(&block)
  end

  self
end

#compatible?(other) ⇒ Boolean

Is this array compatible with other?

Returns:

  • (Boolean)


5
6
7
8
9
# File 'lib/flex_array/flex_array_validate.rb', line 5

def compatible?(other)
  @array_specs == other.array_specs
rescue
  false
end

#cycle(count = FOREVER, &block) ⇒ Object

Retrieve data from the array endlessly repeating as needed.



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/flex_array/flex_array_each.rb', line 7

def cycle(count = FOREVER, &block)
  if block_given?
    if @transposed && length > 0
      count.times do
        process_all do |_index, posn|
          block.call(@array_data[posn])
        end
      end

      nil
    else
      @array_data.cycle(count.to_i, &block)
    end
  else
    self.to_enum(:cycle, count)
  end
end

#dimensionsObject

The number of dimensions in this array.



50
51
52
# File 'lib/flex_array.rb', line 50

def dimensions
  @array_specs.spec_dimensions
end

#dupObject

Create a duplicate of this array.



20
21
22
23
24
25
# File 'lib/flex_array/flex_array_new.rb', line 20

def dup
  other = self.shallow_dup
  other.array_specs = @array_specs.dup
  other.array_data  = @array_data.dup
  other
end

#each(&block) ⇒ Object

Process the standard each operator.



45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/flex_array/flex_array_each.rb', line 45

def each(&block)
  if block_given?
    if @transposed
      process_all {|_index, posn| block.call(@array_data[posn])}
    else
      @array_data.each(&block)
    end

    self
  else
    self.to_enum(:each)
  end
end

#each_with_index(&block) ⇒ Object

Process the standard each_with_index operator.



72
73
74
75
76
77
78
79
# File 'lib/flex_array/flex_array_each.rb', line 72

def each_with_index(&block)
  if block_given?
    process_all {|index, posn| block.call(@array_data[posn], index)}
    self
  else
    self.to_enum(:each_with_index)
  end
end

#empty?Boolean

Is this flex array empty?

Returns:

  • (Boolean)


78
79
80
# File 'lib/flex_array.rb', line 78

def empty?
  length == 0
end

#find_index(value = nil, &block) ⇒ Object

The flex array version of find_index. This returns the coordinates of the first object that matches the search object or is flagged true by the search block.



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/flex_array/flex_array_each.rb', line 175

def find_index(value = nil, &block)
  blk = get_find_block(value, &block)

  if blk
    process_all do |index, posn|
      if blk.call(@array_data[posn])
        return index
      end
    end

    nil
  else
    self.to_enum(:find_index)
  end
end

#find_indexes(value = nil, &block) ⇒ Object

The improved flex array version of find_index. This returns the coordinates of objects that match the search object or are flagged true by the search block.



214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/flex_array/flex_array_each.rb', line 214

def find_indexes(value = nil, &block)
  blk, result = get_find_block(value, &block), []

  if blk
    process_all do |index, posn|
      if blk.call(@array_data[posn])
        result << index.dup
      end
    end

    result
  else
    self.to_enum(:find_indexes)
  end
end

#flatten_collectObject



117
# File 'lib/flex_array/flex_array_each.rb', line 117

alias_method :flatten_collect, :collect

#lengthObject Also known as: size

The total number of elements in this array.



43
44
45
# File 'lib/flex_array.rb', line 43

def length
  @array_specs.spec_count
end

#limitsObject

Get the limits of the subscripts of the flex array.



58
59
60
# File 'lib/flex_array.rb', line 58

def limits
  @array_specs.collect {|spec| spec.range }
end

#reshape(array_specs) ⇒ Object

Return a copy of this flex array, recast in a new shape, dropping or repeating data elements as required.



6
7
8
9
# File 'lib/flex_array/flex_array_reshape.rb', line 6

def reshape(array_specs)
  iterator = @array_data.cycle
  FlexArray.new(array_specs) {iterator.next}
end

#reshape!(array_specs) ⇒ Object

Recast this flex array in a new shape, dropping or repeating data elements as required.



13
14
15
16
17
# File 'lib/flex_array/flex_array_reshape.rb', line 13

def reshape!(array_specs)
  temp = self.reshape(array_specs)
  @array_specs, @array_data = temp.array_specs, temp.array_data
  self
end

#select_collect(indexes, &block) ⇒ Object

The flex array version of collect that accepts an optional set of indexes to select the data being collected into a flex array.



127
128
129
130
# File 'lib/flex_array/flex_array_each.rb', line 127

def select_collect(indexes, &block)
  result = self.dup
  result.select_collect!(indexes, &block)
end

#select_collect!(indexes, &block) ⇒ Object

The enhanced flex array version of collect! that accepts a set of indexes to select the data being collected.



162
163
164
165
166
167
168
169
170
# File 'lib/flex_array/flex_array_each.rb', line 162

def select_collect!(indexes, &block)
  fail ArgumentError, "A block is required." unless block_given?
  validate_index_count(indexes)

  process_indexes(indexes) {|_index, posn| @array_data[posn] =
    block.call(@array_data[posn])}

  self
end

#select_cycle(indexes, count = FOREVER, &block) ⇒ Object

Retrieve data from a subset of the flex array endlessly repeating as needed.



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/flex_array/flex_array_each.rb', line 26

def select_cycle(indexes, count = FOREVER, &block)
  validate_index_count(indexes)

  if block_given?
    unless empty?
      count.times do
        process_indexes(indexes) do |_index, posn|
          block.call(@array_data[posn])
        end
      end
    end

    nil
  else
    self.to_enum(:select_cycle, indexes, count)
  end
end

#select_each(indexes, &block) ⇒ Object

Process the enhanced select_each operator.



60
61
62
63
64
65
66
67
68
69
# File 'lib/flex_array/flex_array_each.rb', line 60

def select_each(indexes, &block)
  validate_index_count(indexes)

  if block_given?
    process_indexes(indexes) {|_index, posn| block.call(@array_data[posn])}
    self
  else
    self.to_enum(:select_each, indexes)
  end
end

#select_each_with_index(indexes, &block) ⇒ Object

Process the enhanced select_each_with_index operator.



82
83
84
85
86
87
88
89
90
91
# File 'lib/flex_array/flex_array_each.rb', line 82

def select_each_with_index(indexes, &block)
  validate_index_count(indexes)

  if block_given?
    process_indexes(indexes) {|index, posn| block.call(@array_data[posn], index)}
    self
  else
    self.to_enum(:select_each_with_index, indexes)
  end
end

#select_find_index(indexes, value = nil, &block) ⇒ Object

The enhanced flex array version of find_index. This returns the coordinates of the first object that matches the search object or is flagged true by the search block.



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/flex_array/flex_array_each.rb', line 194

def select_find_index(indexes, value = nil, &block)
  validate_index_count(indexes)
  blk = get_find_block(value, &block)

  if blk
    process_indexes(indexes) do |index, posn|
      if blk.call(@array_data[posn])
        return index
      end
    end

    nil
  else
    self.to_enum(:select_find_index, indexes)
  end
end

#select_find_indexes(indexes, value = nil, &block) ⇒ Object

The enhanced and improved flex array version of find_index. This returns the coordinates of objects that match the search object or are flagged true by the search block.



233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/flex_array/flex_array_each.rb', line 233

def select_find_indexes(indexes, value = nil, &block)
  validate_index_count(indexes)
  blk, result = get_find_block(value, &block), []

  if blk
    process_indexes(indexes) do |index, posn|
      if blk.call(@array_data[posn])
        result << index.dup
      end
    end

    result
  else
    self.to_enum(:select_find_index, indexes)
  end
end

#select_flatten_collect(indexes, &block) ⇒ Object

The flex array version of collect that accepts an optional set of indexes to select the data being collected into a standard array.



134
135
136
137
138
139
140
141
142
143
144
# File 'lib/flex_array/flex_array_each.rb', line 134

def select_flatten_collect(indexes, &block)
  validate_index_count(indexes)

  if block_given?
    result = []
    process_indexes(indexes) {|_index, posn| result << block.call(@array_data[posn])}
    result
  else
    self.to_enum(:select_collect, indexes)
  end
end

#shallow_dupObject



17
# File 'lib/flex_array/flex_array_new.rb', line 17

alias_method :shallow_dup, :dup

#to_aObject

Convert the flex array to a simple array. Contained arrays are not affected.



20
21
22
23
24
25
26
27
# File 'lib/flex_array/flex_array_reshape.rb', line 20

def to_a
  if @transposed
    fetch = self.cycle
    Array.new(@array_data.length) { fetch.next }
  else
    @array_data.dup
  end
end

#to_flex_arrayObject

Return this flex array as a flex array!



63
64
65
# File 'lib/flex_array.rb', line 63

def to_flex_array
  self
end

#transpose(dim_a, dim_b) ⇒ Object

Return a reference to this array’s data with the specified dimensions transposed. This may change the “shape” of the array if the transposed dimensions were of different limits.



17
18
19
# File 'lib/flex_array/flex_array_transpose.rb', line 17

def transpose(dim_a, dim_b)
  FlexArray.new_from_array(self).transpose!(dim_a, dim_b)
end

#transpose!(dim_a, dim_b) ⇒ Object

Transpose the specified dimensions. This may change the “shape” of the array if the transposed dimensions were of different limits.



6
7
8
9
10
11
12
# File 'lib/flex_array/flex_array_transpose.rb', line 6

def transpose!(dim_a, dim_b)
  validate_dimension(dim_a)
  validate_dimension(dim_b)
  @array_specs[dim_a], @array_specs[dim_b] = @array_specs[dim_b], @array_specs[dim_a]
  @transposed = @array_specs.transposed?
  self
end

#versionObject

The version of the class of this instance.



32
33
34
# File 'lib/flex_array.rb', line 32

def version
  FlexArray::VERSION
end