Question

I want to track all instances of a class, and the following code works perfectly, but isn't very DRY.

class BaseClass
end

class ClassA < BaseClass
  @@instances = []
  attr_accessor :name

  def initialize(name)
    @name = name
    @@instances << self
  end
  def self.list
    @@instances
  end
  def to_s
    @name
  end
end

class ClassB < BaseClass
  @@instances = []
  attr_accessor :name

  def initialize(name)
    @name = name
    @@instances << self
  end
  def self.list
    @@instances
  end
  def to_s
    @name
  end
end

puts "Creating instances"
a = ClassA.new "a"
aa = ClassA.new "aa"
b = ClassB.new "b"

puts "Listing for ClassA"
puts ClassA.list
puts "Listing for ClassB"
puts ClassB.list

The output of which becomes

Creating instances
Listing for ClassA
a
aa
Listing for ClassB
b

Perfect. However, when I try to dedupe it like so

class BaseClass
  @@instances = []
  attr_accessor :name

  def initialize(name)
    @name = name
    @@instances << self
  end
  def self.list
    @@instances
  end
  def to_s
    @name
  end
end

class ClassA < BaseClass
end

class ClassB < BaseClass
end

puts "Creating instances"
a = ClassA.new "a"
aa = ClassA.new "aa"
b = ClassB.new "b"

puts "Listing for ClassA"
puts ClassA.list
puts "Listing for ClassB"
puts ClassB.list

I get the following output

Creating instances
Listing for ClassA
a
aa
b
Listing for ClassB
a
aa
b

This makes sense because @@instances was defined in BaseClass and is shared with ClassA and ClassB.

How can I get my code deduplicated to look like the latter example, such that it behaves like the former example?

Was it helpful?

Solution

The easiest way is to get rid of the trick you are trying to do, and use ObjectSpace.each_object.

class BaseClass
  attr_accessor :name
  def initialize(name); @name = name end
  def to_s; @name end
end

class ClassA < BaseClass; end

class ClassB < BaseClass; end

puts "Creating instances"
a = ClassA.new "a"
aa = ClassA.new "aa"
b = ClassB.new "b"
puts "Listing for ClassA"
puts ObjectSpace.each_object(ClassA).to_a
puts "Listing for ClassB"
puts ObjectSpace.each_object(ClassB).to_a

This gives

Creating instances
Listing for ClassA
aa
a
Listing for ClassB
b
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top