Ruby Ruby Blocks Ruby Blocks Calling Blocks

Francesco Mari
Francesco Mari
10,924 Points

Why I cant print the returning value of the block method?

Hi! I'm trying to directly printing the returning value of the block method "run". This code runs without issues:

class Benchmarker
  def run(description, &block)
    start_time = Time.now
    block.call
    end_time = Time.now
    elapsed = end_time - start_time
    puts
    return "#{elapsed} seconds elapsed for #{description}"
  end
end

benchmarker = Benchmarker.new
result = benchmarker.run "sleeping random amount of time" do
  5.times do
    print "."
    sleep(rand(0.1..1.0))
  end
end

puts result

but if I try to print directly the result of the block method:

class Benchmarker
  def run(description, &block)
    start_time = Time.now
    block.call
    end_time = Time.now
    elapsed = end_time - start_time
    puts
    return "#{elapsed} seconds elapsed for #{description}"
  end
end

benchmarker = Benchmarker.new
puts benchmarker.run "sleeping random amount of time" do
  5.times do
    print "."
    sleep(rand(0.1..1.0))
  end
end

I got this error:

in `run': undefined method `call' for nil:NilClass (NoMethodError)
    from benchmarker.rb:13:in `<main>'

2 Answers

Kourosh Raeen
Kourosh Raeen
23,710 Points

Hi Francesco - Here's the syntax that works:

puts benchmarker.run("sleeping random amount of time") {
  5.times do
    print "."
    sleep(rand(0.1..1.0))
  end
}

Don't ask me why this works and not yours because I don't have a good answer as of now :smiley:, but it seems like with your syntax the block is not passed into the function so you end up calling the call method, pardon the pun, on nil. If you find a good answer let me know.

If you do the following:

class Benchmarker
  def run(description, &block)
    start_time = Time.now
    block.call
    end_time = Time.now
    elapsed = end_time - start_time
    puts
    return "#{elapsed} seconds elapsed for #{description}"
  end
end

benchmarker = Benchmarker.new
puts( benchmarker.run "sleeping random amount of time" do
    5.times do
      print "."
      sleep(rand(0.1..1.0))
    end
  end
)

it runs without error.

Since you aren't explicit with the parenthesis, the interpreter probably assumes this:

 puts( benchmarker.run "sleeping random amount of time" ) do

which gives the same error since the block is now passed to "puts" and not "benchmarker.run"