Look up all descendants of a class in Ruby
Here is an example:
class Parent
def self.descendants
ObjectSpace.each_object(Class).select { |klass| klass < self }
end
end
class Child < Parent
end
class GrandChild < Child
end
puts Parent.descendants
puts Child.descendants
puts Parent.descendants gives you:
GrandChild
Child
puts Child.descendants gives you:
GrandChild
How to get all descendants of a class in Ruby using `self.inherited`?
class A
singleton_class.send(:attr_reader, :descendants)
@descendants = []
def self.inherited(subclass)
A.descendants << subclass
end
end
A.methods(false)
#=> [:inherited, :descendants, :descendants=]
class B < A; end
class C < B; end
class D < B; end
class E < C; end
class F < E; end
A.descendants
#=> [B, C, D, E, F]
Alternatively, you can use ObjectSpace#each_object to obtain A
's descendants.
ObjectSpace.each_object(Class).select { |c| c < A }
#=> [F, E, D, C, B]
If you wish to obtain the ordering of
arr = [B, C, D, E, F]
you could write
(arr << A).each_with_object({}) { |c,h| h[c] =
arr.each_with_object([]) { |cc,a| a << cc if cc.superclass == c } }
#=> {B=>[C, D], C=>[E], D=>[], E=>[F], F=>[], A=>[B]}
How do I get a list of all subclasses without instantiating first in Ruby
This is an artefact of development mode only loading classes when first referenced: those files haven't been read by the interpreter yet - as far as ruby is concerned the classes genuinely do not exist yet
A workaround is to put
require_dependency "subclass_a"
require_dependency "subclass_b"
....
At the bottom the file for main class (outside the class definition)
How to check all classes under or using a class?
There's nothing built into the core Ruby language that will do what you want - you'll need to write your own. Here's an example method subclasses_of(class_name_here)
(below) that will return a list of subclasses of a particular class for you:
class Mammal
end
class Human < Mammal
end
class Dog < Mammal
end
def subclasses_of input
ObjectSpace.each_object(Class).select { |klass| klass < input }
end
subclasses_of(Mammal)
#=> [Human, Dog]
Btw, there's an answer to this question here:
http://dzone.com/snippets/objectsubclasses
How to get all the descendants of an object in Ruby on Rails
I believe you're interpreting the ancestry gem incorrectly.
It looks like you expect Region to show up as a child of Country. Is that right?
Ancestry is useful for tree like structures (think folders -> sub folders -> child sub folders -> etc.)
Applying has_ancestry within your Country model would allow you to create countries within countries. But I don't believe that's what you're looking for.
Regardless, you can set up those relations by setting the "parent_id" attribute for a country when creating/updating it within the controller. Just set it to the ID of the parent country.
Same for regions if you want a tree structure of regions.
How can I get all defined classes?
p ObjectSpace.each_object(Class){|ob| p ob}
Ruby Object Model - ancestors of a class
The class A
is an instance of Class
, and you can see that via A.class
The class of an instance of A is A
, and you access that via a = A.new; a.class
The method ancestors
is showing the class hierarchy that an object of that class has (or would have) as its inheritance.
There are two parallel class hierarchy models going on in your example, and they only impinge on each other because Ruby represents its classes as objects for you to inspect and modify.
There is no fundamental reason to need A.class.ancestors and A.ancestors to intersect at all - except Ruby also has a deep class model with simple roots, so in practice that is what you'll see.
In fact I couldn't find any counter-example, even nil does this:
NilClass.ancestors
=> [NilClass, Object, Kernel, BasicObject]
NilClass.class.ancestors
=> [Class, Module, Object, Kernel, BasicObject]
This one is more enlightening though:
BasicObject.ancestors
=> [BasicObject]
BasicObject.class.ancestors
=> [Class, Module, Object, Kernel, BasicObject]
How do I get the parent's class name in Ruby
class A
end
class B < A
end
B.superclass # => A
B.superclass.name # => "A"
Loading class descendants in rails development
I found the following post: http://avinmathew.com/using-rails-descendants-method-in-development/
In short it says the following:
In enviroments/development.rb
add the following:
config.eager_load_paths += Dir['path/to/files/*.rb']
ActionDispatch::Reloader.to_prepare do
Dir['path/to/files/*.rb'].each {|file| require_dependency file}
end
The first line adds the path that should be loaded when you start your app (or console)
and the rest tells rails to reload the classes on each request.
Nested singleton class method lookup
Much of this explanation is based on How Ruby Method Dispatch Works by James Coglan, a little of the Ruby Hacking Guide, and just a smidge of source.
To begin with a summary, the ancestry looks like this:
+----------------+
| |
+--------------------------- Module ~~~~~~~~~~~~~~> #<Class:Module> |
| ^ ^ |
| | | |
| Class ~~~~~~~~~~~~~~~> #<Class:Class> |
| ^ ^ |
| | | |
| BasicObject ~~~~~> #<Class:BasicObject> ~~> #<Class:#<Class:BasicObject>> |
| ^ ^ ^ |
| | Kernel | | |
| | ^ | | |
| | | | +-----------------------|----------------+
| +-----+----+ | | |
| | | v |
+-------> Object ~~~~~~> #<Class:Object> ~~~~~~~~> #<Class:#<Class:Object>>
^ ^ ^
| | |
Foo ~~~~~~~~> #<Class:Foo> ~~~~~~~~~~> #<Class:#<Class:Foo>>
---> Parent
~~~> Singleton class
Let's start from the beginning and build out. BasicObject
is the root of everything - if you check BasicObject.superclass
, you get nil
. BasicObject
is also an instance of Class
. Yes, that gets circular, and there's a special case in the code to deal with it. When A
is an instance of B
, A.singleton_class
is a child of B
, so we get this:
Class
^
|
BasicObject ~~~~~> #<Class:BasicObject>
Object
inherits from BasicObject
. When A
inherits from B
, A
is a child of B
and A.singleton_class
is a child of B.singleton_class
. Object
also includes Kernel
. When A
includes B
, B
is inserted as the first ancestor of A
(after A
itself, but before A.superclass
).
Class
^
|
BasicObject ~~~~~> #<Class:BasicObject
^ ^
| Kernel |
| ^ |
| | |
+-----+----+ |
| |
Object ~~~~~~> #<Class:Object>
Kernel
is an instance of Module
. It's the only instance of Module
we'll see, and its singleton class doesn't appear in any ancestry chains, so I won't draw beyond it.
Now we get down to Foo
, which inherits from Object
(though you don't need to write < Object
). We can already figure out what Foo
and its singleton class are children of.
Class
^
|
BasicObject ~~~~~> #<Class:BasicObject>
^ ^
| Kernel |
| ^ |
| | |
+-----+----+ |
| |
Object ~~~~~~> #<Class:Object>
^ ^
| |
Foo ~~~~~~~~> #<Class:Foo>
Now Class
inherits from Module
, and Module
inherits from Object
, so add Module
and the appropriate singleton classes. Because Module < Object
and Object < BasicObject
and BasicObject.instance_of?(Class)
, this is where the drawing gets a little funky. Remember you just stop traversing upwards whenever you hit BasicObject
.
+----------------+
| |
+--------------------------- Module ~~~~~~~~~~~~~~> #<Class:Module> |
| ^ ^ |
| | | |
| Class ~~~~~~~~~~~~~~~> #<Class:Class> |
| ^ |
| | |
| BasicObject ~~~~~> #<Class:BasicObject> |
| ^ ^ |
| | Kernel | |
| | ^ | |
| | | | +----------------------------------------+
| +-----+----+ | |
| | | v
+-------> Object ~~~~~~> #<Class:Object>
^ ^
| |
Foo ~~~~~~~~> #<Class:Foo>
Last step. Every instance of Class
has a singleton_class
(though it won't be instantiated until it's needed, or else you'd need more RAM). All of our singleton classes are instances of Class
, so they have singleton classes. Watch out for this sentence: A class's singleton class's parent is the class's parent's singleton class. I don't know if there's a succinct way to state that as far as type systems go, and the Ruby source pretty much says it's just doing it for consistency in any case. So, when you ask for Foo.singleton_class.singleton_class
, the language happily obliges you and propagates the necessary parents upward, leading finally to:
+----------------+
| |
+--------------------------- Module ~~~~~~~~~~~~~~> #<Class:Module> |
| ^ ^ |
| | | |
| Class ~~~~~~~~~~~~~~~> #<Class:Class> |
| ^ ^ |
| | | |
| BasicObject ~~~~~> #<Class:BasicObject> ~~> #<Class:#<Class:BasicObject>> |
| ^ ^ ^ |
| | Kernel | | |
| | ^ | | |
| | | | +-----------------------|----------------+
| +-----+----+ | | |
| | | v |
+-------> Object ~~~~~~> #<Class:Object> ~~~~~~~~> #<Class:#<Class:Object>>
^ ^ ^
| | |
Foo ~~~~~~~~> #<Class:Foo> ~~~~~~~~~~> #<Class:#<Class:Foo>>
If you start from any node in this graph and traverse depth-first, right to left (and stop at BasicObject
, you get the node's ancestor chain, just like we wanted. And, we've built it up from some basic axioms, so we might just be able to trust it. Lacking trust, there are a couple interesting ways to verify the structure further.
Try looking at node.singleton_class.ancestors - node.ancestors
for any node in the graph. This gives us the ancestors of the singleton class that are not the ancestors of the node itself, which eliminates some of the confusing redundancy in the list.
> Foo.singleton_class.singleton_class.ancestors - Foo.singleton_class.ancestors
=> [#<Class:#<Class:Foo>>, #<Class:#<Class:Object>>, #<Class:#<Class:BasicObject>>,
#<Class:Class>, #<Class:Module>]
You can also verify any one parent with node.superclass
.
> Foo.singleton_class.singleton_class.superclass
=> #<Class:#<Class:Object>>
And you can even verify that the object identity is all consistent, so there aren't anonymous classes popping up all over the place with no particular relationship to each other.
> def ancestor_ids(ancestors)
> ancestors.map(&:object_id).zip(ancestors).map{|pair| pair.join("\t")}
> end
> puts ancestor_ids(Foo.ancestors)
70165241815140 Foo
70165216040500 Object
70165216040340 Kernel
70165216040540 BasicObject
> puts ancestor_ids(Foo.singleton_class.ancestors)
70165241815120 #<Class:Foo>
70165216039400 #<Class:Object>
70165216039380 #<Class:BasicObject>
70165216040420 Class
70165216040460 Module
70165216040500 Object # Same as Foo from here down
70165216040340 Kernel
70165216040540 BasicObject
> puts ancestor_ids(Foo.singleton_class.singleton_class.ancestors)
70165241980080 #<Class:#<Class:Foo>>
70165215986060 #<Class:#<Class:Object>>
70165215986040 #<Class:#<Class:BasicObject>>
70165216039440 #<Class:Class>
70165216039420 #<Class:Module>
70165216039400 #<Class:Object> # Same as Foo.singleton_class from here down
70165216039380 #<Class:BasicObject>
70165216040420 Class
70165216040460 Module
70165216040500 Object
70165216040340 Kernel
70165216040540 BasicObject
And that, in a nutshell, is how you snipe a nerd.
Related Topics
What Is the Easiest Way to Duplicate an Activerecord Record
Get the Name of the Currently Executing Method
Disable Activerecord For Rails 4
Ruby MySQL2 Gem Installation on Windows 7
Nokogiri/Xpath Namespace Query
Why Are We Installing Ruby 1.9.2/1.9.3 Gems into a 1.9.1 Folder
Method to Parse HTML Document in Ruby
Detect Mime Type of Uploaded File in Ruby
How to Change My Ruby Version Using Rvm
Ruby: How to Post a File Via Http as Multipart/Form-Data
How to Get Source Code of a Method Dynamically and Also Which File Is This Method Locate In
Limitations in Running Ruby/Rails on Windows
Rails: Access to Current_User from Within a Model in Ruby on Rails
Difference Between Various Variables Scopes in Ruby
Creating Matrix With 'Array.New(N, Array.New)'