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 =
i[[] count each].freeze
OTHER_METHODS =
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.



30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/sleeping_king_studios/tools/array_tools.rb', line 30

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]

Yield Parameters:

  • item (Object)

    An item in the array to matched.

Yield Returns:

  • (Boolean)

    True if the item matches the criteria, otherwise false.

Raises:

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



66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/sleeping_king_studios/tools/array_tools.rb', line 66

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 }
    

    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 }
    

    Yield Parameters:

    • item (Object)

      An item in the array to matched.

    Raises:

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



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

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.



128
129
130
131
132
# File 'lib/sleeping_king_studios/tools/array_tools.rb', line 128

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.



137
138
139
140
141
142
143
# File 'lib/sleeping_king_studios/tools/array_tools.rb', line 137

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'

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

Raises:

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



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

def humanize_list(ary, **options, &block) # rubocop:disable Metrics/AbcSize
  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.



211
212
213
214
215
216
217
218
219
# File 'lib/sleeping_king_studios/tools/array_tools.rb', line 211

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.

See Also:



228
229
230
# File 'lib/sleeping_king_studios/tools/array_tools.rb', line 228

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']

Raises:

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



268
269
270
271
272
273
274
275
276
277
278
# File 'lib/sleeping_king_studios/tools/array_tools.rb', line 268

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