Meta programming

From Logic Wiki
Jump to: navigation, search


Meta Programming can be defined as writing codes which writes codes.

Example 1

Look at the example below

class Account
  attr_accessor :name, :address, :email, :notes, :bank_balance
end

user_info = {
              :name => "Ali",
              :address => "Timperley",
              :email => "ali@iybar.com",
              :notes => "good guy",
              :bank_balance => 0
            }

account = new Account.new

account.name - user_info[:name]
account.address = user_info[:address]
account.email = user_info[:email]
account_notes = user_info[:notes]
account_bank_balance = user_info[:bank_balance]

This is the classic way of creating a new user and fill the object. Take a look at it now

class Account
  attr_accessor :name, :address, :email, :notes, :bank_balance

  def assign_values(values)
    values.each_key do |k|
      self.send("#{k}=)", values[k])
    end
end

user_info = {
              :name => "Ali",
              :address => "Timperley",
              :email => "ali@iybar.com",
              :notes => "good guy",
              :bank_balance => 0
            }

account = new Account.new
account.assign_values(user_info)

what happens here is in the self.send line we are saying something like this

    self.send("#{k}=)", values[k])
       |    |     |
       V    V     V
    self.name = values[k] 

Example 2

class String
  def self.add_new_method(name)
    send(:define_method, name){
      puts "You created a method named #{name}, and you are in it right now!"
    }
  end
end

String.add_new_method("Ali")

"string".Ali

here we used define_method method to create a method in a class. This newly on the fly created method writes some text. When we call it, it creates a method named Ali and this method writes a text. A bit complex huh ?

Example 3

class Array
  def self.add_new_method(name, &logic)
    Array.send(:define_method, name) do |*args|
    locgic.call(self, *args)
  end
end

Array.add_new_method("prepend_array") do |me, x|
  me.each{ |e| puts "#{x} #{e} "}
end 

["cat", "dog", "bird"].prepend_array("Animal:")

self and me in the codes above are necessary to make each aware of which object it's in

Example 4

class Model
  @all_fields = []
  
  def self.field(name)
    @@all_fields << name
    attr_accessor(name)
  end

  def initialize
    @fields = @@all_fields
  end
end

class Account < Model
  field :balance
  field :address
  field :name
end

a = Account.new
a.balance = 1000000
a.address = "212 main St"
a.name = "Mr Who"

puts a.inspect