Domanda

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?

È stato utile?

Soluzione

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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top