Class: SleepingKingStudios::Tools::ArrayTools

Inherits:
Base
  • Object
show all
Defined in:
lib/sleeping_king_studios/tools/array_tools.rb

Overview

Tools for working with array-like enumerable objects.

Constant Summary collapse

ARRAY_METHODS =

Expected methods that an Array-like object should implement.

%i[[] count each].freeze
OTHER_METHODS =

Methods that an Array-like object should not implement.

%i[each_key each_pair].freeze

Instance Method Summary collapse

Methods inherited from Base

instance

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.



33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/sleeping_king_studios/tools/array_tools.rb', line 33

def array?(ary)
  return true if ary.is_a?(Array)

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

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

  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.



69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/sleeping_king_studios/tools/array_tools.rb', line 69

def bisect(ary)
  require_array! ary

  raise ArgumentError, 'no block given' unless block_given?

  selected = []
  rejected = []

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

  [selected, rejected]
end

#count_values(ary) ⇒ Hash{Object, Integer} #count_values(ary) {|item| ... } ⇒ Hash{Object, Integer} Also known as: tally

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.



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

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
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.



131
132
133
134
135
# File 'lib/sleeping_king_studios/tools/array_tools.rb', line 131

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.



140
141
142
143
144
145
146
# File 'lib/sleeping_king_studios/tools/array_tools.rb', line 140

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)

    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.



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/sleeping_king_studios/tools/array_tools.rb', line 188

def humanize_list(ary, **options, &block)
  require_array! ary

  return '' if ary.empty?

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

  return ary[0].to_s if size == 1

  separator, last_separator =
    options_for_humanize_list(size: size, **options)

  return "#{ary[0]}#{last_separator}#{ary[1]}" if size == 2

  "#{ary[0...-1].join(separator)}#{last_separator}#{ary.last}"
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:



214
215
216
217
218
219
220
221
222
# File 'lib/sleeping_king_studios/tools/array_tools.rb', line 214

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:



231
232
233
# File 'lib/sleeping_king_studios/tools/array_tools.rb', line 231

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, 'zweihander'
#=> []
values
#=> ['longsword', 'zweihander', '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.



271
272
273
274
275
276
277
278
279
280
281
# File 'lib/sleeping_king_studios/tools/array_tools.rb', line 271

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

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

  ary[range] = insert

  deleted
end