2012-04-11 14 views
5

El siguiente es un fragmento de código de Ruby de Why's Poignant Guide to Ruby Chapter 6, donde se intenta demostrar metaprogramming en Ruby:¿Qué hace este código de Ruby ?: def self.metaclass; clase << uno mismo; yo; fin; final

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

no estoy tan bien familiarizado con Ruby, pero ¿es esto lo que se vería en forma expandida?

def self.metaclass 
    def self.self 
    end 
end 

Al menos así es como yo lo entiendo. Sin embargo, todavía no comprende lo que hace este código, exactamente. ¿Cuál es su propósito?

Más adelante en el código, qué añade esto:

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

Si he entendido bien, esta pieza de código añade un nuevo valor a @traits con el nombre y el valor dado. ¿Es eso correcto?

Gracias por su ayuda, aquí está el código fuente completo que me causó problemas, para cualquier persona que quiera verlo:

# 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 

Y en uso:

class Dragon < Creature 
    life(1340)  # tough scales 
    strength(451) # bristling veins 
    charisma(1020) # toothy smile 
    weapon(939) # fire breath 
end 
+3

Lea esto: http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/ – Phrogz

+0

Gracias, esto parece útil. Pero realmente me gustaría entender el significado de def self.metaclass; clase << uno mismo; yo; fin; fin. – LonelyWebCrawler

Respuesta

5
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 

En resumen: lo que está viendo define un método llamado metaclass en la clase Creature (no por instancias). Cuando ejecuta este método, encuentra la metaclase de Creature y lo devuelve.

Read around the 'net para lo que es la "metaclase" de un objeto.

+0

Gracias. ¿Estoy en lo correcto al decir que ya no es necesario con #define_singleton_method? – LonelyWebCrawler

+2

Si solo quiere usar la metaclase para definir un método, no, no es necesario. Pero si desea obtener acceso a la metaclase por otros motivos (por ejemplo, para enumerar todos los métodos), ese método no lo corta. Lo que sí lo corta, sin embargo, es la introducida en 1.9.2 ['singleton_class'] (http://www.ruby-doc.org/core-1.9.3/Object.html#method-i-singleton_class) método que realiza esta misma funcionalidad. – Phrogz

2

En forma expandida se ve exactamente el mismo:

def self.metaclass 
    class << self 
    self 
    end 
end 

Aviso es sólo volver self, que porque se evalúa en el contexto de la metaclase, que en efecto lo class << self hace, self es la metaclase.

Con la introducción de cosas como define_singleton_method, el número de casos en los que necesita tener acceso directamente a la metaclase se está volviendo muy pequeño.

Todo es very complicated y aparentemente una consecuencia del principio de diseño "todo es un objeto".

+0

Whoa, ¿podría aclarar ese párrafo empezando por "Note it's just ..."? – LonelyWebCrawler

+1

Bueno, el contenido del bloque interno es simplemente 'self', que tiene el efecto de devolverlo desde ese bloque porque no se ejecuta ninguna otra instrucción. – tadman