Jwan622 Jwan622 - 1 month ago 6
Ruby Question

Ruby blocks and procs. Do you not need to specify a second argument when using a Proc?

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?

Answer

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

Procs 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
Comments