Why doesn't my ruby method call work? (yield) [duplicate] - ruby

This question already has answers here:
Passing block into a method - Ruby [duplicate]
(2 answers)
Closed 2 years ago.
I can't figure out why I get this error message when I run my file on the console: no block given (yield) (LocalJumpError)
Here my code:
def block_splitter(array)
array.partition { |item| yield(item) }
end
beatles = ["John", "Paul", "Ringo", "George"]
puts block_splitter(beatles) do |beatle|
beatle.start_with?("P")
end
Thanks for your help!

It's a whitespace issue. Your problem is in this line:
puts block_splitter(beatles) do |beatle|
# ...
end
The above code is being interpreted like this:
puts(block_splitter(beatles)) do |beatle|
# ...
end
I.e. the ruby interpreter thinks that the block is being passed to the puts method, not the block_splitter method.
By assigning a variable and printing the result, you'll see that this works as expected:
result = block_splitter(beatles) do |beatle|
beatle.start_with?("P")
end
puts result
Or, you can define this as a 1-liner, and the ruby interpreter handles it like you expected:
puts block_splitter(beatles) { |beatle| beatle.start_with?("P") }
Or, you could wrap it in extra brackets:
puts(block_splitter(beatles) do |beatle|
beatle.start_with?("P")
end)

So there is a problem with missing parentheses. Ruby interpreter allow not to use those, but when You use nested method calls It's better (and sometimes necessary) to use them. To fix it You can do something like this
puts(block_splitter(beatles) do |beatle|
beatle.start_with?("P")
end)
Or even better
puts(block_splitter(beatles) {|beatle| beatle.start_with?("P")})

Related

Why can't I print the result of reduce/inject directly [duplicate]

This question already has answers here:
Code block passed to each works with brackets but not with 'do'-'end' (ruby)
(3 answers)
Closed 4 years ago.
Found an interesting quirk in the ruby interpreter - at least in MRI 2.4.2.
As far as I can tell, each of the below code snippets should print '123'. If I try to print the result of reduce directly, I get NoMethodError: undefined method '' for 1:Integer (or whatever type the array contains) But if I first save the result and then print it, it works fine..
So, this code is broken:
puts [1,2,3].reduce('') do |memo, num|
memo + num.to_s
end
And this code works:
temp = [1,2,3].reduce('') do |memo, num|
memo + num.to_s
end
puts temp
These should work exactly the same, right? Should this be filed as a bug? Am I just missing something fundamental here?
I'd think it should at least show which method is trying to be called. Can't find anything in google about an undefined method without a method name...
You need parenthesis on the puts call. This works:
puts([1,2,3].reduce('') do |memo, num|
memo + num.to_s
end)
Normally you can avoid parenthesis, but sometimes the parser will find ambiguities and will just raise an error, like in your first case.

in ruby, when is a block not a block? [duplicate]

This question already has an answer here:
Ruby block and unparenthesized arguments
(1 answer)
Closed 7 years ago.
Jokes aside, I have a strange situation, I have some code:
def remotes(form,remotes)
personalised_form = form.dup
remotes.each do |ident,remote|
object = yield(ident)
result = remote.call(object)
insert_into_(personalised_form,ident,result)
end
personalised_form
end
And I'm seeing if it works like so:
pp remotes(forms,remotes) do |ident|
case(ident)
when :get_assets
'#Userobject'
end
end
The problem is that ruby seems to think I'm not passing a block to the remotes function.
Why is ruby insisting that I'm not passing a block? (it gives a no block given (yield) (LocalJumpError) specifically).
Thought it's not relevant, remotes is a hash containing key's and Procs, and form is just a specificly structured hash that has the result of the proc inserted into it using the ident to locate the correct insertion point
Ruby thinks you are passing the block to pp method, which simply ignores it. Try:
res = remotes(forms,remotes) do |ident|
case(ident)
when :get_assets
'#Userobject'
end
end
pp res

Function overloading in Ruby [duplicate]

This question already has answers here:
Why doesn't ruby support method overloading?
(9 answers)
Closed 7 years ago.
I have this piece of code in Ruby.
class Superheros
class<<self
def foo1(param1)
print "foo1 got executed\n"
end
def foo1
print "foo1 without param got executed\n"
end
def foo3(param1,param2)
print "foo3 got executed\n"
end
end
end
print Superheros.foo3(2,3)
print Superheros.foo1
print Superheros.foo1
print Superheros.foo1(5)
I get the error in Superheros.foo1(5) . But i already have the function foo1(param1) to match it with, but it gives me an error
`foo1': wrong number of arguments (1 for 0) (ArgumentError)
Why is that?
PS: I found out if i remove the function name without the parameter,
the Superheros.foo1(5) works just fine.
Ruby doesn't support method overloading. In your code, your second definition of foo1 replaced the first. That's why you get an error when you try to pass arguments, the method that accepted arguments is gone.
There is a question on SO about this topic here, with some good explanations.
Maybe you could use variable arguments:
def foo1(*args)
case args.length
when 1
puts "Function A"
when 2
puts "Function B"
else
puts "Called with #{args.length} arguments"
end
end

Whats the ruby syntax for calling a method with multiple parameters and a block?

Ruby doesn't like this:
item (:name, :text) {
label('Name')
}
And I don't know why. I'm attempting to create a DSL. The 'item' method looks like this:
def item(name, type, &block)
i = QbeItemBuilder.new(#ds, name, QbeType.gettype(type))
i.instance_exec &block
end
Take a name for the item, a type for the item, and a block. Construct an item builder, and execute the block in its context.
Regardless of whether or not I need to use instance_exec (I'm thinking that I don't - it can be stuffed in the initialiser), I get this:
SyntaxError (ds_name.ds:5: syntax error, unexpected ',', expecting ')'
item (:name, :text) {
^
How do I invoke method with multiple arguments and a block? What does ruby think I'm trying to do?
The space before parentheses is causing ruby to evaluate (:name, :text) as single argument before calling the method which results in a syntax error. Look at these examples for illustration:
puts 1 # equivalent to puts(1) - valid
puts (1) # equivalent to puts((1)) - valid
puts (1..2) # equivalent to puts((1..2)) - valid
puts (1, 2) # equivalent to puts((1, 2)) - syntax error
puts(1, 2) # valid
Your way of providing the block is syntactically valid, however when the block is not in the same line as the method call it is usually better to use do ... end syntax.
So to answer your question you can use:
item(:name, :text) { label('Name') }
or:
item(:name, :text) do
label('Name')
end
Remove the space before the ( in item (:name, :text) {

Ruby hash/sub-hash existance check [duplicate]

This question already has answers here:
How to avoid NoMethodError for missing elements in nested hashes, without repeated nil checks?
(16 answers)
Closed 7 years ago.
I find myself needing to put guards like this:
if hash[:foo] && hash[:foo][:bar] && hash[:foo][:bar][:baz]
puts hash[:foo][:bar][:baz]
end
I'd like to shorten this in some way; I know I can wrap in a begin/rescue block but that seems worse. Maybe something like:
ruby Hash include another hash, deep check
Something like:
def follow_hash(hash, path)
path.inject(hash) { |accum, el| accum && accum[el] }
end
value = follow_hash(hash, [:foo, :bar, :baz])
puts value if value
I found this article very informative: http://avdi.org/devblog/2011/06/28/do-or-do-not-there-is-no-try/
value = Maybe(params)[:foo][:bar][:baz][:buz]

Resources