What exactly is `&:capitalize` in Ruby? - ruby

I just read this answer Converting upper-case string into title-case using Ruby.
There is the following line of code
"abc".split(/(\W)/).map(&:capitalize).join
What exactly is &:capitalize? Before I had put this into irb myself, I would have told you, it's not valid ruby syntax. It must be some kind of Proc object, because Array#map normaly takes a block. But it isn't. If I put it into irb alone, I get syntax error, unexpected tAMPER.

foo(&a_proc_object) turns a_proc_object into a block and calls foo with that block.
foo(&not_a_proc_object) calls to_proc on not_a_proc_object and then turns the proc object returned by to_proc into a block and calls foo with that block.
In ruby 1.8.7+ and active support Symbol#to_proc is defined to return a proc which calls the method named by the symbol on the argument to the proc.

It's Symbol#to_proc: see http://pragdave.pragprog.com/pragdave/2005/11/symbolto_proc.html
map(&:capitalize) is exactly the same as map { |x| x.capitalize }.

The ampersand is syntactic sugar that does a whole bunch of code generation with the to_proc message. See http://blog.codahale.com/2006/08/01/stupid-ruby-tricks-stringto_proc/

Related

Giving parameters to ampersand block

If we have a method on a collection that takes a block with another method executed on each element, we can write it shorter using ampersand. For example: if we have an array of integers and we want to remove the odd numbers we can do this:
[1,2,3,4,5,6,7,8].reject {|x| x.odd?}
Using ampersand, we can write this:
[1,2,3,4,5,6,7,8].reject(&:odd?)
Let's say we have an array of strings, and we want to remove the elements containing 'a'. We can write the solution like this:
['abc','cba','cbc','cdc','dca','cad','dc','cc].reject {|x| x.include? 'a'}
How do we write this using the ampersand syntax (if it's possible)?
You can't, it is not possible.
& followed by a symbol is is a shortcut for a method that does not take any arguments.
As you said,
.reject(&:odd?)
Is a shortcut for:
.reject {|x| x.odd?}
Basically, &:SYMBOL is always a shortcut for passing a block {|x| x.SYMBOL}
The reason this works is because calling the #to_proc method on a symbol returns a lambda expression that's a one-argument lambda, which calls the method with the same name as the symbol on it's argument.
And & converts from lambda to a block argument -- but beyond that, will call to_proc on it's operand before converting it to a block argument. So it calls to_proc on the symbol, and then gets a lambda from the symbol. And then passes this as a block argument to your method.
There's no way to use that shortcut when you need a block whose body goes beyond a one-argument block which just calls the method named after a symbol on it's argument.
Just write it out as you did. Nothing at all wrong with .reject {|x| x.include? 'a'}, just write that.

Why does `gsub` call `to_hash`?

I am writing a DSL. I don't want users to have to quote the arguments to pass strings, therefore I overwrite method_missing to convert an unknown method to a string. In the following example, create is the DSL method, and I wanted user to type arg1 and arg2 without the quotes.
def method_missing(m, *arg)
m.to_s
end
def create(*args)
arg1.gsub(#do something here)
end
create arg1 arg2
However, this raises and error when I use gsub on the 'string':
'gsub': can't convert String to Hash (String#to_hash gives String) (TypeError)
I guess the method_missing overwriting is messed it up since it looks like gsub is calling String#to_hash, which is not a method in String, thus it is routed to method_missing.
I am wondering why gsub calls String#to_hash, or whether there is any other way to let users of the DSL not have to type quotes, without overwriting method_missing.
String#gsub does different things depending on the argument count and types, and if a block was given:
gsub(pattern, replacement) → new_str
gsub(pattern, hash) → new_str
gsub(pattern) {|match| block } → new_str
gsub(pattern) → enumerator
The second one is documented as:
If the second argument is a Hash, and the matched text is one of its keys, the corresponding value is the replacement string.
But how to distinguish it from the first? Both take two arguments! That's a little bit complicated but in your case Ruby (well, the reference implementation called CRuby or MRI to be exact) starts with checking if the second argument has the internal type T_HASH (it doesn't as it's most likely T_STRING due to #to_s), then it checks if #to_hash can be called. Either because it responds to it or #method_missing can instead. You have defined it so Ruby calls it. However it doesn't return a T_HASH and that is the cause of the exception you've posted.
A possible solution is defining main.method_missing and not Object#method_missing (as String inherits from Object):
def self.method_missing(m, *arg)
m.to_s
end
However I recommend sticking to quotes or writing your own small parser for this kind of file if it shouldn't adhere to Ruby's syntax. Using *_missing may be the cause of confusing or unhelpful error messages. Or even none (I guess create arg1 arg2 should've been create arg1, arg2).
gsub probably uses method_missing itself somewhere, so it seems that defining it globally there is causing internal issues with the method call. If you're going to use method_missing make sure you always define it in a module or a class:
module CoolDSL
def self.method_missing(m, *arg)
m.to_s
end
def self.create(*args)
args[0].gsub(/1/, "2")
end
def self.do_thing
create arg1 arg2
end
end
CoolDSL.do_thing
Naturally, that's not exactly useful as a DSL, so you'll want to learn the power of instance_eval and yield. I like this guide.

Why does Ruby call the `call` method when I don't supply the method name?

Given the following module:
module Foo
def self.call
'foo'
end
end
I would of course expect the following to work:
puts Foo.call # outputs "foo"
However, I did not expect this to work:
puts Foo.() # outputs "foo"
Apparently when the method name is left off, Ruby assumes that I want to call the call method. Where is this documented, and why does it behave that way?
Proc#call:
Invokes the block, setting the block’s parameters to the values in params using something close to method calling semantics. Generates a warning if multiple values are passed to a proc that expects just one (previously this silently converted the parameters to an array). Note that prc.() invokes prc.call() with the parameters given. It’s a syntax sugar to hide “call”.
I did some research and found method #() is a syntactic sugar of the method #call..Look at the error as below :
module Foo
def self.bar
12
end
end
Foo.()
#undefined method `call' for Foo:Module (NoMethodError)
As OP defined the #call method in module Foo class,Foo#call is called in an attempt of Foo.().
Here is some more examples :
"ab".method(:size).() # => 2
"ab".method(:size).call # => 2
"ab".() # undefined method `call' for "ab":String (NoMethodError)
See here what Matz said So compromise with object.() syntax introduced in 1.9...
Apparently, as Arup is saying, this is syntactic sugar introduced a while ago, possibly for the single cause of making Proc objects easier to work with. (You don't have to explicitly call them, but can just do prc.() instead).
I also concluded that this is definitely a Ruby 1.9+ feature. If I switch my JRuby to 1.8 mode, I get this instead:
SyntaxError: spam.rb:12: syntax error, unexpected tLPAREN2
So, somewhere in the changelogs for Ruby 1.9 it can probably be found, if someone really wants to dig it out from the caves... :)

What does the end.method do in Ruby?

I've seen code like this:
def some_method
# ...
end.another_method
What does the end.another_method part do?
I believe that your example is wrong, as what you are doing here is defining a method and calling a method on the result of a method definition (not a method call), which is always (usually?) nil.
There's a similar form which fmendez is referring to, but end is the end of a block, not a method definition in that case.
So, for example:
array.map do |element|
element * element
end.sum
would, hypothetically, return a sum of squares of elements of given array.
But, if you are doing method chaining like this, it is more common to use bracket style blocks instead of do..end, so the above example would read:
array.map{ |element|
element * element
}.sum
Blocks in Ruby are method arguments, not unlike any other method arguments (apart from the dedicated syntax), so putting dot after end is not different than putting the dot after ) in
'hello'.concat(' world!').capitalize
Which is also an example of method chaining.
In Ruby, the . is the message sending operator. (In other languages, it would be called a method calling operator instead.) So, when you say
foo.bar
it means "evaluate foo and send the message bar to the result of evaluating foo".
In this particular case, you are sending the message another_method to the result of evaluating
def some_method; end
The Ruby Language Specification says that the value of a method definition expression is undefined and should be ignored; and on most Ruby implementations, method definition expressions simply evaluate to nil, which isn't terribly useful.
However, on some implementations, method definition expressions do evaluate to something more useful than nil. On Rubinius, for example, they evaluate to the CompiledMethod object for the method being defined. And CompiledMethod has a rich API, so sending messages to a CompiledMethod object definitely makes sense.
It has also been proposed that method definition expressions should return a Symbol corresponding to the name of the method being defined or a Method object.
Put simply: the dot in this particular case means the exact same thing it always means in Ruby: send a message, call a method, invoke a member function, whatever you want to call it.

What do you call the &: operator in Ruby? [duplicate]

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.

Resources