Class: MapWithIndifferentAccess::List

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
WrapsCollection
Defined in:
lib/map_with_indifferent_access/list.rb

Instance Attribute Summary collapse

Attributes included from WrapsCollection

#inner_collection

Class Method Summary collapse

Instance Method Summary collapse

Methods included from WrapsCollection

#_frozen?, #clear, #empty?, #eql?, #freeze, #frozen?, #hash, #length, #size, #taint, #tainted?, #trust, #untaint, #untrust, #untrusted?

Constructor Details

#initialize(basis = []) ⇒ List

Initializes a new instance of MapWithIndifferentAccess::List that encapsulates a new empty Array or the Array coerced from the given basis.

When a MapWithIndifferentAccess::List is given as a basis, this results on the given and new instances sharing the same #inner_array. There is no obvious reason to do that on purpose, but there is also no particular harm in allowing it to happen.

Parameters:

  • basis (Array, List, Object) (defaults to: []) —

    An Array or an object that can be implicitly coerced to an Array

Raises:

  • (ArgumentError)


77
78
79
80
81
82
83
# File 'lib/map_with_indifferent_access/list.rb', line 77

def initialize(basis = [])
  use_basis = basis
  use_basis = basis.inner_array if self.class === basis
  use_basis = ::Array.try_convert( use_basis )
  raise ArgumentError, "Could not convert #{basis.inspect} into an ::Array" unless use_basis
  @inner_collection = use_basis
end

Instance Attribute Details

#inner_array=(value) ⇒ Array

Alias for WrapsCollection#inner_collection. The encapsulated Array instance.

Returns:

  • (Array)


55
# File 'lib/map_with_indifferent_access/list.rb', line 55

alias inner_array inner_collection

Class Method Details

.try_convert(from_obj) ⇒ List?

Try to convert from_obj into a MapWithIndifferentAccess::List.

Returns:

  • (List) —

    converted object if from_obj is convertible.

  • (nil) —

    if from_obj cannot be converted for any reason.



22
23
24
25
26
27
28
29
# File 'lib/map_with_indifferent_access/list.rb', line 22

def self.try_convert(from_obj)
  if self === from_obj
    from_obj
  else
    array = ::Array.try_convert( from_obj )
    new( array ) if array
  end
end

.try_deconstruct(obj) ⇒ Array?

Try to convert obj, which might be a MapWithIndifferentAccess::List into an Array.

Returns:

  • (Array) —

    converted object if obj is convertible.

  • (nil) —

    if obj cannot be converted for any reason.



39
40
41
42
43
44
45
46
47
48
# File 'lib/map_with_indifferent_access/list.rb', line 39

def self.try_deconstruct(obj)
  if self === obj
    obj.inner_array
  elsif obj.respond_to?(:to_ary )
    a = obj.to_ary
    ::Array === a ? a : nil
  else
    nil
  end
end

Instance Method Details

#&(other) ⇒ List

Set Intersection. Returns a new MapWithIndifferentAccess::List containing elements common to the target MapWithIndifferentAccess::List and other (a List or other Array-like object), excluding any duplicate items. The order is preserved from the original list.

It compares elements using their #hash and #eql? methods for efficiency.

Note that this does not recongnize items of Map type as equal just because they are equal by #==, which can be the case when they have equivalent keys that differ by String/Symbol type. You might therefore wish to call #& for lists that have first had their keys deeply-stringified or deeply-symbolized.

Parameters:

  • other (List, Array, Object)

Returns:



# File 'lib/map_with_indifferent_access/list.rb', line 420

#*(n_copies) ⇒ Map #*(separator) ⇒ String

Repetition.

Overloads:

  • #*(n_copies) ⇒ Map

    Returns a new List built by concatenating n_copies copies of itself together.

    Returns:

  • #*(separator) ⇒ String

    Equivalent to target_list.join(separator).

    Returns:

    • (String)


529
530
531
532
533
# File 'lib/map_with_indifferent_access/list.rb', line 529

def *(n_copies_or_separator)
  result = inner_array * n_copies_or_separator
  result = List.new( result ) if Array === result
  result
end

#+(other) ⇒ List

Concatenation. Returns a new MapWithIndifferentAccess::List built by concatenating other (a List or other Array-like object) to the target List.

Parameters:

  • other (List, Array, Object)

Returns:

See Also:



# File 'lib/map_with_indifferent_access/list.rb', line 459

#-(other) ⇒ List

Difference. Returns a new MapWithIndifferentAccess::List that is a copy of the original, removing any items that also appear in other (a List or other Array-like object). The order is preserved from the original List.

It compares elements using their #hash and #eql? methods for efficiency.

Note that this does not recongnize items of Map type as equal just because they are equal by #==, which can be the case when they have equivalent keys that differ by String/Symbol type. You might therefore wish to call #- for lists that have first had their keys deeply-stringified or deeply-symbolized.

Parameters:

  • other (List, Array, Object)

Returns:



488
489
490
491
492
493
494
495
496
497
498
# File 'lib/map_with_indifferent_access/list.rb', line 488

%w( & | + - ).each do |method_name|
  class_eval <<-EOS, __FILE__, __LINE__ + 1

    def #{method_name}(other)
      other = self.class.try_deconstruct( other ) || other
      inner_result = inner_array.#{method_name}(other)
      List.new( inner_result )
    end

  EOS
end

#<<(value) ⇒ List

Append. Pushes the given object on to the end of the list. Returns the array itself, so several appends may be chained together.

Internalizes the given onject before appending it to the target's #inner_array.

Returns:

See Also:



213
214
215
216
217
# File 'lib/map_with_indifferent_access/list.rb', line 213

def <<(value)
  value = Values << value
  inner_array << value
  self
end

#<=>(other) ⇒ 1, ...

Comparison. Returns an integer (-1, 0, or +1) if this List is less than, equal to, or greater than other, and other is a List or other Array-like object that can be coerced to a List.

Each externaized item in the target List is compared to the corresponding externalized item in other (using the <=> operator). As soon as a comparison is non zero (i.e. the two corresponding elements are not equal), that result is returned for the whole array comparison.

If all the elements are equal, then the result is based on a comparison of the list lengths. Thus, two Lists are "equal" according to #<=> 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 list.

nil is returned if other is not a List or Arraylike object or if the comparison of two elements returns nil.

Parameters:

  • (List, Array, Object)

Returns:

  • (1, 0, -1, nil)

See Also:

  • Array#<=>


680
681
682
683
684
685
686
687
# File 'lib/map_with_indifferent_access/list.rb', line 680

def <=>(other)
  return nil unless \
    List === other || (
      other.respond_to?(:to_ary ) && other.respond_to?(:length )
    )
  other = Values >> other
  rel_order( other )
end

#==(other) ⇒ Boolean

Equality. The target is equal to the given Array-like object if both contain the same number of elements, and externalizations of corresponding items in itself and the given object are equal according to #==.

Returns:

  • (Boolean)

See Also:



643
644
645
646
647
648
649
650
651
652
653
654
# File 'lib/map_with_indifferent_access/list.rb', line 643

def ==(other)
  same_class = self.class === other

  return false unless same_class || other.respond_to?(:to_ary )

  # Optimizations
  return true if equal?( other )
  return true if same_class && inner_array == other.inner_array

  return false unless length == other.length
  zip( other ).all? { |(v,other_v)| v == Values >> other_v }
end

#[](index) ⇒ Object #[](start, length) ⇒ List #[](range) ⇒ List #slice(index) ⇒ Object #slice(start, length) ⇒ List #slice(range) ⇒ List

Returns the element at index, or returns a subarray starting at the start index and continuing for length elements, or returns a subarray specified by range of indices.

Externalizes the result before returning it.

Overloads:

  • #[](index) ⇒ Object

    Parameters:

    • index (Fixnum)

    Returns:

    • (Object)
  • #[](start, length) ⇒ List

    Parameters:

    • start (Fixnum)
    • length (Fixnum)

    Returns:

  • #[](range) ⇒ List

    Parameters:

    • range (Range)

    Returns:

  • #slice(index) ⇒ Object

    Parameters:

    • index (Fixnum)

    Returns:

    • (Object)
  • #slice(start, length) ⇒ List

    Parameters:

    • start (Fixnum)
    • length (Fixnum)

    Returns:

  • #slice(range) ⇒ List

    Parameters:

    • range (Range)

    Returns:

See Also:



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/map_with_indifferent_access/list.rb', line 172

['[]', 'slice'].each do |method_name|
  class_eval <<-EOS, __FILE__, __LINE__ + 1

    def #{method_name}(index, *maybe_length)
      arg_count = 1 + maybe_length.length
      unless (1..2) === arg_count
        raise ArgumentError, "wrong number of arguments (\#{arg_count} for 1..2)"
      end

      if !maybe_length.empty? || Range === index
        value_array = inner_array.#{method_name}( index, *maybe_length )
        value_array.map!{ |v| Values >> v }
        List.new( value_array )
      else
        value = inner_array.#{method_name}( index )
        Values >> value
      end
    end

  EOS
end

#[]=(index, value) ⇒ Object #[]=(start, length, array_or_value) ⇒ Object #[]=(range, array_or_value) ⇒ Object

Element Assignment — Sets the element at index, or replaces a subarray from the start index for length elements, or replaces a subarray specified by the range of indices.

The given object or array is internalized befor being ussed for assignment into the #inner_array.

Overloads:

  • #[]=(index, value) ⇒ Object

    Parameters:

    • index (Fixnum)
    • value (Object)
  • #[]=(start, length, array_or_value) ⇒ Object

    Parameters:

    • start (Fixnum)
    • length (Fixnum)
    • array_or_value (Array, List Object, nil)
  • #[]=(range, array_or_value) ⇒ Object

    Parameters:

    • range (Ramge)
    • array_or_value (Array, List, Object, nil)

Returns:

  • the given value or array.

See Also:



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/map_with_indifferent_access/list.rb', line 110

def []=(index, length_or_value, *maybe_value)
  arg_count = 2 + maybe_value.length
  unless (2..3) === arg_count
    raise ArgumentError, "wrong number of arguments (#{arg_count} for 2..3)"
  end

  if maybe_value.empty?
    maybe_length = []
    value_or_values = length_or_value
  else
    maybe_length = [length_or_value]
    value_or_values = maybe_value.first
  end

  if (
    ( !maybe_length.empty? || Range === index ) &&
    ( value_array = List.try_deconstruct( value_or_values ) )
  )
    value_array = value_array.map{ |v| Values << v }
    inner_array[ index, *maybe_length ] = value_array
  else
    value = Values << value_or_values
    inner_array[ index, *maybe_length ] = value
  end
end

#assoc(value) ⇒ List?

Searches through elements of the target List that are also externally represented as Lists, comparing the first item in each of those with value using #==.

Returns the first item from the target that matches (is the first associated List) or nil of no match is found.

Returns:

See Also:



# File 'lib/map_with_indifferent_access/list.rb', line 708

#at(index) ⇒ Object

Returns the externalization of the element at index. A negative index counts from the end of the list. Returns nil if the index is out of range.

See Also:



199
200
201
202
# File 'lib/map_with_indifferent_access/list.rb', line 199

def at(index)
  item = inner_array.at( index )
  Values >> item
end

#bsearch {|x| ... } ⇒ Object? #bsearch ⇒ Enumerator

Works identically to Array#bsearch except that externalized values are passed to the block, and the externalized result is returned.

Overloads:

  • #bsearch {|x| ... } ⇒ Object?

    Yield Parameters:

    • x

    Returns:

    • (Object, nil)
  • #bsearch ⇒ Enumerator

    Returns:

    • (Enumerator)


759
760
761
762
763
# File 'lib/map_with_indifferent_access/list.rb', line 759

def bsearch
  return to_enum(:bsearch) unless block_given?
  inner_result = inner_array.bsearch{ |x| yield Values >> x }
  Values >> inner_result
end

#collect! ⇒ List, Enumerable #map! ⇒ List, Enumerable

Invokes the given block once for each externalized item from the target List, replacing the element with the internalization of the value returned by the block.

If no block is given, returns an Enumerator instead.

Yield Parameters:

  • extern_item

Returns:

  • (List, Enumerable)

See Also:

  • Enumerable#collect


780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
# File 'lib/map_with_indifferent_access/list.rb', line 780

%w(collect! map!).each do |method_name|
  class_eval <<-EOS, __FILE__, __LINE__ + 1

    def #{method_name}
      return to_enum( :#{method_name} ) unless block_given?

      inner_array.#{method_name}{ |item|
        item = Values >> item
        mapped_outer = yield( item )
        Values << mapped_outer
      }
      self
    end

  EOS
end

#combination(n) {|combination| ... } ⇒ List #combination(n) ⇒ Enumerator

Yields every combination of length n of elements from the target List in the form of a List and then returns the target List itself.

Makes no guarantees about the order in which the combinations are yielded.

If no block is given, an Enumerator is returned instead.

Overloads:

  • #combination(n) {|combination| ... } ⇒ List

    Parameters:

    • n (Fixnum)

    Yield Parameters:

    • combination (List)

    Returns:

  • #combination(n) ⇒ Enumerator

    Parameters:

    • n (Fixnum)

    Returns:

    • (Enumerator)


814
815
816
817
818
819
820
821
# File 'lib/map_with_indifferent_access/list.rb', line 814

def combination(n)
  return to_enum( :combination, n ) unless block_given?

  inner_array.combination n do |inner_combos|
    yield List.new( inner_combos )
  end
  self
end

#compact ⇒ List

Returns a copy of the target List with all nil items removed.

Returns:

See Also:



841
842
843
844
845
# File 'lib/map_with_indifferent_access/list.rb', line 841

def compact
  result = dup
  result.compact!
  result
end

#compact! ⇒ List?

Removes nil elements from the target List.

Returns nil if no changes were made. Otherwise returns the List.

Returns:

See Also:



831
832
833
# File 'lib/map_with_indifferent_access/list.rb', line 831

def compact!
  inner_array.compact! && self
end

#concat(other) ⇒ List

Appends elements of other (a List or other Array-like object) to the target List.

Parameters:

  • other (List, Array, Object)

Returns:

  • (List) —

    The target list.

See Also:



280
281
282
283
284
# File 'lib/map_with_indifferent_access/list.rb', line 280

def concat(other)
  other = self.class.try_deconstruct(other) || other
  inner_array.concat other
  self
end

#delete(obj) ⇒ Object #delete(obj) { ... } ⇒ Object

Deletes all items from self, the externalizations of which are equal to the externalization of obj.

Returns the externalization of the last deleted item if applicable.

Overloads:

  • #delete(obj) ⇒ Object

    Returns nil if no matching items are found.

  • #delete(obj) { ... } ⇒ Object

    Returns the externalization of the block result is no matching items are found.

    Yields:

See Also:



550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
# File 'lib/map_with_indifferent_access/list.rb', line 550

def delete(obj)
  obj = Values >> obj
  removed_items = false
  result = nil
  inner_array.delete_if{ |v|
    v = Values >> v
    if v == obj
      result = v
      removed_items = true
      true
    end
  }
  if !removed_items && block_given?
    result = Values >> yield( obj )
  end
  result
end

#delete_at(index) ⇒ Object?

Deletes the element at the specified index, returning the externalization of that element, or nil if the index is out of range.

Parameters:

  • index (Fixnum)

Returns:

  • (Object, nil)

See Also:



415
416
417
418
# File 'lib/map_with_indifferent_access/list.rb', line 415

def delete_at(index)
  inner_result = inner_array.delete_at( index )
  Values >> inner_result
end

#each {|item| ... } ⇒ List #each ⇒ Enumerator

Calls the given block once for each item in the target's #inner_array, passing the externalization of the item to the block.

Overloads:

  • #each {|item| ... } ⇒ List

    Yield Parameters:

    • item

    Returns:

  • #each ⇒ Enumerator

    Returns:

    • (Enumerator)

See Also:



701
702
703
704
705
706
# File 'lib/map_with_indifferent_access/list.rb', line 701

def each
  inner_array.each do |item|
    item = Values >> item
    yield item
  end
end

#fetch(index) ⇒ Object #fetch(index, default) ⇒ Object #fetch(index) {|index| ... } ⇒ Object

Tries to retrieve the element at position index, but raises an IndexError exception or uses a default value when an invalid index is referenced.

Returns the externalization of the retrieved value.

Overloads:

  • #fetch(index) ⇒ Object

    Tries to retrieve the element at position index, but raises an IndexError exception if the referenced index lies outside of the array bounds.

    Raises:

    • (IndexError)
  • #fetch(index, default) ⇒ Object

    Tries to retrieve the element at position index, but uses the given default if the referenced index lies outside of the array bounds.

  • #fetch(index) {|index| ... } ⇒ Object

    Tries to retrieve the element at position index, but if the referenced index lies outside of the array bounds, calls the given block, and uses the block call result.

    Yield Parameters:

    • index

See Also:



323
324
325
326
327
328
329
330
331
# File 'lib/map_with_indifferent_access/list.rb', line 323

def fetch(index, *args)
  item =
    if block_given?
      inner_array.fetch( index, *args ){ |idx| yield idx }
    else
      inner_array.fetch( index, *args )
    end
  Values >> item
end

#first ⇒ Object



7
8
9
# File 'lib/map_with_indifferent_access/list.rb', line 7

def first
  self.at(0)
end

#insert(index, *values) ⇒ List

Inserts the given values before the element with the given index.

Internalizes the values before inserting them into the target's #inner_array.

Negative indices count backwards from the end of the array, where -1 is the last element. If a negative index is used, the given values will be inserted after that element, so using an index of -1 will insert the values at the end of the list.

Returns:

See Also:



267
268
269
270
271
# File 'lib/map_with_indifferent_access/list.rb', line 267

def insert(index, *values)
  values.map!{ |v| Values << v }
  inner_array.insert(index, *values)
  self
end

#join(separator = $,) ⇒ String

Returns a string consisting of String-converted item values from the target List separated by the separator string. If no separator or nil is given, uses the value of $, as the separator. Treats a nil $, value as a blank string.

The items are not externalized before being converted to Strings, so my_map.join is exactly equivalent to my_map.inner_array.join.

Parameters:

  • separator (String) (defaults to: $,)

Returns:

  • (String)

See Also:

  • Array#join


515
# File 'lib/map_with_indifferent_access/list.rb', line 515

def_delegator :inner_array, :join

#last ⇒ Object



11
12
13
# File 'lib/map_with_indifferent_access/list.rb', line 11

def last
  self.at(-1)
end

#pop ⇒ Object? #pop(n) ⇒ MapWithIndifferentAccess::List

Removes and returns the last element or last n elements of the array.

Returns the externalization of the removed element or array of elements

See #push for the opposite effect.

Overloads:

See Also:



387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
# File 'lib/map_with_indifferent_access/list.rb', line 387

%w(shift pop).each do |method_name|
  class_eval <<-EOS, __FILE__, __LINE__ + 1

    def #{method_name}(*maybe_n)
      arg_count = maybe_n.length
      unless (0..1) === arg_count
        raise ArgumentError, "wrong number of arguments (\#{arg_count} for 0..1)"
      end
      if maybe_n.empty?
        Values >> inner_array.#{method_name}
      else
        inner_result = inner_array.#{method_name}( *maybe_n )
        List.new( inner_result )
      end
    end

  EOS
end

#push(*values) ⇒ List

Append. Pushes the given object(s) on to the end of the list. Returns the array itself, so several appends may be chained together.

Internalizes each given object before appending it to the target's #inner_array.

Returns:

See Also:



230
231
232
233
234
# File 'lib/map_with_indifferent_access/list.rb', line 230

def push(*values)
  values.map!{ |v| Values << v }
  inner_array.push *values
  self
end

#rassoc(value) ⇒ List?

Searches through elements of the target List that are also externally represented as Lists, comparing the second item in each of those with value using #==.

Returns the first item from the target that matches (is the first associated List) or nil of no match is found.

Returns:

See Also:



734
735
736
737
738
739
740
741
742
743
744
745
746
747
# File 'lib/map_with_indifferent_access/list.rb', line 734

[ ['assoc', 0 ], ['rassoc', 1 ] ].each do |(method_name,search_col)|
  class_eval <<-EOS, __FILE__, __LINE__

    def #{method_name}(value)
      result = nil
      each do |item|
        next unless List === item && item.length > #{search_col}
        result = item if item[#{search_col}] == value
      end
      result
    end

  EOS
end

#shift ⇒ Object? #shift(n) ⇒ List

Removes and returns the first element or first n elements of the array, shifting all of the other elements downward.

Returns the externalization of the removed element or array of elements

See #unshift for the opposite effect.

Overloads:

  • #shift ⇒ Object?

    Removes the first element and returns it, shifting all other elements down by one. Returns nil if the array is empty.

    Returns:

    • (Object, nil)
  • #shift(n) ⇒ List

    Returns a MapWithIndifferentAccess::List of the first n elements (or less) just like array.slice!(0, n) does, but also removing those elements from the target.

    Returns:

See Also:



# File 'lib/map_with_indifferent_access/list.rb', line 333

#to_a ⇒ Object

Alias for WrapsCollection#inner_collection. Returns the encapsulated Array instance.



# File 'lib/map_with_indifferent_access/list.rb', line 57

#uniq ⇒ List

Returns a new instance with duplicate items omitted. Items are considered equal if their #hash values are equal and comparison using #eql? returns true.

If a block is given, then externalized items are passed to the block, and the return values from the block will be used for dupliacte-check comparison.

Note that items externally represented as Maps that are equal according to Map#== will not necessarily be identified as duplicates since they can still differ according to Map#eql if their encapsulated Hash objects are unequal due to key String/Symbol type differences. You might therefore want to ensure that the target List has been deeply stringified or symbolized before calling #uniq! on it.

Returns:

See Also:



588
589
590
591
592
593
594
595
596
# File 'lib/map_with_indifferent_access/list.rb', line 588

def uniq
  result = dup
  if block_given?
    result.uniq!{ |item| yield( item ) }
  else
    result.uniq!
  end
  result
end

#uniq! ⇒ List?

Deletes duplicate items from the target's #inner_array, leaving only unique items remaining. Items are considered equal if their #hash values are equal and comparison using #eql? returns true.

Returns the target List if any duplicates were found and removed. Otherwise, returns nil.

If a block is given, then externalized items are passed to the block, and the return values from the block will be used for dupliacte-check comparison.

Note that items externally represented as Maps that are equal according to Map#== will not necessarily be identified as duplicates since they can still differ according to Map#eql if their encapsulated Hash objects are unequal due to key String/Symbol type differences. You might therefore want to ensure that the target List has been deeply stringified or symbolized before calling #uniq on it.

Returns:

See Also:



622
623
624
625
626
627
628
629
630
631
632
633
# File 'lib/map_with_indifferent_access/list.rb', line 622

def uniq!
  inner_result = 
    if block_given?
      inner_array.uniq!{ |item|
        yield( Values >> item )
      }
    else
      inner_array.uniq!
    end

  inner_result && self
end

#unshift(*values) ⇒ List

Prepends objects to the front of the list, moving other elements upwards.

Internalizes each value before prepending it to the target's #inner_array.

See also #shift for the opposite effect.

Returns:

See Also:



247
248
249
250
251
# File 'lib/map_with_indifferent_access/list.rb', line 247

def unshift(*values)
  values.map!{ |v| Values << v }
  inner_array.unshift *values
  self
end

#values_at(*indexes) ⇒ Object

Returns a MapWithIndifferentAccess::List containing the elements in self corresponding to the given selector(s).

The selectors may be either Integer indices or Ranges.

Returns:

  • List



293
294
295
296
# File 'lib/map_with_indifferent_access/list.rb', line 293

def values_at(*indexes)
  inner_result = inner_array.values_at( *indexes )
  Values >> inner_result
end

#|(other) ⇒ List

Set Union. Returns a new MapWithIndifferentAccess::List by joining the target List with other (a List or other Array-like object), excluding any duplicates and preserving the order from the original List.

It compares elements using their #hash and #eql? methods for efficiency.

Note that this does not recongnize items of Map type as equal just because they are equal by #==, which can be the case when they have equivalent keys that differ by String/Symbol type. You might therefore wish to call #| for lists that have first had their keys deeply-stringified or deeply-symbolized.

Parameters:

  • other (List, Array, Object)

Returns:



# File 'lib/map_with_indifferent_access/list.rb', line 440