package Module::Find; use 5.006001; use strict; use warnings; use File::Spec; use File::Find; our $VERSION = '0.13'; our $basedir = undef; our @results = (); our $prune = 0; our $followMode = 1; our @ISA = qw(Exporter); our @EXPORT = qw(findsubmod findallmod usesub useall setmoduledirs); our @EXPORT_OK = qw(followsymlinks ignoresymlinks); =encoding utf-8 =head1 NAME Module::Find - Find and use installed modules in a (sub)category =head1 SYNOPSIS use Module::Find; # use all modules in the Plugins/ directory @found = usesub Mysoft::Plugins; # use modules in all subdirectories @found = useall Mysoft::Plugins; # find all DBI::... modules @found = findsubmod DBI; # find anything in the CGI/ directory @found = findallmod CGI; # set your own search dirs (uses @INC otherwise) setmoduledirs(@INC, @plugindirs, $appdir); # not exported by default use Module::Find qw(ignoresymlinks followsymlinks); # ignore symlinks ignoresymlinks(); # follow symlinks (default) followsymlinks(); =head1 DESCRIPTION Module::Find lets you find and use modules in categories. This can be very useful for auto-detecting driver or plugin modules. You can differentiate between looking in the category itself or in all subcategories. If you want Module::Find to search in a certain directory on your harddisk (such as the plugins directory of your software installation), make sure you modify C<@INC> before you call the Module::Find functions. =head1 FUNCTIONS =over =item C Sets the directories to be searched for modules. If not set, Module::Find will use @INC. If you use this function, @INC will I be included automatically, so add it if you want it. Set to undef to revert to default behaviour. =cut sub setmoduledirs { return @Module::Find::ModuleDirs = grep { defined } @_; } =item C<@found = findsubmod Module::Category> Returns modules found in the Module/Category subdirectories of your perl installation. E.g. C will return C, but not C . =cut sub findsubmod(*) { $prune = 1; return _find($_[0]); } =item C<@found = findallmod Module::Category> Returns modules found in the Module/Category subdirectories of your perl installation. E.g. C will return C and also C . =cut sub findallmod(*) { $prune = 0; return _find($_[0]); } =item C<@found = usesub Module::Category> Uses and returns modules found in the Module/Category subdirectories of your perl installation. E.g. C will return C, but not C . If any module dies during loading, usesub will also die at this point. =cut sub usesub(*) { $prune = 1; my @r = _find($_[0]); foreach my $m (@r) { eval " require $m; import $m ; "; die $@ if $@; } return @r; } =item C<@found = useall Module::Category> Uses and returns modules found in the Module/Category subdirectories of your perl installation. E.g. C will return C and also C . If any module dies during loading, useall will also die at this point. =cut sub useall(*) { $prune = 0; my @r = _find($_[0]); foreach my $m (@r) { eval " require $m; import $m; "; die $@ if $@; } return @r; } # 'wanted' functions for find() # you know, this would be a nice application for currying... sub _wanted { my $name = File::Spec->abs2rel($_, $basedir); return unless $name && $name ne File::Spec->curdir(); if (-d && $prune) { $File::Find::prune = 1; return; } return unless /\.pm$/ && -r; $name =~ s|\.pm$||; $name = join('::', File::Spec->splitdir($name)); push @results, $name; } # helper functions for finding files sub _find(*) { my ($category) = @_; return undef unless defined $category; my $dir = File::Spec->catdir(split(/::|'/, $category)); my @dirs; if (@Module::Find::ModuleDirs) { @dirs = map { File::Spec->catdir($_, $dir) } @Module::Find::ModuleDirs; } else { @dirs = map { File::Spec->catdir($_, $dir) } @INC; } @results = (); foreach $basedir (@dirs) { next unless -d $basedir; find({wanted => \&_wanted, no_chdir => 1, follow => $followMode}, $basedir); } # filter duplicate modules my %seen = (); @results = grep { not $seen{$_}++ } @results; @results = map "$category\::$_", @results; @results = map { ($_ =~ m{^(\w+(?:(?:::|')\w+)*)$})[0] || die "$_ does not look like a package name" } @results; return @results; } =item C Do not follow symlinks. This function is not exported by default. =cut sub ignoresymlinks { $followMode = 0; } =item C Follow symlinks (default behaviour). This function is not exported by default. =cut sub followsymlinks { $followMode = 1; } =back =head1 HISTORY =over 8 =item 0.01, 2004-04-22 Original version; created by h2xs 1.22 =item 0.02, 2004-05-25 Added test modules that were left out in the first version. Thanks to Stuart Johnston for alerting me to this. =item 0.03, 2004-06-18 Fixed a bug (non-localized $_) by declaring a loop variable in use functions. Thanks to Stuart Johnston for alerting me to this and providing a fix. Fixed non-platform compatibility by using File::Spec. Thanks to brian d foy. Added setmoduledirs and updated tests. Idea shamelessly stolen from ...errm... inspired by brian d foy. =item 0.04, 2005-05-20 Added POD tests. =item 0.05, 2005-11-30 Fixed issue with bugfix in PathTools-3.14. =item 0.06, 2008-01-26 Module::Find now won't report duplicate modules several times anymore (thanks to Uwe Völker for the report and the patch) =item 0.07, 2009-09-08 Fixed RT#38302: Module::Find now follows symlinks by default (can be disabled). =item 0.08, 2009-09-08 Fixed RT#49511: Removed Mac OS X extended attributes from distribution =item 0.09, 2010-02-26 Fixed RT#38302: Fixed META.yml generation (thanks very much to cpanservice for the help). =item 0.10, 2010-02-26 Fixed RT#55010: Removed Unicode BOM from Find.pm. =item 0.11, 2012-05-22 Fixed RT#74251: defined(@array) is deprecated under Perl 5.15.7. Thanks to Roman F, who contributed the implementation. =item 0.12, 2014-02-08 Fixed RT#81077: useall fails in taint mode Thanks to Aran Deltac, who contributed the implementation and test. Fixed RT#83596: Documentation doesn't describe behaviour if a module fails to load Clarified documentation for useall and usesub. Fixed RT#62923: setmoduledirs(undef) doesn't reset to searching @INC Added more explicit tests. Thanks to Colin Robertson for his input. =item 0.13, 2015-03-09 This release contains two contributions from Moritz Lenz: - Link to Module::Pluggable and Class::Factory::Util in "SEE ALSO" - Align package name parsing with how perl does it (allowing single quotes as module separator) =back =head1 DEVELOPMENT NOTES Please report any bugs using the CPAN RT system. The development repository for this module is hosted on GitHub: L. =head1 SEE ALSO L, L, L =head1 AUTHOR Christian Renz, Ecrenz@web42.comE =head1 COPYRIGHT AND LICENSE Copyright 2004-2014 by Christian Renz . All rights reserved. This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut 1;