Adding methods or attributes to a class/module “on-the-fly” is a pretty common pattern in Ruby ( activerecord , activesupport , rake , rack , etc..).

To do so, we can use the Module#class_eval and Module#module_eval methods.

What are the main differences between these 2 methods ?

Before to start

I’m thrilled to share with you our latest project: Fun Facts about Ruby — Volume 1

Please feel free to spread the word and share this post! 🙏

Thank you for your time!

class_eval

In Ruby, when we want to add a method to a class we can use the Module#class_eval method. This method accepts a String or a block as argument

array_second = <<-RUBY

def second

self[1]

end

RUBY Array.class_eval(array_second) String.class_eval do

def /(delimiter)

split(delimiter)

end

end $> [1,2,3].second

=> 2

$> "1,2,3" / ','

=> ["1", "2", "3"]

The call to Array.class_eval(array_second) adds the method second to any instance of Array by passing a String that will be evaluated in the context of the class Array .

The call to String.class_eval with a block will evaluate the content of the block in the context of the class String . Here it’ll add a String#/(delimiter) method — that we can use as operator — to any instance of String .

NB: feel free to read this article about heredocs if the <<-RUBY syntax is unfamiliar to you

module_eval

The Module#module_eval is the equivalent of Module#class_eval for modules

module Commentable

def add_comment(comment)

self.comments << comment

end def comments

@comments ||= []

end

end Commentable.module_eval do

def comment_count

comments.count

end

end class Post

include Commentable

end $> post = Post.new

=> #<Post:0x00007fd9ac0238b0>

$> post.add_comment("Very nice !")

=> ["Very nice !"]

$> post.comment_count

=> 1

two skins for one core

We said that class_eval is used for adding methods and attributes to an existing class.

And module_eval is used for adding methods and attributes to an existing modules.

But this is just a convention..

In effect, class_eval is an alias for module_eval .

Let’s have a look to the Ruby code source to confirm the previous affirmation.

in ruby/vm_eval.c

rb_define_method(rb_cModule, "module_eval", rb_mod_module_eval, -1); rb_define_method(rb_cModule, "class_eval", rb_mod_module_eval, -1);

As we can see the module_eval and class_eval share the same C function named rb_mod_module_eval() .

As this C function designation includes module_eval we can say that class_eval is an alias to module_eval .

Voilà !

May I have your attention please 🎤🎤

Feel free to subscribe here: www.rubycademy.com