简体   繁体   中英

Ruby metaprogramming: instance_eval and class_eval

Seems I am confused between the two methods though I have been using them for a while, I can't understand why the method passengers is not being added to the object in the following code:

class Bus
  def number_of_seats
    42
  end
end

Bus.class_eval do
  define_method :number_of_windows do
    number_of_seats
  end

  def fuel_type
    :diesel
  end
end

Bus.instance_eval do
  define_method :destination do
    'Paris'
  end

  def passengers
    12
  end
end

bus = Bus.new
bus.number_of_windows # => 42
bus.fuel_type # => :diesel
bus.destination # => "Paris"
bus.passengers # => undefined method `passengers' (NoMethodError)

Notes :

  • Tried instance_eval first, just randomly used class_eval and then it too seemed to work!
  • My understanding of instance_eval 's block: The code in the block is run with self set to the object calling instance_eval .
  • My understanding of class_eval 's block: The code in the block is evaluated as if its placed by opening the class of the object calling it. Hence I am puzzled at the class_eval in the above case! I was expecting class_eval on Bus would mean evaluating the block in the class of Bus Class .

You can refer this awesome article on class and instance_eval as to why passengers is not being added to the object.

TL;DR:

Bus.class_eval will create instance methods and Bus.instance_eval will create class methods.

Now, regarding the behavior of destination (which could be called on instance)..... define method when used inside either class_eval or instance_eval is immune to the usual behaviour . Why?.

Because the documentation says so. As per the documentation:

define method - Defines an instance method in the receiver.

Therefore, it does not matter if you use define_method inside class_eval or instance_eval it would always create an instance method.

Source for reference.

Hope this helped :-).

Basically you can't do an instance_eval on a class object when using def . Here's a general way you use instance_eval and class_eval . http://web.stanford.edu/~ouster/cgi-bin/cs142-winter15/classEval.php

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM