2013-01-14 1 views
27

C'è un modo in Ruby per una classe per sapere quante istanze esistono e può elencarle?Come posso elencare tutti gli oggetti creati da una classe in Ruby?

Ecco una lezione di prova:

class Project 

    attr_accessor :name, :tasks 

    def initialize(options) 
    @name = options[:name] 
    @tasks = options[:tasks] 
    end 

    def self.all 
    # return listing of project objects 
    end 

    def self.count 
      # return a count of existing projects 
    end 


end 

Ora mi creano oggetti del progetto di questa classe:

options1 = { 
    name: 'Building house', 
    priority: 2, 
    tasks: [] 
} 

options2 = { 
    name: 'Getting a loan from the Bank', 
    priority: 3, 
    tasks: [] 
} 

@project1 = Project.new(options1) 
@project2 = Project.new(options2) 

Quello che vorrei è avere metodi di classe come Project.all e Project.count per restituire un elenco e il conteggio dei progetti attuali.

Come posso fare?

risposta

40

È possibile utilizzare il modulo ObjectSpace per eseguire questa operazione, in particolare il metodo each_object.

ObjectSpace.each_object(Project).count 

Per completezza, ecco come si usa che nella tua classe (Punta di cappello a Sawa)

class Project 
    # ... 

    def self.all 
    ObjectSpace.each_object(self).to_a 
    end 

    def self.count 
    all.count 
    end 
end 
+0

Devi 'includere ObjectSpace' nella classe affinché funzioni? – onebree

+2

@HunterStevens no, non stiamo mescolando il modulo nella nostra classe, solo chiamando un metodo su di esso –

+0

** AVVISO **: questa soluzione può rendere facile spararsi nel piede. Se non si mantiene un riferimento ai propri oggetti (ad esempio se si esegue il comando 'Project.new' senza assegnare il risultato a qualcosa), a un certo punto verranno raccolti garbage collection e' ObjectSpace.each_object' ovviamente smetterà di segnalarli. Usando '@@ instances = []' invece come nella risposta di rohit89 si risolve questo problema mantenendo un riferimento a quegli oggetti. – vmarquet

5

Un modo è quello di tenere traccia di esso come e quando si creano nuove istanze.

class Project 

    @@count = 0 
    @@instances = [] 

    def initialize(options) 
      @@count += 1 
      @@instances << self 
    end 

    def self.all 
     @@instances.inspect 
    end 

    def self.count 
     @@count 
    end 

end 

Se si desidera utilizzare ObjectSpace, allora la sua

def self.count 
    ObjectSpace.each_object(self).count 
end 

def self.all 
    ObjectSpace.each_object(self).to_a 
end 
+0

Questo è quello che mi piacerebbe fare. Funzionerà sicuramente in tutte le implementazioni di Ruby e potrà essere esteso per scopi diversi se necessario. –

2

Forse questo funzionerà:

class Project 
    class << self; attr_accessor :instances; end 

    attr_accessor :name, :tasks 

    def initialize(options) 
    @name = options[:name] 
    @tasks = options[:tasks] 

    self.class.instances ||= Array.new 
    self.class.instances << self 
    end 

    def self.all 
    # return listing of project objects 
    instances ? instances.dup : [] 
    end 

    def self.count 
    # return a count of existing projects 
    instances ? instances.count : 0 
    end 

    def destroy 
    self.class.instances.delete(self) 
    end 
end 

ma si dovrà distruggere manualmente questi oggetti. Forse un'altra soluzione può essere costruita sulla base del modulo ObjectSpace.

+0

Mi piace, ma può esserci qualche riflesso nel costruito - Non esiste nel rubino? Non ho idea di come usare il modulo ObjectSpace. Esempio sarebbe davvero di aiuto –

+1

Bene. ObjectSpace ti consente di interagire con Garbage Collector. Questa è roba che cerco di non fare nel mio codice. Puoi sperimentare con 'ObjectSpace.each_object (Project) .to_a' ma non posso aiutarti di più con questo. – yattering

+0

qualche motivo particolare per cui questo dovrebbe essere evitato? –

4
class Project 
    def self.all; ObjectSpace.each_object(self).to_a end 
    def self.count; all.length end 
end