This question already has answers here:
What does map(&:name) mean in Ruby?
(17 answers)
Closed 8 years ago.
I saw the code from here
Post.published.collect(&:views_count)
I guess it equals to
.collect { |p| p.views_count }
But I never saw this usage before, does this have a name? Where can I find more information about it?
This is actually a rather clever hack made it into ruby 1.9.
Basically, & in front of a variable in ruby coerces it into a proc. It does that by calling to_proc. Some clever fellow (first time I saw this was in _whys code, but I won't credit him cause I don't know if he came up with it) added a to_proc method to Symbol, that is essentially {|obj| obj.send self}.
There aren't many coercians in ruby, but it seems like all of them are mostly used to do hacks like this (like !! to coerce any type into a boolean)
It's a use of Symbol#to_proc. The & operator turns a Proc object into a block, and because Ruby 1.8.7 and newer implement Symbol#to_proc, it can be used with a symbol like :views_count. And yes, it's equivalent to {|p| p.views_count}.
Related
This question already has answers here:
What does map(&:name) mean in Ruby?
(17 answers)
Closed 4 years ago.
I've seen an example of how to sort a string. To sort case insensitively:
str.chars.sort(&:casecmp).join
#=> "ginrSt"
I'm curious about (&:casecmp). I found that for example:
arr.map(&:name)
is shorthand for
arr.map(&:name.to_proc)
which is same with
arr.map{|el| el.name}
I know the & (ampersand) tries to convert symbol to proc, and pass it as a block to a method. I do not understand how this would work for sort method, which is supposed to compare two values. Would it be as follows?
str.chars.sort{|a, b| a.casecmp ;b.casecmp}.join
It wouldn't be helpful since soft needs a block to return an integer and casecmp needs an argument. (Or is it called parameter in that case?) To me, it looks more like this:
str.chars.sort{|a, b| a.casecmp(b)}.join
How does &:casecmp know to take one of |a, b| as a caller and the other one as an argument? I wouldn't guess it that it is an option.
If more than one parameter is passed to your block, the proc created by Symbol#to_proc uses the additional block parameters as parameters to the method call.
http://phrogz.net/symbol-to-proc-with-multiple-arguments
So, what's really happening is, sort(&:casecmp) is converted to:
sort {|a,b| a.casecmp(b) }
because sort takes two parameters.
This question already has an answer here:
How can I more elegantly remove duplicate items across all elements of a Ruby Array?
(1 answer)
Closed 8 years ago.
I have this piece of code in an application and was told to make it more elegant but have no idea how to make it better
self.join(" ").split(" ").uniq
Any suggestion will be much appreciated.
self is an array
flat_map(&:split).uniq
flat_map runs a block over an array, and concatenates all the resulting arrays.
flat_map(&:split) is equivalent to calling s.split on every argument, which happens to do the exact same thing as s.split(' '), (unless you redefine $;, but please don't do that).
We don't need self, so we omit it.
This question already has answers here:
Can you supply arguments to the map(&:method) syntax in Ruby?
(9 answers)
Closed 8 years ago.
I wonder, isn't it possible to call a method using & operator with parameters?
items.each &:my_proc # ok
items.each &:my_proc(123, "456") # ops!
No, it's not possible. Use full form.
items.each{|i| i.my_proc(123, '456')}
Look at the source of Symbol#to_proc for the "why".
You can use a bit of trickery and acheive something similar:
class Symbol
def [](*args)
proc{|obj| obj.send(self, *args) }
end
end
[123.456, 234.567].map(&:round[2])
#=> [123.46, 234.57]
I highly discourage the use in production code though, since gems etc may rely on Symbol#[]. This is just a fun thing to play around with ;-)
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
What do you call the &: operator in Ruby?
I see '.map(&:chomp)' all the time
I know what chomp and map do, but I want to know what &: does and I'd like to know why I can't find it on the web after 30 minutes of googling.....
It's Symbol#to_proc, and it turns the symbol into a proc which attempts to invoke the given method on its argument, returning the result.
x = :reverse.to_proc
x.call("asdf") # "fdsa", like calling "asdf".reverse
In your case, .map(&:chomp) is equivalent to .map { |x| x.chomp }.
If you can't find it by Googling, it's because you're Googling the wrong thing. It's a well-known Ruby idiom.
This question already has answers here:
Closed 13 years ago.
Possible Duplicates:
Ruby/Ruby on Rails ampersand colon shortcut
What does map(&:name) mean in Ruby?
I was reading Stackoverflow and stumbled upon the following code
array.map(&:to_i)
Ok, it's easy to see what this code does but I'd like to know more about &: construct which I have never seen before.
Unfortunately all I can think of is "lambda" which it is not. Google tells me that lambda syntax in Ruby is ->->(x,y){ x * y }
So anyone knows what that mysterious &: is and what it can do except calling a single method?
There's a few moving pieces here, but the name for what's going on is the Symbol#to_proc conversion. This is part of Ruby 1.9 and up, and is also available if you use later-ish versions of Rails.
First, in Ruby, :foo means "the symbol foo", so it's actually two separate operators you're looking at, not one big &: operator.
When you say foo.map(&bar), you're telling Ruby, "send a message to the foo object to invoke the map method, with a block I already defined called bar". If bar is not already a Proc object, Ruby will try to make it one.
Here, we don't actually pass a block, but instead a symbol called bar. Because we have an implicit to_proc conversion available on Symbol, Ruby sees that and uses it. It turns out that this conversion looks like this:
def to_proc
proc { |obj, *args| obj.send(self, *args) }
end
This makes a proc which invokes the method with the same name as the symbol. Putting it all together, using your original example:
array.map(&:to_i)
This invokes .map on array, and for each element in the array, returns the result of calling to_i on that element.