omninonsense
omninonsense

Reputation: 6882

How to find each instance of a class in Ruby

Is there a way to get all the objects that are of a certain class in Ruby?

To clarify:

class Pokemon
end

pikatchu = Pokemon.new
charmander = Pokemon.new

So, is there a way I could somehow retrieve references those two objects (pikatchu and charmander)?

I actually thought of shoving it all into a class array via initialize, but that could potentially grow big, and I am assuming there might be a native Ruby approach to it.

Upvotes: 16

Views: 5774

Answers (4)

Jonathan Allard
Jonathan Allard

Reputation: 19249

Slightly adjusted, this is probably a good time to use Enumerator#to_a:

Pokemon.new("Charmander")
#=> #<Pokemon:0x00007fe4226658d8 @name="Charmander">
Pokemon.new("Sandshrew")
#=> #<Pokemon:0x00007fe424822cf0 @name="Sandshrew">

ObjectSpace.each_object(Pokemon).to_a
#=> [#<Pokemon:0x00007fe4226658d8 @name="Charmander">, #<Pokemon:0x00007fe424822cf0 @name="Sandshrew">]

Upvotes: 0

Kevin Cooper
Kevin Cooper

Reputation: 5385

ObjectSpace is a simple solution, but note that you can only add to it; removing objects requires garbage collection and that can get messy.

Here's an example of tracking class members that allows you to clear the count. This could be useful, for example, when writing a dummy class for specs.

class Foo
  @@instances = []

  def initialize
    @@instances << self
  end

  def self.clear
    @@instances.clear
  end

  def self.all
    @@instances
  end
end

Usage:

(1..10).each { Foo.new }
Foo.all.size # 10
Foo.clear
Foo.all.size # 0

Upvotes: 2

Cary Swoveland
Cary Swoveland

Reputation: 110685

Yes, one could use ObjectSpace, but in practice one would simply keep track of instances as they are created.

class Pokemon
  @pokees = []
  self.class.public_send(:attr_reader, :pokees)

  def initialize
    self.class.pokees << self
  end
end

pikatchu = Pokemon.new
  #=> #<Pokemon:0x00005c46da66d640> 
charmander = Pokemon.new
  #=> #<Pokemon:0x00005c46da4cc7f0> 
Pokemon.pokees
  #=> [#<Pokemon:0x00005c46da66d640>, #<Pokemon:0x00005c46da4cc7f0>] 

Upvotes: 2

Grant Sayer
Grant Sayer

Reputation: 2320

The solution is to use ObjectSpace.each_object method like

ObjectSpace.each_object(Pokemon) {|x| p x}

which produces

<Pokemon:0x0000010098aa70>
<Pokemon:0x00000100992158>
 => 2 

Details are discussed in the PickAxe book Chapter 25

Upvotes: 30

Related Questions