dwilbank
dwilbank

Reputation: 2520

Tacking methods onto `end`

At the end of this here block,

entries.map do |key_val|
  "[#{key_val.first}] \"#{key_val.last}\""
end.sort.join("\n")

I see sort tacked onto end. Is this common? What is it doing? I've never seen end being treated as the value of return. Is that what's happening? The map inside the method returns an array and you can grab onto it with end?

Upvotes: 2

Views: 93

Answers (3)

Mark Reed
Mark Reed

Reputation: 95315

Don't be fooled by the syntax. The block defined by do...end is just a special type of argument passed to the map call. It doesn't go in parentheses or otherwise look like it's an argument, but it is one; the syntax of the method call runs all the way to the end. So when you stick a .method on the end, you're calling that method on the return value of the map call - which is, hopefully, an Array.

There are various ways to rewrite so that it's clearer to those less familiar with Ruby's syntax oddities. For instance, add some parentheses to make the precedence explicit, as suggested by @AndrewMarshall:

(entries.map do |key_val|
  "[#{key_val.first}] \"#{key_val.last}\""
end).sort.join("\n")

Or create a Proc out of the block and pass it inside the method call parentheses using &, so the chained method call is in a more familiar place syntactically (in this one I also rewrote the block itself in what I think is a cleaner style):

block = proc do |key, val|
  %([#{key}] "#{val}")
end

entries.map(&block).sort.join("\n")

You can combine that with removing a level of chaining, as in AJcodez's answer:

intermediate_array = entries.map(&block)
intermediate_array.sort.join("\n")

Or eliminate the chaining entirely:

mapped = entries.map(&block)
sorted = mapped.sort
joined = sorted.join("\n")
return joined

Basically, the fact that the method call syntax is attached to the end is just a quirk of Ruby's block-passing syntax (and, of course, also works if you attach the method call to the closing brace of a {...} block). You're just calling a method (that happens to take a block, which you supply) and then calling a second method on the return value of the first.

Upvotes: 6

user2909560
user2909560

Reputation: 1

I do not believe calling a method on 'end' is common practice. I have been learning ruby for about 2 months now, and have not once come across that syntax.

Upvotes: 0

AJcodez
AJcodez

Reputation: 34206

In ruby everything returns a value, including blocks. Same as:

intermediate_array = entries.map do |key_val|
  "[#{key_val.first}] \"#{key_val.last}\""
end
intermediate_array.sort.join("\n")

I prefer the above syntax choice, but both are perfectly valid for the interpreter.

Upvotes: 0

Related Questions