I want to write a method which takes a block and if no block given it should use a default block. So I want to have something like this:
def say_hello(name, &block = ->(name) { puts "Hi, #{name}" })
# do something
end
But when I'm trying to do so I'm getting the syntax error.
I know I can deal with my problem using block_given?
. But I am interested in first approach.
Am I missing something or this is just not possible?
Some answers suggest using block_given?
, but since there is no possibility that a block would be nil
or false
when it is given, you can simply use ||=
.
def say_hello(name, &block)
block ||= ->(name){puts "Hi, #{name}"}
# do something
end
You cannot declare a default block in the method definition, however you can use a little trick to use a custom block if none is given.
def say_hello(name)
block = block_given? ? Proc.new : ->(name) { puts "Hi, #{name}" }
block.call(name)
end
# This example uses a custom block
say_hello('weppos') { |name| puts "Hello, #{name}!" }
# => Hello, weppos!
# This example fallbacks to the default
say_hello('weppos')
# => Hi, weppos!
Let me explain it a little bit. Let's start from a more readable version.
def say_hello(name, &block)
block = block ? block : ->(name) { puts "Hi, #{name}" }
block.call(name)
end
You define the method to accept a block, then you check if block is defined. If not, you assign a custom block. Finally, you execute the block.
Let's enhance it a little bit. You can use block_given? to check if a block is passed
def say_hello(name, &block)
block = block_given? ? block : ->(name) { puts "Hi, #{name}" }
block.call(name)
end
This also allows you to skip the declaration of the block (&block
) in the method definition.
def say_hello(name)
if block_given?
yield name
else
# This is rendundant, but it's for clarity
block = ->(name) { puts "Hi, #{name}" }
block.call(name)
end
end
But, at this point, you can also use the Proc.new
to assign the block to a variable.
def say_hello(name)
block = block_given? ? Proc.new : ->(name) { puts "Hi, #{name}" }
block.call(name)
end
As a final word, I'm trying to understand when this approach would make sense. In most cases, you can probably wrap the code in a class or module and pass it as argument. It's probably better.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With