Add ability for a base class to find its subclasses
Robert Boone [Wed, 28 Nov 2007 16:45:12 +0000 (16:45 +0000)]
lib/Class/MOP/Class.pm
t/010_self_introspection.t

index 1dc8e24..4f75e52 100644 (file)
@@ -386,6 +386,51 @@ sub superclasses {
     @{$self->get_package_symbol('@ISA')};
 }
 
+sub subclasses {
+    my $self = shift;
+
+    my $super_class = $self->name;
+    my @derived_classes;
+    
+    my $find_derived_classes;
+    $find_derived_classes = sub {
+        my ($outer_class) = @_;
+
+        my $symbol_table_hashref = do { no strict 'refs'; \%{"${outer_class}::"} };
+
+      SYMBOL:
+        for my $symbol ( keys %$symbol_table_hashref ) {
+            next SYMBOL if $symbol !~ /\A (\w+):: \z/x;
+            my $inner_class = $1;
+
+            next SYMBOL if $inner_class eq 'SUPER';    # skip '*::SUPER'
+
+            my $class =
+              $outer_class
+              ? "${outer_class}::$inner_class"
+              : $inner_class;
+
+            if ( $class->isa($super_class) and $class ne $super_class ) {
+                push @derived_classes, $class;
+            }
+
+            next SYMBOL if $class eq 'main';           # skip 'main::*'
+
+            $find_derived_classes->($class);
+        }
+    };
+
+    my $root_class = q{};
+    $find_derived_classes->($root_class);
+
+    undef $find_derived_classes;
+
+    @derived_classes = sort { $a->isa($b) ? 1 : $b->isa($a) ? -1 : 0 } @derived_classes;
+
+    return @derived_classes;
+}
+
+
 sub linearized_isa {
     my %seen;
     grep { !($seen{$_}++) } (shift)->class_precedence_list
index 1ca0081..69f3c48 100644 (file)
@@ -3,7 +3,7 @@
 use strict;
 use warnings;
 
-use Test::More tests => 197;
+use Test::More tests => 199;
 use Test::Exception;
 
 BEGIN {
@@ -61,7 +61,7 @@ my @class_mop_class_methods = qw(
 
     attribute_metaclass method_metaclass
 
-    superclasses class_precedence_list linearized_isa
+    superclasses subclasses class_precedence_list linearized_isa
 
     has_method get_method add_method remove_method alias_method
     get_method_list get_method_map compute_all_applicable_methods