2013-01-14 11 views
27

Czy jest jakiś sposób w Rubim, aby klasa wiedziała, ile jej wystąpień istnieje i czy może je wymienić?Jak wyświetlić wszystkie obiekty utworzone z klasy w Ruby?

Oto klasa próbki:

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 

Teraz tworzę obiektów projektowych tej klasy:

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) 

Chciałbym to mieć metod klasy jak Project.all i Project.count zwraca listę i liczba bieżących projektów.

Jak to zrobić?

Odpowiedz

40

W tym celu można użyć modułu ObjectSpace, w szczególności metody each_object.

ObjectSpace.each_object(Project).count 

Dla kompletności, oto jak można wykorzystać, że w swojej klasie (Cynk kapelusza do sawa)

class Project 
    # ... 

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

    def self.count 
    all.count 
    end 
end 
+0

Czy chcesz włączyć obiekt ObjectSpace do klasy, aby to działało? – onebree

+2

@HunterStevens nie, nie mieszamy modułu do naszej klasy, po prostu wywołując na nim metodę –

+0

** OSTRZEŻENIE **: to rozwiązanie może ułatwić strzelanie sobie w stopę. Jeśli nie zachowujesz odniesienia do twoich obiektów (na przykład, jeśli zrobisz "Project.new" bez przypisywania wyniku do czegoś), będą one w pewnym momencie śmieciami, a obiekt "ObjectSpace.each_object" oczywiście przestanie je zgłaszać. Użycie '@@ instances = []' zamiast jak w odpowiedzi rohit89 rozwiązuje ten problem, zachowując odniesienie do tych obiektów. – vmarquet

5

Jednym ze sposobów jest śledzenie go podczas tworzenia nowych instancji.

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 

Jeśli chcesz użyć ObjectSpace, wówczas jej

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

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

To co bym zrobiła. Będzie działał na pewno we wszystkich implementacjach Ruby i może być rozszerzony do różnych celów, jeśli zajdzie taka potrzeba. –

2

Może to będzie działać:

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 

Ale trzeba będzie ręcznie zniszczyć te obiekty. Może inne rozwiązanie można zbudować w oparciu o moduł ObjectSpace.

+0

Podoba mi się to, ale czy może być coś w rodzaju refleksji - czyż nie istnieje w rubinach? Nie mam pojęcia, jak korzystać z modułu ObjectSpace. Przykład naprawdę pomoże –

+1

Dobrze. ObjectSpace pozwala na interakcję z garbage collectorem. To jest coś, czego staram się nie robić w moim kodzie. Możesz eksperymentować z 'ObjectSpace.each_object (Project) .to_a', ale nie mogę ci już z tym pomóc. – yattering

+0

jakiś szczególny powód, dla którego należy tego unikać? –

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