Ruby metaprogramming I

Michal Sz
akra-polska
Published in
2 min readJul 10, 2018

What do we mean by metaprogramming?

Term metaprogramming refers to way of coding which a program has knowledge about itself and can manipulate itself. This technic give programmer to write more dynamic code — “code which write code”.

The code which changes a class or an instance at runtime.

How Ruby does it?

In Ruby, everything is executable, even the class definitions. But it doesn’t end there. In ruby, you can open a class and modify it. Good example of this modification is monkey-patching.

class String
def up_letters
upcase
end
end

slogan = 'Hello'
puts slogan.up_letters
# HELLO
class Person
attr_accessor :name, :email
attr_accessor :role def initialize(role:, age:) @age = age @role = role end
private
def age @age end
end

Sadly with above Person class we are not able to get access to age attribute since the age is private. To handle this kind case we can use send to get access to it.

admin = Person.new(role: 'admin', age: 35)admin.send(:age)#35

Dynamic methods using define_method

We are going to extend our class with method to check which role person has. Let’s image that our Person class will have 3 roles: super_admin, admin, client. Our plan is to have 3 methods ie. is_admin?, is_super_admin? and is_client?.

class Person
.
.
.
['admin', 'super_admin', 'client'].each do |role| define_method("is_#{role}?") do @role == role end
.
.
.
end

Above we used define_method (from Module) to implement three methods is_admin?, is_super_admin? and is_client?. This approach allow reduce amount of code in Person class.

Extend instance by instance_eval

The method instance_eval allow us to define method only for one particular instance.

admin = Person.new(role: 'admin', age: 35)super_admin = Person.new(role: 'super_admin', age: 35)
super_admin.instance_eval do
def access_to_all?
true
endendputs super_admin.access_o_all?
puts admin.access_o_all?
trueundefined method `access_to_all?' for #<Person:0x00007fa04f8a93b8> (NoMethodError)

The above NoMethodError we got on admin instance — since we have called instance_eval only on super_admin instance.

Person.class_eval do  def access_to_all?    is_admin? || is_super_admin?  endend

Above code solves problem for each instance admin and super_admin.

Summary

Ruby allows write code which change class or instance during runtime.

Advantages

This sort of coding is very powerful and You can achieve the same result with less code.

  • flexibility code
  • less code
  • delegate calls method to other object by using method_missing

Disadvantages

Over use metaprogramming may that the code is hard to:

  • read
  • debug
  • search

--

--