Ruby comes with many fantastic Enumerable methods, but the two most useful ones come through Smalltalk via LISP: #map and #inject . What follows are some lengthy method definitions followed by rewrites that are not only more concise but also more clear in their intentions.

Requirement:

As a user with a PGP key I want to see the list of key ids for all my signers so I can quickly import them from the keyserver.

The initial implementation is a little lengthy and overly explicit:

def signer_key_ids result = [] signers.each do |signer| result << signer.key_id end result end

But a simple use of #map more clearly illuminates what this method does:

def signer_key_ids signers.map { |signer| signer.key_id } end

Another requirement comes in:

As a user with a PGP key I want to see the list of all UIDs for all my signers so I can see their names and where they work.

We can write this in a structured way using #each and #flatten :

def signer_uids result = [] signers.each do |signer| result << signer.uids end result.flatten end

But a #map makes it more clear. Note the use of Symbol#to_proc here:

def signer_uids signers.map(&:uids).flatten end

An #inject combined with Array#+ removes the need to call #flatten at the end:

def signer_uids signers.inject([]) do |result, signer| result + signer.uids end end

Though in this case using #inject is the long way; instead try Enumerable#flat_map :

def signer_uids signers.flat_map(&:uids) end

Another requirement comes in from above:

As a user with a PGP key I want to see a mapping of all key ids to their UIDs for each signer so I can build my own keyserver.

Well we need to build a hash, and we need to build it from each element in an array. At least, that’s one way to phrase it:

def signer_keys_and_uids result = {} signers.each do |signer| result[signer.key_id] = signer.uids end result end

But another way to phrase it is: given an empty hash, #inject a hash from key id to UIDs for each element in the array of signers:

def signer_keys_and_uids signers.inject({}) do |result, signer| result.merge(signer.key_id => signer.uids) end end

One last requirement, they swear:

As a user with a PGP key I want to confirm that all my signers are signed by me so I can always feel mutually complete.

With the hash above we were dealing with another Enumerable. Here it’s a Boolean, so let’s try it the long way:

def mutually_signed? result = true signers.each do |signer| result = result && signer.signed_by?(self) end result end

Though, now that we’ve seen that, it looks a bit familiar:

def mutually_signed? signers.inject(true) do |result, signer| result && signer.signed_by?(self) end end

But if that’s too obtuse, we can always think of it as an array of Booleans that must all be true:

def mutually_signed? signers.map(&:signed_by?).inject(:&) end

As Rubyists we also know that we have other fantastic abstractions up our Enumerable sleeve:

def mutually_signed? signers.all?(&:signed_by?) end

To get a comfortable intuition with #map , #inject , and other Enumerable methods, I recommend going outside of Ruby for a bit. Some amazing books on the topic of functional programming are: