2013-01-14 26 views
27

Có cách nào trong Ruby cho một lớp để biết có bao nhiêu trường hợp tồn tại và có thể liệt kê chúng không?Làm cách nào để liệt kê tất cả các đối tượng được tạo từ một lớp trong Ruby?

Dưới đây là một lớp học mẫu:

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 

Bây giờ tôi tạo các đối tượng dự án của lớp này:

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) 

Những gì tôi muốn là phải có phương pháp lớp như Project.allProject.count để trả về một danh sách và đếm các dự án hiện tại.

Làm cách nào để thực hiện việc này?

Trả lời

40

Bạn có thể sử dụng mô-đun ObjectSpace để thực hiện việc này, cụ thể là phương pháp each_object.

ObjectSpace.each_object(Project).count 

Để hoàn chỉnh, dưới đây là cách bạn sẽ sử dụng trong lớp học của bạn (tip mũ để Sawa)

class Project 
    # ... 

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

    def self.count 
    all.count 
    end 
end 
+0

Bạn có cần 'include ObjectSpace' trong lớp để làm việc này không? – onebree

+2

@HunterStevens không, chúng tôi không trộn các mô-đun vào lớp của chúng tôi, chỉ cần gọi một phương pháp trên nó –

+0

** CẢNH BÁO **: giải pháp này có thể làm cho nó dễ dàng để bắn mình vào chân. Nếu bạn không giữ một tham chiếu đến các đối tượng của bạn (ví dụ nếu bạn 'Project.new' mà không gán kết quả cho một cái gì đó), chúng sẽ được thu thập rác tại một số điểm và' ObjectSpace.each_object' rõ ràng sẽ ngừng báo cáo chúng. Sử dụng '@@ instances = []' thay vào đó trong câu trả lời của rohit89 giải quyết vấn đề này bằng cách giữ một tham chiếu đến các đối tượng đó. – vmarquet

5

Một cách để làm là theo dõi nó và khi bạn tạo các phiên bản mới.

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 

Nếu bạn muốn sử dụng ObjectSpace, sau đó nó

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

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

Đây là những gì tôi muốn làm. Nó sẽ làm việc chắc chắn trong tất cả các triển khai Ruby, và có thể được mở rộng cho các mục đích khác nhau nếu cần thiết. –

2

lẽ điều này sẽ làm việc:

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 

Nhưng bạn sẽ phải tự phá hủy các đối tượng này. Có lẽ giải pháp khác có thể được xây dựng dựa trên mô-đun ObjectSpace.

+0

Tôi thích điều này nhưng có thể có một số phản ánh được xây dựng - Không tồn tại trong ruby? Tôi không có đầu mối làm thế nào để sử dụng mô-đun ObjectSpace. Ví dụ thực sự sẽ giúp –

+1

Vâng. ObjectSpace cho phép bạn tương tác với bộ thu gom rác. Đây là thứ mà tôi cố gắng không làm trong mã của tôi. Bạn có thể thử nghiệm với 'ObjectSpace.each_object (Project) .to_a' nhưng tôi không thể giúp bạn nhiều hơn với điều này. – yattering

+0

bất kỳ lý do cụ thể nào tại sao điều này nên tránh? –

4
class Project 
    def self.all; ObjectSpace.each_object(self).to_a end 
    def self.count; all.length end 
end 
Các vấn đề liên quan