Project Ramon

A learning journey from a Ruby noob perspective

Ruby Refactoring: Replace Loop with Collection Closure Method

replace_loops_with_closure_header_img

Hello and happy Friday!

Today we have a pretty cool refactoring pattern to take a peak at. If you’re interested in taking a closer look at these patterns, you should grab a copy of Refactoring Ruby Edition. I know I’ve been enjoying my reading and reviews.

Today we get to look at an alternative to using loops in our code.

Replace Loop with Collection Closure Method

Fortunately for us Ruby practitioners our language has been pretty well influenced by both Lisp and Smalltalk. Both of these dynamic languages have closures and libraries to manipulate collections easily. Ruby’s Enumberable module also allows us to do quite a bit with the Array and Hash classes.

Replacing our loops with closure methods, we can provide the benefit of allowing our code to be easier to follow. This is becuase collection closure methods hide away the groundwork code used to pass through our collections and create inferred collections, allowing us to focus on business logic.

The authors also mention that there are times when a more complex task requires a sequence of collection closure methods chained together.

Lets quickly checkout the mechanics of this pattern:

  • Identify what the basic pattern of the loop is
  • Replace the loop with the appropriate collection closure methods
  • Test

Replacing Loops with Closure Methods In Action

Once again, the illustrations in the book are excellent examples of this refactor pattern.

before:

managers = []
employees.each do |e|
  managers << e if e.manager?
end

This is what has me excited over this pattern! I was very familiar with the .each loops as I started to learn Ruby a couple years ago. But never fell in the habit of extending my reach in this area until today’s chapter neatly laid out how easy it would be to do so.

after:

managers = employees.select {|e| e.manager? }

I wanted to share another note from the authors. The reject method reverses the test of the filter. And in both cases the original collection isn’t touched unless you use the destructive form (select! or reject!).

before:

offices = []
employees.each { |e| offices << e.office } 

after:

offices = employees.collect { |e| e.office }

Conclusion

collect is aliased as map, where collect is the Smalltalk word and map is the Lisp word. The authors point out here that the choice of method depends on whether you like parentheses or square brackets.

I will be sure to personally stay alert for my first opportunity to give closures a try 🙂

Stay tuned…

Advertisements

Categories: Ruby

Tags:

1 reply

  1. Nice. Knowing collection methods and when to use them is very important for development. There are appropriate methods for most operations you might want to do.

    The last piece of code should be without the shovel (<<). You could also write a shorthand for that, like this: employees.collect(&:office)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s