ActiveSupport: Array Extensions

It seems like such a simple thing, but I’m really enjoying reading the source of Rails. I’m finding all sorts of hidden gems (ouch).

For instance, check out this interesting extension added to Array in “core_ext/array/extract_options.rb”

class Array
  # Extracts options from a set of arguments. Removes and returns the last
  # element in the array if it's a hash, otherwise returns a blank hash.
  #   def options(*args)
  #     args.extract_options!
  #   end
  #   options(1, 2)        # => {}
  #   options(1, 2, a: :b) # => {:a=>:b}
  def extract_options!
    if last.is_a?(Hash) && last.extractable_options?

I think I’ve rolled my own version of this at least a few times after seeing too many arguments in the signature.

Or consider this clever extension in “core_ext/array/grouping.rb”

  # Divides the array into one or more subarrays based on a delimiting +value+
  # or the result of an optional block.
  #   [1, 2, 3, 4, 5].split(3)              # => [[1, 2], [4, 5]]
  #   (1..10).to_a.split { |i| i % 3 == 0 } # => [[1, 2], [4, 5], [7, 8], [10]]
  def split(value = nil, &block)
    inject([[]]) do |results, element|
      if block && || value == element
        results << []
        results.last << element


Having just gone through “Learn You a Haskell for Great Good”, I’ve been wanting to see some Ruby examples in the wild of something which should be familiar to the functional and/or lispy crowds. Since Enumerable#inject is not used as much as it should be, let’s review it’s usage.

Inject (also called reduce) takes an enumerable (a thing which meets a couple requirements but basically means you can iterate over) and applies an operation to all of it’s elements and accumulates a resulting value. Simple case:

(1..5).inject(0,:+) # => 0 + 1 + 2 + 3 + 4 + 5 = 15

You can also leave off the accumulator if the first element of your enum is an acceptable starting accumulator, so the above could be

(1..5).reduce(:+) # => 1 + 2 + 3 + 4 + 5 = 15

In addition, it can take a block instead of a binary operation:

(1..5).reduce {|results,x| results + x } # => 15

Now that we’ve reviewed that, we can see the cleverness in Array#split. It has a starting accumulator of [[]] and instead of a simple binary operation :+ it takes a block and applies it to each element in enum. That’s where the logic happens, if the block returns a truthy value, we start a new empty array in the accumulator, otherwise we push the element onto the last array in the accumulator.

That’s it for now!

Published under programming