Use 'puts' with block accepting method over multiple lines [duplicate] - ruby

This question already has answers here:
Ruby Print Inject Do Syntax
(3 answers)
Closed 7 years ago.
Let's say I have the following (working) pseudo-code:
puts results.fields.inject('') { |string, key|
lengths[key] = calculate_length(key)
string << format(key)
}
Following the ruby-style-guide I should
Omit parentheses for 'keyword methods', i.e. puts, (which would create }) or end) anyway)
Use do...end for multi-line blocks
However, when replacing {...} with do...end it raises
undefined method `' for :title:Symbol (NoMethodError)
Therefore, is it possible to refactor this code without violenting the guideline?

There is a difference in precedence between {} and do end
If you use do end the block is associated with the puts statement, whereas the braces are associated with the results.field.inject('')
If you want to use do end then you have to remove the ambiguity of association by parentheses. It's one of those "gotchas" where the guidelines are recognized as guidelines, not absolute rules.
See also this answer...
In Ruby, why is a method invocation not able to be treated as a unit when "do" and "end" is used?

Related

Ruby code what does "&:" do here [duplicate]

This question already has answers here:
What does map(&:name) mean in Ruby?
(17 answers)
Closed 5 years ago.
def reverse_words(s)
s.split.map(&:reverse).join(' ')
end
This code reverses each word in a sentence. But I do not understand "&:" in the code. Can someone explain that to me?
map expects a code block that takes one argument. What you would normally do is to call reverse on that argument:
map {|elt| elt.reverse }
With the & syntax you can shorten this to
map(&:reverse)
The colon is there to make a symbol out of the name reverse.
The & means that reverse is referencing a function, not a block.
This method assumes that the caller will pass it a String object.
First the method #splits the string on whitespaces into an array (if the string has no whitespaces it creates an array with the string as the only element)
Calls the Array#map method on the new array and passes it a reference to the String#reverse method.
The & tells the map method that the input is a reference to a method and not a standard block

Is there a default difference between methods with '!' and without, in ruby? [duplicate]

This question already has answers here:
Why are exclamation marks used in Ruby methods?
(12 answers)
Closed 9 years ago.
Is there a default difference between methods with '!' and without, in ruby?
collect v collect!
flatten v flatten!
and so on..
In ruby the main difference is that, the ! methods are selfish, i.e. they apply the changes to the self object. They return nil, when no changes are done, while the non-! methods create new modified object.
In Rails the difference is that, the ! methods are safe versions of non-! methods, that means the ! methods raises an exception when the code encountered an error during execution, while non-! methods just return error state, usually false condition.

The ampersand operator with parameters [duplicate]

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 ;-)

What does method_name(*) mean? [duplicate]

This question already has an answer here:
naked asterisk as parameter in method definition: def f(*)
(1 answer)
Closed 8 years ago.
In the rails code I came across following method definition def initialize(*)
I understand what def foo(*a) means but can't figure out significance of omitting identifier name after *. How do you access any arguments passed to this method?
Here's my guess.
It works because of second line:
def initialize(*)
super
...
end
So the method receives arbitrary number of arguments and passes all of them to super(as you know, super without arguments means take all arguments from original method).
And then in this case the names for arguments are not required.

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