Y'all I'm dying here. Can somebody please explain how this works?
For further actions, you may consider blocking this person and/or reporting abuse
Y'all I'm dying here. Can somebody please explain how this works?
For further actions, you may consider blocking this person and/or reporting abuse
JetThoughts Dev -
Alef Ojeda de Oliveira -
Davide Santangelo -
Rails Designer -
Top comments (5)
Hi Tiffany!
define_method
does what the name entails. Allows you to create a method (instance method) on the fly. Let's take a step back.If you were a five year old I would probably use a videogame analogy: the powerups. You're Mario or Zelda or whatever and you are running through the game. You end up picking up a mushroom or a tool and you're (let's ignore the fact that these powerups are usually temporary) able to do something new that you weren't five seconds ago. Basically the videogame added, while you were already playing, a new skill to your player (and only yours if you were playing a multi player game). You can use this skill like if it were there from the beginning, even if you know it was not.
define_method
is like one of those super powers in videogames: allows you to add functions (skills) to your object (a singular player).A quick side note: most examples on the internet use
define_method
for a tangential (but still powerful) usage: shortening the amount of code you have to type. For example: let's say you have aJob
object that can be in a few different states:created
,queued
,running
,completed
,failed
and you want to ask the job if it's running. You might decide to usedefine_method
to iterate over all the possible states (likely defined in constants or a hash) and create methods so you can dojob.running?
.I think the true power of
define_method
is in the analogy with the videogame though, not just to let the developer write less code during the definition of the class.Let's see some code, shall we?
Let's start from the side note, adding methods based on a series of states:
This prints:
Following the game analogy here we're still a little off, because if you look closely we defined the method inside the class
Job
which means that ANY job will have those methods.Let's take it a step further:
This will print:
So, how we give a powerup to Mario but not to luigi? The standard library comes to our rescue:
This will print:
There's still an issue, if we were to inadvertantly ask Luigi to fly this would happen:
Wait, what? The thing is that
define_method
operates on the class by default. What if we really want this to happen just for mario?This is where I get lost in Ruby metaprogramming (I admit I never fully understood this syntax):
this will print:
As you can see only mario now has that method. Fortunately there's a clearer way to create this "method generator", define_singleton_method:
Ruby metaprogramming is definitely a complicated part of the language. :-)
Thank you for this amazing, detailed response! It is complicated but you definitely made it much clearer. :)
You're welcome :)
@mudasobwa thanks for the addition!
Do you agree how weird is that syntax though?
I have to call
extend
on an object but then suddenly have to create a new Module and put my method in it.Ruby's metaprogramming syntax is quite obscure sometimes.
Compare it with Python's, which I find more explicit and clear in this case:
the output:
I'm not saying it's wrong or bad, it's obviously right in the context of how Ruby works. I'm just saying it seems weird if you read it.
To add a method named fly to an object mario I have to extend with a method inside an anonymous module that's going to be "injected" inside mario.
In Python this reads: to add a method named fly to an object mario I have to attach it to mario.
This is what I meant with "I find more explicit and clear".
Any way you put it metaprogramming is super cool, in each language I come across of it :-)
Thanks for the reminder about Elixir, I need to get around it sooner or later.