DEV Community

Cover image for Understanding Ruby - Enumerable - Coercion
Brandon Weaver
Brandon Weaver

Posted on

Understanding Ruby - Enumerable - Coercion

Introduction

Enumerable. Debatably one of, if not the, most powerful features in Ruby. As a majority of your time in programming is dealing with collections of items it's no surprise how frequently you'll see it used.

Difficulty

Foundational

Some knowledge required of functions in Ruby. This post focuses on foundational and fundamental knowledge for Ruby programmers.

Prerequisite Reading:

Enumerable

Enumerable is an interface module that contains several methods for working with collections. Many Ruby classes implement the Enumerable interface that look like collections. Chances are if it has an each method it supports Enumerable, and because of that it's quite ubiquitous in Ruby.

Note: This idea was partially inspired by Lamar Burdette's recent work on Ruby documentation, but takes its own direction.

Coercion

Perhaps you don't even want an Enumerable at all, there are even methods for changing it over to another type, or methods to coerce them rather.

#to_a / #entries

to_a will coerce a collection into an Array. This isn't very useful for an Array, sure, but remember that other collection types have Enumerable like Hash and Set:

require 'set'

Set[1, 2, 3].to_a
# => [1, 2, 3]

{ a: 1, b: 2, c: 3 }.to_a
# => [[:a, 1], [:b, 2], [:c, 3]]
Enter fullscreen mode Exit fullscreen mode

Its use is very much "what's on the box". If you need something to be an Array use to_a

#to_h

to_h is very similar, it coerces a collection to a Hash:

[[:a, 1], [:b, 2], [:c, 3]].to_h
# => [[:a, 1], [:b, 2], [:c, 3]]
Enter fullscreen mode Exit fullscreen mode

One interesting thing you can do is to use something like each_with methods to do nifty things:

%i(a b c).each_with_index.to_h
# => {:a=>0, :b=>1, :c=>2}

%i(a b c).each_with_object(:default).to_h
# => {:a=>:default, :b=>:default, :c=>:default}
Enter fullscreen mode Exit fullscreen mode

While that alone is interesting, there's a pattern you may recognize from Ruby in days past:

%i(a b c).map { |v| [v, 0] }.to_h
# => {:a=>0, :b=>0, :c=>0}

# Remember, `map` returns an `Array`
{ a: 1, b: 2, c: 3 }.map { |k, v| [k, v + 1] }.to_h
# => {:a=>2, :b=>3, :c=>4}
Enter fullscreen mode Exit fullscreen mode

Guess what else to_h does? It takes a Block Function:

%i(a b c).to_h { |v| [v, 0] }
# => {:a=>0, :b=>0, :c=>0}

{ a: 1, b: 2, c: 3 }.to_h { |k, v| [k, v + 1] }
# => {:a=>2, :b=>3, :c=>4}
Enter fullscreen mode Exit fullscreen mode

...which is pretty nifty. Granted Hash has transform_values now as well, which is probably a better idea for that specific transformation, but it gets the point across.

to_h is great, much like to_a, when you need a Hash. It has some more power behind it for getting there, and a lot of neat things you can do with it as a result.

Wrapping Up

With that we're done with our section on Enumerable, and we'll be moving on to new subjects!

Want to keep up to date on what I'm writing and working on? Take a look at my new newsletter: The Lapidary Lemur

Top comments (0)