57

Is there a one-line method of writing this each block in Ruby?

cats.each do |cat|
   cat.name
end

I'm trying to shorten the amount of code in my project. I'm using Ruby 1.9.2.

Thanks!

Goalie
  • 3,045
  • 5
  • 35
  • 46

4 Answers4

84

Yes, you can write:

cats.each { |cat| cat.name }

Or simply:

cats.each(&:name)

Note that Enumerable#each returns the same object you are iterating over (here cats), so you should only use it if you are performing some kind of side-effect within the block. Most likely, you wanted to get the cat names, in that case use Enumerable#map instead:

cat_names = cats.map(&:name)
tokland
  • 66,169
  • 13
  • 144
  • 170
  • How about if I wanted to do something like this (Which is currently a two liner): User.where(:email => /josh@josh.com/).each do |user| user.destroy end – Goalie Jun 12 '12 at 07:22
  • 3
    `User.where(:email => /josh@josh.com/).each(&:destroy)`. Here `each` makes sense because destroying is a side-effect. But I'd write: `User.destroy_all(:email => /josh@josh.com/)` – tokland Jun 12 '12 at 07:24
53

Just remove the line breaks:

cats.each do |cat| cat.name end

Note, there are two different coding styles when it comes to blocks. One coding style says to always use do/end for blocks which span multiple lines and always use {/} for single-line blocks. If you follow that school, you should write

cats.each {|cat| cat.name }

The other style is to always use do/end for blocks which are primarily executed for their side-effects and {/} for blocks which are primarily executed for their return value. Since each throws away the return value of the block, it only makes sense to pass a block for its side-effects, so, if you follow that school, you should write it with do/end.

But as @tokland mentions, the more idiomatic way would be to write

cats.each(&:name)
Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
17

Another trick which I use for rails console/irb is to separate commands with ';' e.g.

[1,2].each do |e| ; puts e; end
Zaharije
  • 341
  • 1
  • 7
0
for cat in cats;cat.name;end

that should do it too.

Robert SS
  • 29
  • 1
  • this is very ugly, please look at accepted answer. You should avoid ";" as much as possible for code legibility. Or at least add spaces on line jumps. Also question asks for "block one liner" not for. – Alexis Rabago Carvajal Oct 11 '17 at 18:18