Reputation: 11639
I read this about Ruby Procs:
class Monkey
# Monkey.tell_ape { "ook!" }
# ape: ook!
# => nil
def self.tell_ape
tell("ape", &Proc.new)
end
def self.tell(name)
puts "#{name}: #{yield}"
end
end
In that above example... the block is being passed to .tell_ape
and Proc.new
is converting the block to a proc right? However... doesn't the .tell
method need to accept a &block
parameter in its method signature? We're passing a Proc as an argument to the .tell
method right? If so... doesn't the .tell
method need to have a second parameter?
Upvotes: 0
Views: 85
Reputation: 369438
All methods always take exactly one optional block argument:
puts('Hello') { I.can.write.whatever.i.want.here.because.the.block.is.never.ran }
# Hello
def foo; end
foo { same.here }
The whole point of blocks is that they are syntactically and semantically lightweight, and one of the ways this is achieved is that they are anonymous:
def bar; yield if block_given? end
# Note how I didn't need to say where to yield to and what block to check since
# there can only ever be at most one anyway.
bar { puts 'Hello' }
# Hello
They are also not objects.
But if it doesn't have a name and isn't even an object, then how can you refer to it? Well, that's where &
parameters come in: they tell Ruby to convert the block to a proper Proc
object and bind it to a parameter:
def baz(&blk) p blk end
baz { again.we.are.not.calling.the.block }
# #<Proc:0xdeadbeef081542@(pry):42>
# ^^^^^^^ Debugging representation of a Proc object
Proc
s have a call
method which executes them (there's also a piece of syntactic sugar for calling call
):
def quux(grault, &blk)
blk.(grault)
yield grault
end
quux('Hello') {|garply| puts garply }
# Hello
# Hello
Upvotes: 2
Reputation: 2204
When you have a method that receives a block, the yield keyword will execute the block, you don't have to pass it explicitly as an argument.
def foo
yield 1
end
is equivalent to:
def foo(&block)
block.call(1)
end
Upvotes: 1