Module: SleepingKingStudios::Tools::ArrayTools

Extended by:
ArrayTools
Included in:
ArrayTools
Defined in:
lib/sleeping_king_studios/tools/array_tools.rb

Overview

Tools for working with array-like enumerable objects.

Constant Summary collapse

ARRAY_METHODS =
[:[], :count, :each].freeze
OTHER_METHODS =
[:each_key, :each_pair].freeze

Instance Method Summary collapse

Instance Method Details

#array?(ary) ⇒ Boolean

Returns true if the object is or appears to be an Array.

Parameters:

  • ary (Object)

    The object to test.

Returns:

  • (Boolean)

    True if the object is an Array, otherwise false.



19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/sleeping_king_studios/tools/array_tools.rb', line 19

def array? ary
  return true if Array === ary

  ARRAY_METHODS.each do |method_name|
    return false unless ary.respond_to?(method_name)
  end # each

  OTHER_METHODS.each do |method_name|
    return false if ary.respond_to?(method_name)
  end # each

  true
end

#bisect(ary) {|item| ... } ⇒ Array<Array<Object>>

Separates the array into two arrays, the first containing all items in the original array that matches the provided block, and the second containing all items in the original array that do not match the provided block.

Examples:

selected, rejected = ArrayTools.bisect([*0...10]) { |item| item.even? }
selected
#=> [0, 2, 4, 6, 8]
rejected
#=> [1, 3, 5, 7, 9]

Parameters:

  • ary (Array<Object>)

    The array to bisect.

Yield Parameters:

  • item (Object)

    An item in the array to matched.

Yield Returns:

  • (Boolean)

    True if the item matches the criteria, otherwise false.

Returns:

  • (Array<Array<Object>>)

    An array containing two arrays.

Raises:

  • ArgumentError If the first argument is not an Array-like object or if no block is given.



55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/sleeping_king_studios/tools/array_tools.rb', line 55

def bisect ary, &block
  require_array! ary

  raise ArgumentError.new('no block given') unless block_given?

  selected, rejected = [], []

  ary.each do |item|
    (yield(item) ? selected : rejected) << item
  end # each

  [selected, rejected]
end

#count_values(ary) ⇒ Hash{Object, Integer} #count_values(ary) {|item| ... } ⇒ Hash{Object, Integer}

Overloads:

  • #count_values(ary) ⇒ Hash{Object, Integer}

    Counts the number of times each value appears in the enumerable object.

    Examples:

    ArrayTools.count_values([1, 1, 1, 2, 2, 3])
    #=> { 1 => 3, 2 => 2, 3 => 1 }
    

    Parameters:

    • ary (Array<Object>)

      The values to count.

    Returns:

    • (Hash{Object, Integer})

      The number of times each value appears in the enumerable object.

    Raises:

    • ArgumentError If the first argument is not an Array-like object.

  • #count_values(ary) {|item| ... } ⇒ Hash{Object, Integer}

    Calls the block with each item and counts the number of times each result appears.

    Examples:

    ArrayTools.count_values([1, 1, 1, 2, 2, 3]) { |i| i ** 2 }
    #=> { 1 => 3, 4 => 2, 9 => 1 }
    

    Parameters:

    • ary (Array<Object>)

      The values to count.

    Yield Parameters:

    • item (Object)

      An item in the array to matched.

    Returns:

    • (Hash{Object, Integer})

      The number of times each result appears.

    Raises:

    • ArgumentError If the first argument is not an Array-like object.



99
100
101
102
103
104
105
106
107
# File 'lib/sleeping_king_studios/tools/array_tools.rb', line 99

def count_values ary, &block
  require_array! ary

  ary.each.with_object({}) do |item, hsh|
    value = block_given? ? block.call(item) : item

    hsh[value] = hsh.fetch(value, 0) + 1
  end # each
end

#deep_dup(ary) ⇒ Array

Creates a deep copy of the object by returning a new Array with deep copies of each array item.

Parameters:

  • ary (Array<Object>)

    The array to copy.

Returns:

  • (Array)

    The copy of the array.



115
116
117
118
119
# File 'lib/sleeping_king_studios/tools/array_tools.rb', line 115

def deep_dup ary
  require_array! ary

  ary.map { |obj| ObjectTools.deep_dup obj }
end

#deep_freeze(ary) ⇒ Object

Freezes the array and performs a deep freeze on each array item.

Parameters:

  • ary (Array)

    The object to freeze.



124
125
126
127
128
129
130
# File 'lib/sleeping_king_studios/tools/array_tools.rb', line 124

def deep_freeze ary
  require_array! ary

  ary.freeze

  ary.each { |obj| ObjectTools.deep_freeze obj }
end

#humanize_list(ary, options = {}, &block) ⇒ String

Accepts a list of values and returns a human-readable string of the values, with the format based on the number of items.

Examples:

With Zero Items

ArrayTools.humanize_list([])
#=> ''

With One Item

ArrayTools.humanize_list(['spam'])
#=> 'spam'

With Two Items

ArrayTools.humanize_list(['spam', 'eggs'])
#=> 'spam and eggs'

With Three Or More Items

ArrayTools.humanize_list(['spam', 'eggs', 'bacon', 'spam'])
#=> 'spam, eggs, bacon, and spam'

With Three Or More Items And Options

ArrayTools.humanize_list(['spam', 'eggs', 'bacon', 'spam'], :last_separator => ' or ')
#=> 'spam, eggs, bacon, or spam'

Parameters:

  • ary (Array<String>)

    The list of values to format. Will be coerced to strings using #to_s.

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

    Optional configuration hash.

Options Hash (options):

  • :last_separator (String)

    The value to use to separate the final pair of values. Defaults to “ and ” (note the leading and trailing spaces). Will be combined with the :separator for lists of length 3 or greater.

  • :separator (String)

    The value to use to separate pairs of values before the last in lists of length 3 or greater. Defaults to “, ” (note the trailing space).

Returns:

  • (String)

    The formatted string.

Raises:

  • ArgumentError If the first argument is not an Array-like object.



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/sleeping_king_studios/tools/array_tools.rb', line 169

def humanize_list ary, options = {}, &block
  require_array! ary

  ary = ary.map(&block) if block_given?

  separator = options.fetch(:separator, ', ')
  last_separator = options.fetch(:last_separator, ' and ')

  case ary.count
  when 0
    ''
  when 1
    ary.first.to_s
  when 2
    "#{ary[0]}#{last_separator}#{ary[1]}"
  else
    if last_separator =~ /\A,?\s*/
      last_separator = last_separator.sub /\A,?\s*/, separator
    else
      last_separator = "#{separator}#{last_separator}"
    end # if-else

    "#{ary[0...-1].join(separator)}#{last_separator}#{ary.last}"
  end # case
end

#immutable?(ary) ⇒ Boolean

Returns true if the array is immutable, i.e. the array is frozen and each array item is immutable.

Parameters:

  • ary (Array)

    The array to test.

Returns:

  • (Boolean)

    True if the array is immutable, otherwise false.

See Also:



203
204
205
206
207
208
209
210
211
# File 'lib/sleeping_king_studios/tools/array_tools.rb', line 203

def immutable? ary
  require_array! ary

  return false unless ary.frozen?

  ary.each { |item| return false unless ObjectTools.immutable?(item) }

  true
end

#mutable?(ary) ⇒ Boolean

Returns true if the array is mutable.

Parameters:

  • ary (Array)

    The array to test.

Returns:

  • (Boolean)

    True if the array is mutable, otherwise false.

See Also:



220
221
222
# File 'lib/sleeping_king_studios/tools/array_tools.rb', line 220

def mutable? ary
  !immutable?(ary)
end

#splice(ary, start, delete_count, *insert) ⇒ Array<Object>

Accepts an array, a start value, a number of items to delete, and zero or more items to insert at that index. Deletes the specified number of items, then inserts the given items at the index and returns the array of deleted items.

Examples:

Deleting items from an Array

values = %w(katana wakizashi tachi daito shoto)
ArrayTools.splice values, 1, 2
#=> ['wakizashi', 'tachi']
values
#=> ['katana', 'daito', 'shoto']

Inserting items into an Array

values = %w(longsword broadsword claymore)
ArrayTools.splice values, 1, 0, 'zweihänder'
#=> []
values
#=> ['longsword', 'zweihänder', 'broadsword', 'claymore']

Inserting and deleting items

values = %w(shortbow longbow crossbow)
ArrayTools.splice values, 2, 1, 'arbalest', 'chu-ko-nu'
#=> ['crossbow']
values
#=> ['shortbow', 'longbow', 'arbalest', 'chu-ko-nu']

Parameters:

  • ary (Array<Object>)

    The array to splice.

  • start (Integer)

    The starting index to delete or insert values from or into. If negative, counts backward from the end of the array.

  • delete_count (Integer)

    The number of items to delete.

  • insert (Array<Object>)

    The items to insert, if any.

Returns:

  • (Array<Object>)

    The deleted items, or an empty array if no items were deleted.

Raises:

  • ArgumentError If the first argument is not an Array-like object.



260
261
262
263
264
265
266
267
268
269
270
# File 'lib/sleeping_king_studios/tools/array_tools.rb', line 260

def splice ary, start, delete_count, *insert
  require_array! ary

  start   = start < 0 ? start + ary.count : start
  range   = start...(start + delete_count)
  deleted = ary[range]

  ary[range] = insert

  deleted
end