Ruby check if block is nil - ruby

I call a method with a block;
method do
"Hello"
end
and the method is defined as;
def method
yield
end
and when defining method; i want to check if given block is empty (nil) or not, because the variable in the method may end up like this;
method do
""
end
So in definition, i want to check if the yield block is nil or not. Like;
def method
if yield ? yield : "Empty block? Seriously?"
end
I know the above does not work. Bu it is what i want to achieve.
Also keep in mind that block_given? will always be "true" since the block is given even if it is nil or empty string.
UPDATE: As most of the comments/answers state that the question is unclear; here is the problem simplified by #ndn:
I want to check if the result of executing a block is "empty"(nil or "") without
invoking it first.

It is unclear what you are asking, because a block itself can not be empty. Therefore, you might mean a few different things:
A missing block. You can check if a block is given
block_given?
Block with empty body (aka {} or do end). This is not impossible, but requires some advanced voodoo ruby metaprogramming magic. Generally, if this is what you are looking for, either you are writing something very interesting or your approach is completely wrong.
You want to check if the result of executing a block is "empty" without invoking it first. This is impossible. For example, consider the following block:
{ [nil, "", true].sample }
Obviously, there is no way to know in advance.
You are ok with calling the block. Then you can assign the result to a variable and make checks on it:
def some_method
evaluation_result = yield if block_given?
if evaluation_result.nil? or evaluation_result == ""
# do something if the block was not given or the result is nil/empty
puts "Empty block? Seriously?"
else
# do something if the block was given and the result is non nil/empty
puts evaluation_result
end
end
Now when you invoke some_method:
some_method { "something" } # => "something"
some_method { 3 + 5 } # => 8
some_method { nil } # => "Empty block? Seriously?"
some_method { "" } # => "Empty block? Seriously?"
some_method { } # => "Empty block? Seriously?"
some_method # => "Empty block? Seriously?"
EDIT:
A workaround for case #3 might be to create two procs, one with what you want to do if the block is "empty" and one - if it is not, then pass them around to the endpoint where you will finally invoke the block. This might or might not be applicable depending on your exact situation.
EDIT2:
Another workaround can be to redefine the Proc#call method for your proc instances. However, this doesn't work for yield:
def secure(&block)
insecure_call = block.method(:call)
block.define_singleton_method(:call) do
insecure_call_result = insecure_call.call
if insecure_call_result.nil? or insecure_call_result == ""
"<b>Bummer! Empty block...</b>"
else
insecure_call_result
end
end
end
x = proc { }
y = proc { "" }
z = proc { nil }
a = proc { 3 + 5 }
b = proc { "something" }
u = proc { [nil, "", true].sample }
[x, y, z, a, b, u].each { |block| secure &block }
# some method that uses the block
def user(&block)
"What I got is #{block.call}!"
end
user &x # => "What I got is <b>Bummer! Empty block...</b>!"
user &y # => "What I got is <b>Bummer! Empty block...</b>!"
user &z # => "What I got is <b>Bummer! Empty block...</b>!"
user &a # => "What I got is 8!"
user &b # => "What I got is something!"
user &u # => Different each time
EDIT3: Another alternative, which is sort of cheating, is to wrap the given proc in another proc. This way, it will work for yield too.
def wrap(&block)
proc do
internal_proc_call_result = block.call
if internal_proc_call_result.nil? or internal_proc_call_result == ""
"<b>Bummer! Empty block...</b>"
else
internal_proc_call_result
end
end
end
Now using the result of wrap and will get you behavior similar to secure.

If I understand correctly, you want to statically determine what the runtime value of a block is. This is one of the many known impossible problems resulting from the undecidability of the Halting Problem.
In other words: it can't be done.
Not "it can't be done in Ruby", not "it is hard", it simply can't be done, period. And it can be (and has been) mathematically proven that it can't be done. Ever.

UPDATED Answer
My last effort to simplify the answer based on comments..
You can check for block emptiness with block_given? and you need to explicitly check for yield output for emptiness like below
def method(&block)
# Below if condition is to prove that block can be accessed
if block_given?
p block
p block.yield
end
b = yield if block_given?
(b.nil? || b.empty?) ? "Empty block? Seriously?" : b
end
p method {"Hello"} # inline block
result = method do
"World"
end
p result
p method # No blocks provided
p method {""} # Block that returns empty string
Output of the program
"Hello"
"World"
"Empty block? Seriously?"
"Empty block? Seriously?"

Related

Self enumerating function

I've got some code:
def my_each_with_index
return enum_for(:my_each_with_index) unless block_given?
i = 0
self.my_each do |x|
yield x, i
i += 1
end
self
end
It is my own code, but the line:
return enum_for(:my_each_with_index) unless block_given?
is found in solutions of other's. I can't get why they passed the function to enum_for as a parameter. When I invoke my function without a block, it won't return anything with or without enum_for. I could left sth like:
return unless block_given?
and it has the same result. Or am I wrong?
Being called without a block, it will return an enumerator:
▶ def my_each_with_index
▷ return enum_for(:my_each_with_index) unless block_given?
▷ end
#⇒ :my_each_with_index
▶ e = my_each_with_index
#⇒ #<Enumerator: main:my_each_with_index>
later on you might iterate on this enumerator:
▶ e.each { |elem| ... }
This behavior is specifically useful in some cases, like lazy iteration, passing block to this enumerator later etc.
Just returning nil cuts this ability off.
Think you for very precise answer. I recived also very good example to understand this issue for other new developers:
def iterator
yield 1
yield 2
yield 3
puts "koniec"
end
iterator { |v| puts v }
it = enum_for(:iterator)
puts it.next
puts it.next
puts it.next
puts it.next
Just run and analyze this code.
For any method that accepts a block, a good method implementation should have a well-defined behavior when the block is not given.
In the example shared by you, each_for_index is being re-implemented by author, may be to provide additional semantics or may be just for academic purpose given that its behavior is same as Ruby's Enumerable#each_with_index.
The documentation has following for Enumerable#each_with_index.
Calls block with two arguments, the item and its index, for each item
in enum. Given arguments are passed through to each().
If no block is given, an enumerator is returned instead.
In order to stay consistent with highlighted line indicating what should be the behavior if block is not given, one has to use something like
return enum_for(:my_each_with_index) unless block_given?
enum_for is interesting method
enum_for creates a new Enumerator which will enumerate by calling method on obj.
Below is an example reproduced from documentation:
str = "xyz"
enum = str.enum_for(:each_byte)
enum.each { |b| puts b }
# => 120
# => 121
# => 122
So, if one does not pass block to my_each_with_index, they have a chance to pass it later - just like one would have done with each_with_index.
e = obj.my_each_with_index
...
e.each { |x, i| # do something } # `my_each_with_index` executed later
In summary, my_each_with_index tries to be consistent with each_with_index and tries to be a well-behaved API.

Return the value from Ruby block

I have a method
def method1(&block)
#.............
if condition == "yes"
yield if block_given?
{success: :true, value: **value returned from the block**}
else
{is_success: :false, value: get_errors_array() }
end
end
How do retrieve the value from &block? Should the &block use return keyword for that?
Nope, there shouldn't be a return in a block here. The "return" value of block is the value of last expression in it.
value_returned = yield if block_given?
def method1
fail("Needs block") unless block_given?
if condition
{success: true, value: yield}
else
{success: false, value: get_errors_array}
end
end
Notes and questions:
If you use yield is not idiomatic to put &block in the method arguments. If you want to require the block write fail("Need blocks") unless block_given?. You can leave it out and then you'll get a "LocalJumpError: no block given", which is also ok.
yield is an expression, not an statement.
It's not idiomatic to write method().
You need a default value to be used when no block is given (unless you fail before, of course).
You used different keys success and is_success, why?
You used :true and :false instead of real booleans, why?
Use call.
block.call
if block takes arguments, then give arguments:
block.call(whatever_arguments)
The & prefix operator will allow a method to capture a passed block as a
named parameter.
def wrap &b
print "dog barks: "
3.times(&b)
print "\t"
end
wrap { print "Wow! " } # Wow! Wow! wow!

Function calls in hash come up empty in Ruby

I've been sifting through the prior questions and answers on stackoverflow, and I have gotten most of my question figured out. I figured out that I can't place a function call within a hash, without placing it within a proc, or a similar container.
What I'm ultimately trying to do is have a menu displayed, grab user input, and then iterate through the hash, and run the specified function:
def Main()
menu_titles = {"Answer1" => Proc.new{Choice1()}}
Menu(menu_titles)
end
def Choice1()
puts "Response answer"
end
def Menu(menu_titles)
menu_titles.each_with_index do |(key, value),index|
puts "#{index+1}. #{key}"
end
user_input = 0
menu_titles.each_with_index do |(key, value), index|
if index.eql?(user_input)
menu_titles[value]
break
end
end
end
Main()
The issue I'm having right now is that I'm not entering the functions that my hash calls for. Whether I use a return or a "puts", I either get a blank line or nothing at all. If anyone has other recommendations about my code, I'm all ears also. To be honest, I don't like using procs, but that's mostly because I don't entirely know how they work and where to use them.
Right now for my menus I have:
user_input = 1
if user_input == 1
Choice1()
...
end
Here's how I would refactor this:
class Menu
attr_reader :titles
# initialize sets up a hard-coded titles instance variable,
# but it could easily take an argument.
def initialize
#titles = {
"Answer1" => Proc.new{ puts "choice 1" },
"Answer2" => Proc.new{ puts "choice 2" }
}
end
# This is the only public instance method in your class,
# which should give some idea about what the class is for
# to whoever reads your code
def choose
proc_for_index(display_for_choice)
end
private
# returns the index of the proc.
def display_for_choice
titles.each_with_index { |(key,value), index| puts "#{index + 1}. #{key}" }
gets.chomp.to_i - 1 # gets will return the string value of user input (try it in IRB)
end
# first finds the key for the selected index, then
# performs the hash lookup.
def proc_for_index(index)
titles[titles.keys[index]]
end
end
If you're serious about Ruby (or object-oriented programming in general), I would highly recommend learning about the advantages of packaging your code into behavior-specific classes. This example allows you to do this:
menu = Menu.new
proc = menu.choose
#=> 1. Answer1
#=> 2. Answer2
2 #(user input)
proc.call
#=> choice 2
And you could actually run it on one line:
Menu.new.choose.call

Use of yield and return in Ruby

Can anyone help me to figure out the the use of yield and return in Ruby. I'm a Ruby beginner, so simple examples are highly appreciated.
Thank you in advance!
The return statement works the same way that it works on other similar programming languages, it just returns from the method it is used on.
You can skip the call to return, since all methods in ruby always return the last statement. So you might find method like this:
def method
"hey there"
end
That's actually the same as doing something like:
def method
return "hey there"
end
The yield on the other hand, excecutes the block given as a parameter to the method. So you can have a method like this:
def method
puts "do somthing..."
yield
end
And then use it like this:
method do
puts "doing something"
end
The result of that, would be printing on screen the following 2 lines:
"do somthing..."
"doing something"
Hope that clears it up a bit. For more info on blocks, you can check out this link.
yield is used to call the block associated with the method. You do this by placing the block (basically just code in curly braces) after the method and its parameters, like so:
[1, 2, 3].each {|elem| puts elem}
return exits from the current method, and uses its "argument" as the return value, like so:
def hello
return :hello if some_test
puts "If it some_test returns false, then this message will be printed."
end
But note that you don't have to use the return keyword in any methods; Ruby will return the last statement evaluated if it encounters no returns. Thus these two are equivelent:
def explicit_return
# ...
return true
end
def implicit_return
# ...
true
end
Here's an example for yield:
# A simple iterator that operates on an array
def each_in(ary)
i = 0
until i >= ary.size
# Calls the block associated with this method and sends the arguments as block parameters.
# Automatically raises LocalJumpError if there is no block, so to make it safe, you can use block_given?
yield(ary[i])
i += 1
end
end
# Reverses an array
result = [] # This block is "tied" to the method
# | | |
# v v v
each_in([:duck, :duck, :duck, :GOOSE]) {|elem| result.insert(0, elem)}
result # => [:GOOSE, :duck, :duck, :duck]
And an example for return, which I will use to implement a method to see if a number is happy:
class Numeric
# Not the real meat of the program
def sum_of_squares
(to_s.split("").collect {|s| s.to_i ** 2}).inject(0) {|sum, i| sum + i}
end
def happy?(cache=[])
# If the number reaches 1, then it is happy.
return true if self == 1
# Can't be happy because we're starting to loop
return false if cache.include?(self)
# Ask the next number if it's happy, with self added to the list of seen numbers
# You don't actually need the return (it works without it); I just add it for symmetry
return sum_of_squares.happy?(cache << self)
end
end
24.happy? # => false
19.happy? # => true
2.happy? # => false
1.happy? # => true
# ... and so on ...
Hope this helps! :)
def cool
return yield
end
p cool {"yes!"}
The yield keyword instructs Ruby to execute the code in the block. In this example, the block returns the string "yes!". An explicit return statement was used in the cool() method, but this could have been implicit as well.

Understanding Ruby Enumerable#map (with more complex blocks)

Let's say I have a function
def odd_or_even n
if n%2 == 0
return :even
else
return :odd
end
end
And I had a simple enumerable array
simple = [1,2,3,4,5]
And I ran it through map, with my function, using a do-end block:
simple.map do
|n| odd_or_even(n)
end
# => [:odd,:even,:odd,:even,:odd]
How could I do this without, say, defining the function in the first place? For example,
# does not work
simple.map do |n|
if n%2 == 0
return :even
else
return :odd
end
end
# Desired result:
# => [:odd,:even,:odd,:even,:odd]
is not valid ruby, and the compiler gets mad at me for even thinking about it. But how would I implement an equivalent sort of thing, that works?
edit
In reality, the solution to my problem matters to me a lot less than the motivation/reasoning behind it, to help me understand more how ruby blocks work :)
You're so close. Just remove the returns and you're golden.
This is because the block passed to map is a proc (i.e. created with Proc.new), and not a lambda. A return within a proc doesn't just jump out of the proc- it jumps out of the method that executed (i.e. called call on) the proc. A return within a lambda, on the other hand, jumps out of only the lambda.
The proc method returns a lambda in Ruby 1.8, and a Proc in Ruby 1.9. It's probably best to just not use this method and be explicit with which construct you want to use.
I'm guessing you were either in IRB or a plain ruby script when you were trying this out.
a = Proc.new { return }
a.call # fails. Nothing to return from.
def foobar
a = Proc.new { return }
a.call
puts 'hello' # not reached. The return within the proc causes execution to jump out of the foobar method.
end
foobar # succeeds, but does not print 'hello'. The return within the proc jumps out of the foobar method.
b = lambda { return }
b.call # succeeds. The return only returns from the lambda itself.
def bazquux
b = lambda { return }
b.call
puts 'hello' # this is reached. The lambda only returned from itself.
end
bazquux # succeeds, and prints 'hello'
The lesson to learn from this is to use implicit returns unless you can't, I guess.
I suspect this may be a duplicate question, but to give a value out of a block, use next
simple.map do |n|
if n%2 == 0
next :even
else
next :odd
end
end
Shortest variant using Andrew's answer:
simple.map { |n| next :even if n % 2 == 0; :odd }

Resources