Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does this Ruby code do?: def self.metaclass; class << self; self; end; end

The following is a Ruby code snippet from Why's Poignant Guide to Ruby Chapter 6, where he attempts to demonstrate metaprogramming in Ruby:

# Get a metaclass for this class
def self.metaclass; class << self; self; end; end

I am not that well acquainted with Ruby, but is this what it would look like in expanded form?

def self.metaclass
    def self.self
    end
end

At least that's how I understand it. However, it still don't comprehend what this code does, exactly. What is its purpose?

Further on in the code, Why adds this:

arr.each do |a|
   metaclass.instance_eval do
     define_method( a ) do |val|
       @traits ||= {}
       @traits[a] = val
     end
   end
 end

If I understand it correctly, this piece of code adds a new value to @traits with the given name and value. Is that correct?

Thanks for your help, here's the full source code that caused me trouble, for anyone who wants to see it:

# The guts of life force within Dwemthy's Array
class Creature

# Get a metaclass for this class
def self.metaclass; class << self; self; end; end

# Advanced metaprogramming code for nice, clean traits
def self.traits( *arr )
 return @traits if arr.empty?

 # 1. Set up accessors for each variable
 attr_accessor *arr

 # 2. Add a new class method to for each trait.
 arr.each do |a|
   metaclass.instance_eval do
     define_method( a ) do |val|
       @traits ||= {}
       @traits[a] = val
     end
   end
 end

 # 3. For each monster, the `initialize' method
 #    should use the default number for each trait.
 class_eval do
   define_method( :initialize ) do
     self.class.traits.each do |k,v|
       instance_variable_set("@#{k}", v)
     end
   end
 end

end

# Creature attributes are read-only
traits :life, :strength, :charisma, :weapon
end

And in usage:

class Dragon < Creature
    life( 1340 )     # tough scales
    strength( 451 )  # bristling veins
    charisma( 1020 ) # toothy smile
    weapon( 939 )    # fire breath
end
like image 961
LonelyWebCrawler Avatar asked Apr 11 '12 02:04

LonelyWebCrawler


People also ask

What is class self in Ruby?

self is a reserved keyword in Ruby that always refers to the current object and classes are also objects, but the object self refers to frequently changes based on the situation or context. So if you're in an instance, self refers to the instance. If you're in a class, self refers to that class.

What does self refer to in an instance method body?

the method self refers to the object it belongs to. Class definitions are objects too.


2 Answers

class Foo
  def self.bar    # Create a method invoked by Foo.bar instead of Foo.new.bar
    42            # the return value of this method (value of last expression)
  end
end


class Foo
  def self.jim    # Another method on the class itself
    class << self # Change the 'self' to be the metaclass of the current object
      self        # Evaluate the current 'self' as the 'return value' of 
    end           # class<<self…end; and since this is the last expression in
  end             # the method, its value is the return value for the method
end

In short: what you are seeing defines a method named metaclass on the Creature class itself (not for instances). When you run this method, it finds the metaclass of Creature and returns that.

Read around the 'net for what the "metaclass" of an object is.

like image 107
Phrogz Avatar answered Sep 28 '22 18:09

Phrogz


In expanded form it looks exactly the same:

def self.metaclass
  class << self
    self
  end
end

Notice it's just returning self, which because it's evaluated within the context of the metaclass, which in effect what class << self does, self is the metaclass.

With the introduction of things like define_singleton_method, the number of cases where you need to have access to the metaclass directly are becoming very small.

It's all very complicated and seemingly a consequence of the "everything is an object" design principle.

like image 36
tadman Avatar answered Sep 28 '22 19:09

tadman