Search code examples
perlexceptionsubclassingsymbol-tables

Perl: How to iterate through symbol table to find all loaded subclasses of Foo::Bar?


I have a module which is defining exceptions for the package of which it is a part. The exceptions are being declared with Exception::Class::Nested.

For purposes of discussion, let's say that this module is named Foo::Bar::Exception, and that all of the exceptions it defines are first-level subclasses of that (e.g., Foo::Bar::Exception:DoNotDoThat). All of the exceptions I care about are defined in this module file; I'm not interested in any additional subclassing any other module does of me.

For my import method, I want to construct a list of all the exceptions being defined, and I'd like to do it by traversing the symbol table somehow rather than keeping a hard-coded list that can get out of sync with the definitions and has to be manually maintained.

So, how can Foo::Bar::Exception->import iterate through Foo::Bar::Exception's symbol table to find all the exceptions (first-level subclasses) that have been declared in the module? It's just the active loaded symbol table I'm interested in; no filesystem searches or the like.

Thanks!

[addendum]

Since all of my exception subclass names end with Exception or Error, this looks like it's getting close to what I want:

my %symtable = eval("'%' . __PACKAGE__ . '::'");
my @shortnames = grep(m!(?:Error|Exception)::$!, keys(%symtable));
@shortnames = ( map { $_ =~ s/::$//; $_; } @shortnames );
my @longnames = ( map { __PACKAGE__ . '::' . $_ } @shortnames );

Some of the parenthesisation is unnecessary, but I added it for clarity about the array context.


Solution

  • The symbol table for Foo::Bar::Exception is %Foo::Bar::Exception::, so you could write:

    sub import {
        for my $key (keys %Foo::Bar::Exception::) {
            if (my ($name) = $key =~ /(.+)::$/) {
               my $pkg = 'Foo::Bar::Exception::'.$name;
               no strict 'refs';
               *{caller()."::$name"} = sub () {$pkg};
            }
        }
    }