instance_eval and class_eval | Metaprogramming in ruby -3
change the behaviour of your classes and objects on the fly
Instance_eval
let’s write some basic code for the User class
class User
def initialize(first_name, last_name)
@first_name = first_name
@last_name = last_name
end
def first_name
@first_name
end
end
user = User.new('pratik', 'vyas')
user2 = User.new('milan', 'kumar')
user.instance_eval do
def last_name
@last_name
end
end
user.last_name # => 'vyas'
user2.last_name # => undefined method `last_name' for #<User:0x000055fffe075f68 @first_name="milan", @last_name="kumar">
In the above code we can see that user2.last_name has raised the error. It is because instance_eval evaluates the code in context of instance. which user.
So what will happen if in the place of user.instance_eval if we write User.instance_eval the code will be evaluated in terms of User object itself. Which is a User class itself. Which again means that it will create a class method for ourself.
Let’s try it out.
class User
def initialize(first_name, last_name)
@first_name = first_name
@last_name = last_name
end
def first_name
@first_name
end
end
user = User.new('pratik', 'vyas')
user2 = User.new('milan', 'kumar')
user.instance_eval do
def last_name
@last_name
end
end
User.instance_eval do
def whoami
'You are the class method'
end
end
user.last_name # => 'vyas'
user2.last_name # => undefined method `last_name' for #<User:0x000055fffe075f68 @first_name="milan", @last_name="kumar">
User.whoami # => 'you are the class method'
The above code is executed in context of User instance. That’s the reason we got the class method whoami
Class_eval
class_eval evaluates the code in context of class itself instead of an instance. Let’s see
class User
def initialize(first_name, last_name)
@first_name = first_name
@last_name = last_name
end
def first_name
@first_name
end
end
user = User.new('pratik', 'vyas')
user2 = User.new('milan', 'kumar')
User.class_eval do
def last_name
@last_name
end
end
user.last_name # => 'vyas'
user2.last_name # => 'kumar'
In the above the class_eval evaluated the code in context of User class. So we will have the instance method last_name for all user objects.
class_eval basically reopens the class and add a method inside it just like this
class User
def initialize(first_name, last_name)
@first_name = first_name
@last_name = last_name
end
def first_name
@first_name
end
end
user = User.new('pratik', 'vyas')
user2 = User.new('milan', 'kumar')
# Reopening the User class
class User
def last_name
@last_name
end
end
user.last_name # => 'vyas'
user2.last_name # => 'kumar'
Thanks for giving it a read!
Happy coding :)