Max Kirsch
Max Kirsch

Reputation: 461

Understanding Ruby define_method with initialize

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

Answers (1)

Andrés
Andrés

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

Related Questions