2012-04-11 3 views
5

seguito è riportato un frammento di codice di Ruby da Why's Poignant Guide to Ruby Chapter 6, dove si tenta di dimostrare metaprogrammazione in Ruby:Cosa fa questo codice Ruby ?: def self.metaclass; classe << auto; se stesso; fine; fine

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

non sto che conosco bene Ruby, ma è questo quello che sarebbe simile in forma estesa?

def self.metaclass 
    def self.self 
    end 
end 

Almeno è così che ho capito. Tuttavia, continua a non comprendere ciò che questo codice fa, esattamente. Qual è il suo scopo?

Più avanti nel codice, perché aggiunge questo:

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

Se ho ben capito, questo pezzo di codice aggiunge un nuovo valore per @traits con il nome e il valore dato. È corretto?

Grazie per il vostro aiuto, ecco il codice sorgente completo che mi ha causato problemi, per chi vuole vederlo:

# 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 

E in uso:

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

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

+0

Grazie, questo sembra utile. Ma mi piacerebbe davvero capire il significato di def self.metaclass; classe << auto; se stesso; fine; fine. – LonelyWebCrawler

risposta

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 

In breve: ciò che viene visualizzato definisce un metodo denominato metaclass nella classe Creature (non per le istanze). Quando si esegue questo metodo, trova il metaclasse di Creature e lo restituisce.

Read around the 'net per ciò che è il "metaclasse" di un oggetto.

+0

Grazie. Ho corretto che questo non è più necessario con #define_singleton_method? – LonelyWebCrawler

+2

Se si desidera utilizzare solo la metaclasse per definire un metodo, no, non è necessario. Ma se vuoi ottenere l'accesso al metaclasse per altri motivi (ad es. Per elencare tutti i metodi) quel metodo non lo taglia. Ciò che lo taglia, tuttavia, è l'introduzione-in-1.9.2 ['singleton_class'] (http://www.ruby-doc.org/core-1.9.3/Object.html#method-i-singleton_class) metodo che esegue questa stessa funzionalità. – Phrogz

2

In forma estesa sembra esattamente lo stesso:

def self.metaclass 
    class << self 
    self 
    end 
end 

Avviso è solo il ritorno self, che perché è valutato nel contesto del metaclasse, che in effetti ciò che class << self fa, self è la metaclasse.

Con l'introduzione di elementi come define_singleton_method, il numero di casi in cui è necessario accedere direttamente al metaclass sta diventando molto piccolo.

È tutto very complicated e apparentemente una conseguenza del principio di progettazione "tutto è un oggetto".

+0

Whoa, potresti chiarire che il paragrafo inizia con "Notate che è solo ..."? – LonelyWebCrawler

+1

Bene, il contenuto del blocco interno è semplicemente 'self' che ha l'effetto di restituirlo da quel blocco perché non viene eseguita alcuna altra istruzione. – tadman