Meta Programming is this concept of code writing code. It sounds sophisticated and a 10x multiplier on development productivity.

However, in practical development you’ll come to find that you’ll hardly ever have to use it. But it’s still a good thing to know in case a code base you run across uses it.

As an added bonus I’ll show you that PHP can accomplish the same functionality with it’s Magic Methods.

Magic Methods in PHP

Although PHP is a static language, there are a few tricks up it’s sleeve to accomplish dynamic code. By dynamic code I mean code that is not typed by the developer but code that is created at runtime.

PHP offers a slew of Magic Methods that allow us to hook into the Class lifecycle.

You’re already familiar with one such Magic Method - __construct(). The __construct() method in a class is what’s commonly referred to as the constructor. This method is magically called when an object is instantiating.

The other Magic Methods PHP offers follow the same syntax, 2 underscores __ followed by the Magic Method name.

Overloading a.k.a. Creating Methods at Runtime

Overloading is the idea of creating publicly accessible methods on a PHP object at runtime. Sound familiar?

We have 2 Magic Methods available to us to create this behavior:

  • __call()
  • __callStatic()

They are essentially the same thing, but __callStatic() is used in a static a.k.a. class method context.

__call() is automatically invoked if it’s defined on a class and a method called is not defined.

Let’s return to our Cat:

class Cat {
  public function meow() {
    echo 'meow';
  }
}

Now, if we tried to call a method that didn’t exist on Cat, then PHP would be angry at us:

$cat = new Cat
$cat->eatCheese();

=> Method `eatCheese` not defined on class Cat.

Creating a Dynamic Method

Since cat’s can and will eat a plethora of things: cheese, tuna, salmon, shoe laces, etc. let’s create a dynamic method that will respond to eat*:

class Cat {
  public function meow() {
    echo 'meow';
  }

  public function __call($method) {
    // $method is the missing method name we've called on the object
    // in this example we'll say 'eatCheese'

    // first we'll remove 'eat' from 'eatCheese'
    $food = str_replace('eat', '', $method);
    // then we'll lower case 'Cheese' to 'cheese'
    $food = strtolower($food);

    echo "nom nom $food";
  }
}

Now let’s see it in action:

$cat = new Cat;

$cat->eatCheese();

=> 'nom nom cheese'

We can now have the cat eat anything:

$cat = new Cat;

$cat->eatTuna();
$cat->eatSalmon();
$cat->eatGrass();

=> 'nom nom tuna'
=> 'nom nom salmon'
=> 'nom nom grass'

Creating Dynamic Static Methods

You can create dynamic static methods as well:

class Cat {
  public function meow() {
    echo 'meow';
  }

  public function __callStatic($method) {
    // $method is the missing method name we've called on the object
    // in this example we'll say 'eatCheese'

    // first we'll remove 'eat' from 'eatCheese'
    $food = str_replace('eat', '', $method);
    // then we'll lower case 'Cheese' to 'cheese'
    $food = strtolower($food);

    echo "nom nom $food";
  }
}

Cat::eatTuna();
Cat::eatPasta();

=> 'nom nom tuna'
=> 'nom nom pasta'

Creating Methods Dynamically in Ruby a.k.a. Meta Programming

In a way, Ruby has it’s own set of “Magic Methods” like PHP does. The one we’re going to explore here has the same functionality as PHP’s __call().

Like other things in Ruby this method name might be easier to remember. It’s called method_missing. Just like PHP’s __call() Magic Method, Ruby’s method_missing takes the method name as the first argument.

In the example below we’ll recreate what we accomplished with our PHP Cat class and allow an instance of our Ruby Cat class to eat*.


class Cat
  def meow
    puts 'meow'
  end

  def method_missing(method)
    # replace the 'eat_' in 'eat_cheese' with an empty string
    food = method.sub('eat_', '')

    puts "nom nom #{food}"
  end
end

You may have noticed the minor difference between code style between camelCasing in PHP and underscoring in Ruby means we don’t have to lowercase our dynamic method call here.

Now let’s use our Cat and give it food dynamically:


cat = Cat.new

cat.eat_tuna
cat.eat_salmon
cat.eat_grass

=> 'nom nom tuna'
=> 'nom nom salmon'
=> 'nom nom grass'

Creating a Dynamic Class Method in Ruby

Just like leveraging method_missing to populate missing methods in Ruby Objects, we can use the same method at the class level to create dynamic class methods:


class Cat
  def meow
    puts 'meow'
  end

  # The only change we made is attaching the method to the class by prefixing it with `self.`
  def self.method_missing(method)
    # replace the 'eat_' in 'eat_cheese' with an empty string
    food = method.sub('eat_', '')

    puts "nom nom #{food}"
  end
end

Now that we’ve called method_missing on the class by using self, we can have our Cat eat all sorts of things without being instantiated:


Cat.eat_pasta
Cat.eat_ham

=> 'nom nom pasta'
=> 'nom nom ham'

This is just an introductory guide to Meta Programming. The rabbit hole goes deeper but this will give you an idea of how it works if you ever come across it in the wild.

Last Warning

Like PHP, you can get 100% of your work done in a static way with Ruby. There are very few times when you should consider dynamic programming as a choice. For your future self’s santity and anyone else reading your code, I would refrain from trying this unless it’s painful to engineer a solution without it.

And also note that this is just a 1:1 example of dynamic PHP to dynamic Ruby. In reality, Ruby’s meta programming is a very rich subject. There are times when metaprogramming makes sense, but most of the time it’s a knive that doesn’t need to be pulled out the drawer.

Once you finish this series, you’ll be ready to dive deeper into metaprogramming, and I encourage it.