PHP to Ruby

Meta Programming in Ruby compared to PHP's Magic Methods

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:

classCat{publicfunctionmeow(){echo'meow';}}

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

$cat=newCat$cat->eatCheese();=>Method`eatCheese`notdefinedonclassCat.

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*:

classCat{publicfunctionmeow(){echo'meow';}publicfunction__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";}}

Creating Dynamic Static Methods

You can create dynamic static methods as well:

classCat{publicfunctionmeow(){echo'meow';}publicfunction__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*.

classCatdefmeowputs'meow'enddefmethod_missing(method)# replace the 'eat_' in 'eat_cheese' with an empty stringfood=method.sub('eat_','')puts"nom nom #{food}"endend

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.

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:

classCatdefmeowputs'meow'end# The only change we made is attaching the method to the class by prefixing it with `self.`defself.method_missing(method)# replace the 'eat_' in 'eat_cheese' with an empty stringfood=method.sub('eat_','')puts"nom nom #{food}"endend

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_pastaCat.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.