Reputation: 461
So, I'm currently learning about metaprogramming in Ruby and I want to fully understand what is happening behind the scenes.
I followed a tutorial where I included some of the methods in my own small project, an importer for CSV files and I have difficulties to wrap my hand around one of the methods used.
I know that the define_method
method in Ruby exists to create methods "on the fly", which is great. Now, in the tutorial the method initialize
to instantiate an object from a class is defined with this method, so basically it looks like this:
class Foo
def self.define_initialize(attributes)
define_method(:initialize) do |*args|
attributes.zip(args) do |attribute, value|
instance_variable_set("@#{attribute}", value)
end
end
end
end
Next, in an initializer of the other class first this method is called with Foo.define_initialize(attributes)
, where attributes are the header row from the CSV file like ["attr_1", "attr_2", ...]
, so the *args
are not provided yet.
Then in the next step a loop loops over the the data:
@foos = data[1..-1].map do |d|
Foo.new(*d)
end
So here the *d
get passed as the *args
to the initialize method respectively to the block.
So, is it right that when Foo.define_initialize gets called, the method is just "built" for later calls to the class? So I theoretically get a class which now has this method like:
def initialize(*args)
... do stuff
end
Because otherwise, it had to throw an exception like "missing arguments" or something - so, in other words, it just defines the method like the name implies.
I hope that I made my question clear enough, cause as a Rails developer coming from the "Rails magic" I would really like to understand what is happening behind the scenes in some cases :).
Thanks for any helpful reply!
Upvotes: 1
Views: 546
Reputation: 624
Short answer, yes, long answer:
First, let's start explaining in a really (REALLY) simple way, how metaprogramming works on Ruby. In Ruby, the definition of anything is never close, that means that you can add, update, or delete the behavior of anything (really, almost anything) at any moment. So, if you want to add a method to Object
class, you are allowed, same for delete or update.
In your example, you are doing nothing more than update or create the initialize
method of a given class. Note that initialize
is not mandatory, because ruby builds a default "blank" one for you if you didn't create one. You may think, "what happens if the initialize
method already exist?" and the answer is "nothing". I mean, ruby is going to rewrite the initialize method again, and new Foo.new
calls are going to call the new initialize
.
Upvotes: 2