1

Looking at this instance_eval example:

class KlassWithSecret
    def initialize
        @secret = 99
    end
    def get
        @secret
    end
end
k = KlassWithSecret.new
k.instance_eval { @secret } 
print k.get

I added a get method to KlassWithSecret.

Here's the results of running the program:

>ruby InstanceEvalTest.rb
99

So, does instance_eval here somehow call the initialize method?

I think that I understand this method a bit from reading this helpful post. But I'm still in the dark.

Community
  • 1
  • 1
Kevin Meredith
  • 41,036
  • 63
  • 209
  • 384
  • so, in this example, `instance_eval` is not doing anything with `@secret`, no? I'm trying to understand why, in this example, `@secret` is passed in. – Kevin Meredith Nov 30 '14 at 03:25
  • @cary can you answer the question, not put the comments here? Seems your explanation is better than August. – BMW Nov 30 '14 at 06:28
  • 1
    You asked me to put my comments in the form of an answer. I said I'd do that the following day, but forgot to do so so. It's now done--sorry for the delay. – Cary Swoveland Dec 06 '14 at 18:35

2 Answers2

2

The initialize method is automatically called by Ruby after the new method is called. instance_eval runs the block you supply in the context of the object. This means it has access to anything a normal line of code in the KlassWithSecret class would have.

@secret is an instance variable, meaning that it belongs to an instance of KlassWithSecret. Because we're evaluating { @secret } in the context of a KlassWithSecret instance, we can access @secret.

August
  • 12,410
  • 3
  • 35
  • 51
2

k.instance_eval gives you access to all of the instance variables (here just @secret) and all private methods (if there were any). It executes the code in the block, which in this case returns 99, the value of @secret. Then print k.get prints that value and returns nil.

If the block had been { @secret = 'cat' }, k.instance_val would have changed the value of @secret (and returned the new value).

When using instance_eval, class_eval, class < self and other metaprogramming constructs, you mind find it helpful to track the value of self using puts statements. For example:

k = KlassWithSecret.new #=> #<KlassWithSecret:0x00000101897810 @secret=99>
self #=> main
k.instance_eval { puts "self=#{self}"; @secret }
"self=#<KlassWithSecret:0x00000101897810>"
  #=> 99
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100