Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi there monks,

I have a large pluggable application, with lots of modules that use Moose with roles. During some point in time, I would like to traverse all required modules and ask them if they do a certain role $module->does($role).

Does Moose or any of the Meta packages it uses (Class::MOP? Moose::Meta?) can generate a list of modules loaded in memory that implement a role?

Or, aside from Moose, what's the cleanest way to get a list of modules loaded? Is there a hot cpan package out there that does this? Or should I just traverse the ${::} hash? Googling didn't help.

Thanks! -miguel

Replies are listed 'Best First'.
Re: find all modules that "do" a role
by Corion (Patriarch) on Sep 07, 2009 at 12:38 UTC

    I haven't done anything with Moose, but I suppose that using Module::Pluggable to find all candidates and then using some part of the Moose API to inspect $package->metaclass is the approach I'd use. Actually, looking at Moose::Meta::Class, the following should tell you whether a class does a role:

    package App; use Module::Pluggable sub_name => 'plugins'; my @candidates = App->plugins; for my $class (@candidates) { if ($class->meta->does_role( $role ) { print "$class does $role\n"; }; };

    Of course, with this unchecked approach, you force all plugins into the Moose tarpit, which imposes a burden+learning curve on plugin authors. You might want to be more defensive, by wrapping $class->meta in an eval block or by providing a base class for plugins which sets up enough routines for a bare-bones plugin that does no harm.

    Update: Upon rereading, I see that you only want to look at the classes that have been loaded - then, I'd stay with the defensive approach outlined above, but fill the @candidates from %INC instead via Module::Pluggable, if you want to avoid setting up Module::Pluggable with the correct search paths or want to avoid (re)loading failing modules.

      You're right, Module::Pluggable would give me a good set to start checking. The thing is that I didn't want to depend on M::P, but also check things that were used or required.

      I suppose that, wheather using %INC, or ${*::*}, I'll need to check if the class uses "moose" before invoking $class->meta.

        Module::Pluggable is core, so the only burden would be (again) upon the plugin author. Personally, I wouldn't check whether a class/package uses Moose but rather just do

        my $metaclass = eval { $class->meta }; if ($metaclass) { };

        that way non-Moose things have an option to work as plugins as well, as long as they have:

        sub meta { ... }

        which returns something "good enough". For example the following should work for your use case as a minimal class:

        package My::Plugin; sub meta { __PACKAGE }; sub does_role { my ($class,$role) = @_; $role eq 'chatbot' }; 1
Re: find all modules that "do" a role
by stvn (Monsignor) on Sep 07, 2009 at 16:09 UTC
    Does Moose or any of the Meta packages it uses (Class::MOP? Moose::Meta?) can generate a list of modules loaded in memory that implement a role?

    You can find all the classes managed by Moose by calling the metaclass cache functions in Class::MOP. See here for more information.

    -stvn