Class: Functional::Catalog

Inherits:
Object show all
Includes:
Enumerable
Defined in:
lib/functional/catalog.rb

Overview

A collection of key/value pairs similar to a hash but ordered. Access is via index (like an array) rather than by key (like a hash). Supports duplicate keys. Indexing starts at zero.

Direct Known Subclasses

Catalogue

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data = nil, opts = {}) ⇒ Catalog

Create a new Catalog from the given data. When data is nil or an empty collection the resulting Catalog will be empty. When data is an array, hash, or catalog array the appropriate #from_ factory method will be called. The :from option is used to indicate the type of the source data.

If a block is given each value in the from the source array will be passed to the block and the result will be stored as the value in the Catalog.

Parameters:

  • data (Array, Hash, Catalog) (defaults to: nil)

    the data to construct the Catalog from

  • opts (Hash) (defaults to: {})

    processing options

Options Hash (opts):

  • :from (Symbol)

    the type of the data source. Valid values are :catalog/:catalogue, :hash, :array (default :catalog).



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/functional/catalog.rb', line 25

def initialize(data=nil, opts={})

  if block_given?

    @data = []
    data.each do |item|
      @data << yield(item)
    end

  else
    from = opts[:from]
    from = :array if [:set, :list, :stack, :queue, :vector].include?(from)
    from = "from_#{from}".to_sym

    if Catalog.respond_to?(from)
      @data = Catalog.send(from, data)
      @data = @data.instance_variable_get(:@data)
    elsif opts[:from].nil? && !data.nil?
      @data = Catalog.from_catalog(data)
      @data = @data.instance_variable_get(:@data)
    else
      @data = []
    end
  end
end

Class Method Details

.from_array(*args) ⇒ Object

Creates a new catalog object from an array. Each successive pair of elements will become a key/value pair in the new Catalog. If the source array has an odd number of elements the last element will be discarded. If a block is given each element in the source array will be passed to the block and the result will be stored in the new Catalog.



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/functional/catalog.rb', line 71

def self.from_array(*args)
  collected = []
  data = args.flatten

  max = ((data.size % 2 == 0) ? data.size-1 : data.size-2)
  (0..max).step(2) do |index|
    key = block_given? ? yield(data[index]) : data[index]
    value = block_given? ? yield(data[index+1]) : data[index+1]
    collected << [key, value]
  end

  catalog = Catalog.new
  catalog.instance_variable_set(:@data, collected)
  return catalog
end

.from_catalog(data, *args) ⇒ Object Also known as: from_catalogue

Creates a new Catalog object from an array of key/value pairs. Each key/value pair in the source array will be stored in the new Catalog. If a block is given each value in the from the source array will be passed to the block and the result will be stored as the value in the Catalog.



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/functional/catalog.rb', line 92

def self.from_catalog(data, *args)
  collected = []

  if args.empty? && data.size == 2 && !data.first.is_a?(Array)
    # Catalog.from_catalog([:one, 1])
    data = [data]
  elsif !args.empty?
    #Catalog.from_catalog([:one, 1], [:two, 2], [:three, 3])
    data = [data] + args
  end

  data.each do |item|
    if block_given?
      collected << [item.first, yield(item.last)]
    else
      collected << item
    end
  end
  
  catalog = Catalog.new
  catalog.instance_variable_set(:@data, collected)
  return catalog
end

.from_hash(data = {}) ⇒ Object

Creates a new Catalog object from a hash. Each key/value pair in the hash will be converted to a key/value array in the new Catalog. If a block is given each value in the array will be passed to the block and the result will be stored as the value in the Catalog.



55
56
57
58
59
60
61
62
63
64
# File 'lib/functional/catalog.rb', line 55

def self.from_hash(data = {})
  collected = []
  data.each do |key, value|
    value = yield(value) if block_given?
    collected << [key, value]
  end
  catalog = Catalog.new
  catalog.instance_variable_set(:@data, collected)
  return catalog
end

Instance Method Details

#&(other) ⇒ Object Also known as: intersection

Set Intersection—Returns a new array containing elements common to the two arrays, with no duplicates.



214
215
216
217
218
219
220
221
# File 'lib/functional/catalog.rb', line 214

def &(other)
  other = other.instance_variable_get(:@data) if other.is_a?(Catalog)
  if other.is_a? Array
    return Catalog.from_catalog(@data & other)
  else
    raise TypeError.new("can't convert #{other.class} into Catalog")
  end
end

#+(other) ⇒ Object Also known as: add, sum

together to produce a third array.



227
228
229
230
231
232
233
234
# File 'lib/functional/catalog.rb', line 227

def +(other)
  other = other.instance_variable_get(:@data) if other.is_a?(Catalog)
  if other.is_a? Array
    return Catalog.from_catalog(@data + other)
  else
    raise TypeError.new("can't convert #{other.class} into Catalog")
  end
end

#<=>(other) ⇒ Object Also known as: compare, compare_to

Comparison—Returns an integer (-1, 0, or +1) if this array is less than, equal to, or greater than other_ary. Each object in each array is compared (using <=>). If any value isn’t equal, then that inequality is the return value. If all the values found are equal, then the return is based on a comparison of the array lengths. Thus, two arrays are “equal” according to Array#<=> if and only if they have the same length and the value of each element is equal to the value of the corresponding element in the other array.



168
169
170
171
172
173
174
175
# File 'lib/functional/catalog.rb', line 168

def <=>(other)
  other = other.instance_variable_get(:@data) if other.is_a?(Catalog)
  if other.is_a? Array
    return @data <=> other
  else
    raise TypeError.new("can't convert #{other.class} into Catalog")
  end
end

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

Equality—Two arrays are equal if they contain the same number of elements and if each element is equal to (according to Object.==) the corresponding element in the other array.



148
149
150
151
152
153
154
155
156
# File 'lib/functional/catalog.rb', line 148

def ==(other)
  if other.is_a? Catalog
    return (@data == other.instance_variable_get(:@data))
  elsif other.is_a? Array
    return (@data == other)
  else
    return false
  end
end

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

Returns a new array populated with the given objects.



181
182
183
184
# File 'lib/functional/catalog.rb', line 181

def [](index)
  datum = @data[index]
  return (datum.nil? ? nil : datum.dup)
end

#[]=(index, value) ⇒ Object

Element Assignment—Sets the element at index, or replaces a subarray starting at start and continuing for length elements, or replaces a subarray specified by range. If indices are greater than the current capacity of the array, the array grows automatically. A negative indices will count backward from the end of the array. Inserts elements if length is zero. An IndexError is raised if a negative index points past the beginning of the array. See also Array#push, and Array#unshift.



195
196
197
198
199
200
201
202
203
204
205
# File 'lib/functional/catalog.rb', line 195

def []=(index, value)
  if (index >= 0 && index >= @data.size) || (index < 0 && index.abs > @data.size)
    raise ArgumentError.new('index must reference an existing element')
  elsif value.is_a?(Hash) && value.size == 1
    @data[index] = [value.keys.first, value.values.first]
  elsif value.is_a?(Array) && value.size == 2
    @data[index] = value.dup
  else
    raise ArgumentError.new('value must be a one-element hash or a two-element array')
  end
end

#delete(key, value = nil) ⇒ Object

Deletes items from self that are equal to obj. If the item is not found, returns nil. If the optional code block is given, returns the result of block if the item is not found.



447
448
449
450
451
452
453
454
455
456
457
458
459
460
# File 'lib/functional/catalog.rb', line 447

def delete(key, value=nil)
  item = nil

  if key && value
    item = @data.delete([key, value])
  elsif key.is_a? Array
    item = @data.delete(key)
  elsif key.is_a? Hash
    item = @data.delete([key.keys.first, key.values.first])
  end

  item = yield if item.nil? && block_given?
  return item
end

#delete_at(index) ⇒ Object

Deletes the element at the specified index, returning that element, or nil if the index is out of range. See also Array#slice!.



464
465
466
467
468
# File 'lib/functional/catalog.rb', line 464

def delete_at(index)
  item = @data.delete_at(index)
  item = yield if item.nil? && block_given?
  return item
end

#delete_if(&block) ⇒ Object

Deletes every element of self for which block evaluates to true.

Raises:

  • (ArgumentError)


471
472
473
474
475
476
477
478
479
480
481
482
483
# File 'lib/functional/catalog.rb', line 471

def delete_if(&block)
  raise ArgumentError.new('no block supplied') unless block_given?
  if block.arity <= 1
    items = @data.delete_if(&block)
  else
    items = []
    @data.each do |key, value|
      items << [key, value] if yield(key, value)
    end
    items.each {|item| @data.delete(item)}
  end
  return self
end

#each(&block) ⇒ Object

Calls block once for each key in hsh, passing the key and value to the block as a two-element array. Because of the assignment semantics of block parameters, these elements will be split out if the block has two formal parameters. Also see Hash.each_pair, which will be marginally more efficient for blocks with two parameters.



308
309
310
311
312
# File 'lib/functional/catalog.rb', line 308

def each(&block)
  @data.each do |item|
    yield(item)
  end
end

#each_key(&block) ⇒ Object

Calls block once for each key in hsh, passing the key as a parameter.



322
323
324
325
326
# File 'lib/functional/catalog.rb', line 322

def each_key(&block)
  @data.each do |item|
    yield(item.first)
  end
end

#each_pair(&block) ⇒ Object

Calls block once for each key in hsh, passing the key and value as parameters.



315
316
317
318
319
# File 'lib/functional/catalog.rb', line 315

def each_pair(&block)
  @data.each do |item|
    yield(item.first, item.last)
  end
end

#each_value(&block) ⇒ Object

Calls block once for each key in hsh, passing the value as a parameter.



329
330
331
332
333
# File 'lib/functional/catalog.rb', line 329

def each_value(&block)
  @data.each do |item|
    yield(item.last)
  end
end

#empty?Boolean

Returns true if self array contains no elements.

Returns:

  • (Boolean)


121
122
123
# File 'lib/functional/catalog.rb', line 121

def empty?
  size == 0
end

#firstObject

Returns the first element, or the first n elements, of the array. If the array is empty, the first form returns nil, and the second form returns an empty array.



135
136
137
# File 'lib/functional/catalog.rb', line 135

def first
  @data.first
end

#include?(key = nil, value = nil) ⇒ Boolean

Returns true if the given object is present in self (that is, if any object == anObject), false otherwise.

Returns:

  • (Boolean)


337
338
339
340
341
342
343
344
345
346
347
# File 'lib/functional/catalog.rb', line 337

def include?(key=nil, value=nil)
  if key && value
    return @data.include?([key, value])
  elsif key.is_a?(Array)
    return @data.include?(key)
  elsif key.is_a?(Hash) && key.size == 1
    return @data.include?([key.keys.first, key.values.first])
  else
    return false
  end
end

#keysObject

Returns a new array populated with the keys from this hash. See also Hash#values.



292
293
294
# File 'lib/functional/catalog.rb', line 292

def keys
  return @data.collect{|item| item.first}
end

#lastObject

Returns the last element(s) of self. If the array is empty, the first form returns nil.



141
142
143
# File 'lib/functional/catalog.rb', line 141

def last
  @data.last
end

#lengthObject Also known as: size

Returns the number of elements in self. May be zero.



126
127
128
# File 'lib/functional/catalog.rb', line 126

def length
  @data.length
end

#peekObject

Copies the last element from self and returns it, or nil if the Catalog is empty.



282
283
284
285
286
287
288
# File 'lib/functional/catalog.rb', line 282

def peek
  if self.empty?
    return nil
  else
    return @data.last.dup
  end
end

#popObject

Removes the last element from self and returns it, or nil if the Catalog is empty.



272
273
274
275
276
277
278
# File 'lib/functional/catalog.rb', line 272

def pop
  if self.empty?
    return nil
  else
    return @data.pop
  end
end

#push(item) ⇒ Object Also known as: <<, append

Append—Pushes the given object(s) on to the end of this array. This expression returns the array itself, so several appends may be chained together.



255
256
257
258
259
260
261
262
263
264
265
# File 'lib/functional/catalog.rb', line 255

def push(item)
  if item.is_a?(Hash) && item.size == 1
    @data << [item.keys.first, item.values.first]
    return self
  elsif item.is_a?(Array) && item.size == 2
    @data << item
    return self
  else
    raise TypeError.new("can't convert #{item.class} into Catalog")
  end
end

#slice(index, length = nil) ⇒ Object

Element Reference—Returns the element at index, or returns a subarray starting at start and continuing for length elements, or returns a subarray specified by range. Negative indices count backward from the end of the array (-1 is the last element). Returns nil if the index (or starting index) are out of range.



354
355
356
357
358
359
360
361
# File 'lib/functional/catalog.rb', line 354

def slice(index, length=nil)
  if length.nil?
    catalog = @data.slice(index)
  else
    catalog = @data.slice(index, length)
  end
  return Catalog.new(catalog)
end

#slice!(index, length = nil) ⇒ Object

Deletes the element(s) given by an index (optionally with a length) or by a range. Returns the deleted object, subarray, or nil if the index is out of range.



366
367
368
369
370
371
372
373
# File 'lib/functional/catalog.rb', line 366

def slice!(index, length=nil)
  if length.nil?
    catalog = @data.slice!(index)
  else
    catalog = @data.slice!(index, length)
  end
  return Catalog.new(catalog)
end

#sort(&block) ⇒ Object

Returns a new array created by sorting self. Comparisons for the sort will be done using the <=> operator or using an optional code block. The block implements a comparison between a and b, returning -1, 0, or +1. See also Enumerable#sort_by.



405
406
407
408
# File 'lib/functional/catalog.rb', line 405

def sort(&block)
  sorted = @data.sort(&block)
  return Catalog.new(sorted)
end

#sort!(&block) ⇒ Object

Sorts self. Comparisons for the sort will be done using the <=> operator or using an optional code block. The block implements a comparison between a and b, returning -1, 0, or +1. See also Enumerable#sort_by.



414
415
416
417
# File 'lib/functional/catalog.rb', line 414

def sort!(&block)
  sorted = @data.sort!(&block)
  return self
end

#sort_by_keyObject

Return a new Catalog created by sorting self according to the natural sort order of the keys.



377
378
379
380
# File 'lib/functional/catalog.rb', line 377

def sort_by_key
  sorted = @data.sort{|a, b| a.first <=> b.first}
  return Catalog.new(sorted)
end

#sort_by_key!Object

Sort self according to the natural sort order of the keys. Returns self.



383
384
385
386
# File 'lib/functional/catalog.rb', line 383

def sort_by_key!
  sorted = @data.sort!{|a, b| a.first <=> b.first}
  return self
end

#sort_by_valueObject

Return a new Catalog created by sorting self according to the natural sort order of the values.



390
391
392
393
# File 'lib/functional/catalog.rb', line 390

def sort_by_value
  sorted = @data.sort{|a, b| a.last <=> b.last}
  return Catalog.new(sorted)
end

#sort_by_value!Object

Sort self according to the natural sort order of the values. Returns self.



396
397
398
399
# File 'lib/functional/catalog.rb', line 396

def sort_by_value!
  sorted = @data.sort!{|a, b| a.last <=> b.last}
  return self
end

#to_aObject

Returns a new array that is a one-dimensional flattening of self.



420
421
422
# File 'lib/functional/catalog.rb', line 420

def to_a
  return @data.flatten
end

#to_catalogObject Also known as: to_catalogue

Returns a new array that is the dat equivalent of self where each key/value pair is an two-element array within the returned array.



438
439
440
# File 'lib/functional/catalog.rb', line 438

def to_catalog
  return @data.dup
end

#to_hashObject

Returns a new hash by converting each key/value pair in self into a key/value pair in the hash. When duplicate keys are encountered the last value associated with that key is kept and the others are discarded.



428
429
430
431
432
433
434
# File 'lib/functional/catalog.rb', line 428

def to_hash
  catalog = {}
  @data.each do |item|
    catalog[item.first] = item.last
  end
  return catalog
end

#to_sObject

Returns a string representation of Catalog.



208
209
210
# File 'lib/functional/catalog.rb', line 208

def to_s
  return @data.to_s
end

#valuesObject

Returns a new array populated with the values from hsh. See also Hash#keys.



298
299
300
# File 'lib/functional/catalog.rb', line 298

def values
  return @data.collect{|item| item.last}
end

#|(other) ⇒ Object Also known as: union

Set Union—Returns a new array by joining this array with other_array, removing duplicates.



241
242
243
244
245
246
247
248
# File 'lib/functional/catalog.rb', line 241

def |(other)
  other = other.instance_variable_get(:@data) if other.is_a?(Catalog)
  if other.is_a? Array
    return Catalog.from_catalog(@data | other)
  else
    raise TypeError.new("can't convert #{other.class} into Catalog")
  end
end