I want to be able to list and instatiate all subclasses of a class to create a
Factory type pattern, I want to be able to do something like
subclasses = Array.new
## Magic code that puts all subclasses of a class in
## the subclasses array
subclasses = get_subclasses( .... )
subclasses.each { |subclass|
return subclass.new if condition == true
end
sorry I am very new to Ruby and have no idea on how to do this.
any help is appreciated.
Horacio
Robert
(Robert)
24 October 2005 11:32
2
Horacio Sanson wrote:
I want to be able to list and instatiate all subclasses of a class to
create a Factory type pattern, I want to be able to do something like
subclasses = Array.new
## Magic code that puts all subclasses of a class in
## the subclasses array
subclasses = get_subclasses( .... )
subclasses.each { |subclass|
return subclass.new if condition == true
end
sorry I am very new to Ruby and have no idea on how to do this.
any help is appreciated.
There are two possible approaches:
1. Find them when you need them via ObjectSpace:
cl = Enumerable
=> Enumerable
subclasses =
=>
ObjectSpace.each_object(Module) {|m| subclasses << m if
m.ancestors.include? cl}
=> 371
subclasses
=> [Struct::Tms, Dir, File, IO, Range, Struct, Hash, Array, String,
Enumerable]
2. Record them when they are created.
This is typically done by a variant that uses Class#inherited.
class Foo
def self.inherited(cl)
p cl
end
end
=> nil
class Bar < Foo
end
Bar
=> nil
Kind regards
robert
Something like this should get you started (though don't expect it to
be efficient - it basically queries every object in the system to find
the subclasses):
class A
end
class B < A
end
class C < B
end
class Class
def subclasses
class_hash = {}
ObjectSpace.each_object do |obj|
if Class == obj.class
if obj.ancestors.include? self
class_hash[obj] = true
end
end
end
class_hash.keys
end
end
p A.subclasses
#=> [C, B, A]
Regards,
Sean
···
On 10/24/05, Horacio Sanson <hsanson@moegi.waseda.jp> wrote:
I want to be able to list and instatiate all subclasses of a class to create a
Factory type pattern, I want to be able to do something like
subclasses = Array.new
## Magic code that puts all subclasses of a class in
## the subclasses array
subclasses = get_subclasses( .... )
subclasses.each { |subclass|
return subclass.new if condition == true
end
sorry I am very new to Ruby and have no idea on how to do this.
any help is appreciated.
Horacio
This will save an array of subclasses in a class attribute named `subclasses'. It may not be the most efficient way of doing it, but it works.
class Class
def inherited(subclass)
if superclass.respond_to? :inherited
superclass.inherited(subclass)
end
@subclasses ||= []
@subclasses << subclass
end
def subclasses
@subclasses
end
end
class SuperClass; end
class A < SuperClass; end
class B < SuperClass; end
class C < SuperClass; end
class D < A; end
puts SuperClass.subclasses.join(", ") # A, B, C, D
If you only need one superclass, this is more efficient:
class MyClass
def self.inherited(subclass)
if superclass.respond_to? :inherited
superclass.inherited(subclass)
end
@subclasses ||= []
@subclasses << subclass
end
def self.subclasses
@subclasses
end
end
Cheers,
Daniel
Hi,
At Mon, 24 Oct 2005 20:05:43 +0900,
Horacio Sanson wrote in [ruby-talk:162270]:
I want to be able to list and instatiate all subclasses of a class to create a
Factory type pattern, I want to be able to do something like
FYI, http://www.rubyist.net/~nobu/ruby/factory.rb
···
--
Nobu Nakada
Incorporating Robert's suggestions, this is a bit better:
class Module
def subclasses
classes = []
ObjectSpace.each_object(Module) do |m|
classes << m if m.ancestors.include? self
end
classes
end
end
Regards,
Sean
Pit
(Pit)
24 October 2005 12:50
7
Robert Klemme schrieb:
1. Find them when you need them via ObjectSpace:
ObjectSpace.each_object(Module) {|m| subclasses << m if m.ancestors.include? cl}
If you want to find subclasses of a *class* instead of a module, you can pass the singleton class of the base class:
require "enumerator"
def get_subclasses(klass)
ObjectSpace.enum_for(:each_object, class << klass; self; end).to_a
end
Horacio, if you need help to decipher this code, feel free to ask.
Regards,
Pit
Gene_Tani
(Gene Tani)
24 October 2005 12:12
8
FWIW last summer we made a list of the 10 methods you can use to test
inheritance / mixed-in or extendedness:
Object#kind_of?, #is_a ?, #instance_of ?, #type (deprecated), #class
Module#ancestors, #included_modules
Class#inherited, #superclass
MyClassname === myobj
Sean O'Halpin wrote:
···
Incorporating Robert's suggestions, this is a bit better:
class Module
def subclasses
classes =
ObjectSpace.each_object(Module) do |m|
classes << m if m.ancestors.include? self
end
classes
end
end
Regards,
Sean
Robert
(Robert)
24 October 2005 14:02
9
Pit Capitain wrote:
Robert Klemme schrieb:
1. Find them when you need them via ObjectSpace:
ObjectSpace.each_object(Module) {|m| subclasses << m if
m.ancestors.include? cl}
If you want to find subclasses of a *class* instead of a module, you
can pass the singleton class of the base class:
require "enumerator"
def get_subclasses(klass)
ObjectSpace.enum_for(:each_object, class << klass; self;
end).to_a end
Cool! Didn't know this. Learn something new every day... Thanks!
Kind regards
robert
pit that's insanely cool - thanks!
-a
···
On Mon, 24 Oct 2005, Pit Capitain wrote:
Robert Klemme schrieb:
1. Find them when you need them via ObjectSpace:
ObjectSpace.each_object(Module) {|m| subclasses << m if m.ancestors.include? cl}
If you want to find subclasses of a *class* instead of a module, you can pass the singleton class of the base class:
require "enumerator"
def get_subclasses(klass)
ObjectSpace.enum_for(:each_object, class << klass; self; end).to_a
end
Horacio, if you need help to decipher this code, feel free to ask.
--
email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
anything that contradicts experience and logic should be abandoned.
-- h.h. the 14th dalai lama
===============================================================================
Pit
(Pit)
24 October 2005 16:47
11
Robert Klemme schrieb:
Cool! Didn't know this. Learn something new every day... Thanks!
Same for me. I didn't know this either until today
Regards,
Pit