Instance_eval does not work with do/end block, onl

2019-02-18 23:52发布

问题:

This question already has an answer here:

  • Ruby block and unparenthesized arguments 1 answer
  • Ruby Block Syntax Error [duplicate] 1 answer

If I have a class:

class KlassWithSecret
  def initialize
    @secret = 99
  end
end

and run:

puts KlassWithSecret.new.instance_eval { @secret }

it prints 99, but if I run:

puts KlassWithSecret.new.instance_eval do
  @secret
end

It returns an error: `instance_eval': wrong number of arguments (0 for 1..3) (ArgumentError)

Why can't I use do/end blocks with instance_eval?

P.S. I am using Ruby 2.1.0.

回答1:

It's because when you pass block with curly braces, it is passed to instance_eval method. But if you pass it with do-end, it's passed to puts method, so instance_eval doesn't get block and raises an error.



回答2:

Enclose expression supplied to puts in parenthesis because lower precedence of do..end block.

puts( KlassWithSecret.new.instance_eval do
  @secret
end )

or use brace syntax of block

puts KlassWithSecret.new.instance_eval {
  @secret
}


回答3:

This is because when you use do..end block, the block is passed to the puts function. The code with do..end block will work if you write it like this

puts(KlassWithSecret.new.instance_eval do
  @secret
end)


回答4:

a = Proc.new {@secret}
puts KlassWithSecret.new.instance_eval(&a)
# 99

It say that puts KlaccWithSecret do @secret end does not gain the Proc(block).



回答5:

Ruby(2.0.0) works. Code:

KlassWithSecret.new.instance_eval do
  p @secret
end
# 99

no problem.