Special Types of eval

There are some variations on the eval theme in the form of the methods named instance_eval, module_eval, and class_eval. The instance_eval method can be called from a specific object, and it provides access to the instance variables of that object. It can be called either with a block or with a string:

instance_eval.rb

class MyClass
 def initialize
   @aVar = "Hello world"
 end
end

ob = MyClass.new
p( ob.instance_eval { @aVar } )         #=> "Hello world"
p( ob.instance_eval( "@aVar" ) )        #=> "Hello world"

The eval method, on the other hand, cannot be called from an object in this way because it is a private method of Object (whereas instance_eval is public):

p( ob.eval( "@aVar" )  )    # This won't work!

In fact, you could explicitly change the visibility of eval by sending its name (the symbol :eval) to the public method. Here I am adding eval as a public method of the Object class:

class Object
    public :eval
end

Indeed, bearing in mind that when you write “free-standing” code you are actually working within the scope of Object, simply entering the following code (without the Object class “wrapper”) would have the same effect:

public :eval

Now you can use eval as a method of the ob variable:

p( ob.eval( "@aVar" ) )        #=> "Hello world"

Note

Strictly speaking, eval is a method of the Kernel module that is mixed into the Object class. In fact, it is the Kernel module that provides most of the functions available as methods of Object.

The modification of class definitions at runtime is sometimes called monkey patching. This may have a part to play in certain highly specialized types of programming, but as a general principle, gratuitous messing about with standard Ruby classes is definitely not recommended. Changing the visibility of methods and adding new behavior to base classes are excellent ways of creating inscrutable code dependencies (in which, for example, your own programs work because you happen to know how you’ve changed a base class, but your colleagues’ programs don’t work because they don’t know how the classes have been changed).

The module_eval and class_eval methods operate on modules and classes rather than on objects. For example, the code shown next adds the xyz method to the X module (here xyz is defined in a block and added as an instance method of the receiver by define_method, which is a method of the Module class), and it adds the abc method to the Y class:

module_eval.rb

module X
end

class Y
    @@x = 10
    include X
end

X::module_eval{ define_method(:xyz){ puts("hello" ) } }
Y::class_eval{ define_method(:abc){ puts("hello, hello" ) } }

Note

When accessing class and module methods, you can use the scope resolution operator :: or a single dot. The scope resolution operator is obligatory when accessing constants and optional when accessing methods.

So, now an object that is an instance of Y will have access to both the abc method of the Y class and the xyz method of the X module that has been mixed into the Y class:

ob = Y.new
ob.xyz        #=> hello
ob.abc        #=> hello, hello

In spite of their names, module_eval and class_eval are functionally identical, and each can be used with either a module or a class:

X::class_eval{ define_method(:xyz2){ puts("hello again" ) } }
Y::module_eval{ define_method(:abc2){ puts("hello, hello again") }}

You can also add methods into Ruby’s standard classes in the same way:

String::class_eval{ define_method(:bye){ puts("goodbye" ) } }
"Hello".bye        #=> goodbye
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.219.220.22