Module-Pluggable-5.2/000755 000767 000024 00000000000 12560516377 015013 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/Changes000755 000767 000024 00000020445 12560516334 016307 0ustar00simonstaff000000 000000 2015-08-05 - 5.2 Use Module::Runtime if it's installed (thanks to Olivier Mengué) Switch to using ExtUtils::MakeMaker (thanks to Karen Etheridge and Tim Orling) 2014-01-05 - 5.1 Add in missing files left out of the MANIFEST due to stupidity (thanks to Petr Pisar) 2013-12-20 - 5.0 Gain support for @INC hooks and hence for App::FatPacker (thanks to Diab Jerius) 2013-10-22 - 4.9 Fix the fact that we can't handle single letter package names (thanks sbaynes) 2013-05-27 - 4.8 Fix some typos (David Steinbrunner) Fix error in testing when Text::BibTex is installed (thanks to Andreas Koenig) 2013-02-25 - 4.7 Fix more hash ordering bugs in tests by forcing sort of returned plugins (Yves Orton) 2013-01-23 - 4.6 Add warning about future removal from core 2012-11-05 - 4.5 Fix docs Fix problem with PAUSE upload 2012-11-05 - 4.4 Fix hash ordering bug in tests (Yves Orton) Fix install dir (Tatsuhiko Miyagawa) 2012-08-15 - 4.3 Fix calling the correct method when instantiating (Doh!) Hopefully stop smoker failures 2012-08-14 - 4.2 Fix a problem with installation directory (Jerry D. Hedden) 2012-07-20 - 4.1 Allow triggers on events which gives a powerful way to modify behaviour (Tim Brody, Dan Dascalescu, Paul Evans, Jens Rehsack) Put documentation in about behaviour under blib and test, allow searching outside blib under test (suggestion from Stephen Baynes) Made following symlinks the default behaviour, added ability to turn that off (Aran Deltac) Fix installation path (Matthias Dietrich, Todd Rinaldo) Allow min_depth and max_depth (as per suggestion from Jens Rehsack) Set our @INC up to include and prefer our search_dirs if necessary (as per suggestion from Ian Goodacre) Switch to Module::Build 2012-01-03 - 4.0 Don't use defined on an array (it's deprecated) 2009-03-02 - 3.9 Allow inner packages when in a one file situation (suggestion from Christopher Brown) Fix bug with requiring skipped packages (from Jos Boumans) 2008-03-16 - 3.8 Set INSTALLDIRS correctly in Makefile.PL A couple of other fixups to play nicely in Core 2008-03-12 - 3.7 Ignore editor cruft by default (Dave Rolsky and Matt Trout) Doc patches (Matt Trout) Prevent prototype mismatch warnings under Error.pm (Christopher H. Laco) Don't pick up the ::SUPER pseudo stash in 5.8 (Alex Vandiver) Make things work under VOS (Nicholas Clark and Paul Green) Fix warning under Devel::Cover (Brian Cassidy) Make tests run under Taint again Get rid of Build.PL 2007-04-07 - 3.6 Include blead perl patch from Craig Berry that gives better Module::Pluggable::Object::search_paths portability as prompted by VMS test failures. 2007-01-29 - 3.5 Patch from Audrey Tang to prevent clobbering of $@ 2006-11-27 - 3.4 Make sure we don't fail taint checking when other Module::Pluggable::* modules are installed. 2006-11-24 - 3.3 Few more patches from Jos Boumans to get ready for CORE 2006-11-15 - 3.2 Remove Class::Inspector dependency and inline code Prepare for assimilation into CORE 2006-07-11 - 3.1 Force Test::More version to be latest which stops it trampling on $_ Use Class::Inspector tests to check to see Package is loaded thus preventing incompatability problems introduced by last patch. 2006-06-07 - 3.01 Fix from Brian Cassidy in Devel::InnerPackage 2006-06-06 - 3.0 Big refactor to split stuff up into more manageable pieces 2006-04-05 - 2.98 Allow the ability to provide the file matching regex 2006-02-06 - 2.97 Patch from Ricardo Signes to fix bug where File::Find is not topic-safe in 5.6.1 2005-09-01 - 2.96 Patch from Alex Vandiver to sort an edge case where the package stash to contain "::" 2005-07-30 - 2.95 Patch from Alex Vandiver to sort ::ISA::CACHE issues. More patches from Christopher H. Laco to sort out only and except and to fix calling search_path( add => ... ) before plugins() 2005-07-09 - 2.9 More Tainting fixes Patches from Christopher H. Laco and Joe McMahon to do more taint fixing Suggestion from Christopher H. Laco to do a can check before instatiating 2005-03-18 - 2.8 Minor fixes Patch from Marcus Thiesen to fix so ISA cache magic Patch from Anthony D. Urso to get M::P to work under taint 2005-02-14 - 2.7 Allow redefinition of search_path A patch from Barbie to allow you to do $self->search_path( add => 'Some::Path' ); $self->search_path( new => 'Some::New::Path' ); 2005-02-02 - 2.6 Problems under tests Richard Clamp diagnosed a problem as being due to the fact that we exclude anything not from blib if there was blib.pm is %INC. Of course if the module being tested used another module that used Module::Pluggable then the second module would fail. Fixed it by checking to see if the caller had (^|/)blib/ in their filename. 2004-12-20 - 2.5 'Inspiration' from Module::Pluggable::Fast Noticed Sebastian Riedel's curious Module::Pluggable::Fast which appears to break API backwards compatability in order to inline an explicit call to 'new'. It has no tests. A quick benchmark showed that it was about 10% faster because of cruft that had accumulated over time. So a few quick changes and now Module::Pluggable is only 3% slower. Which is nice. Also added a patch from Barbie to fix things under Windows. 2004-12-15 - 2.4 Bug fix There seemed to be some irregularities in how 5.8.1 worked with the list_packages method. Fixed thanks to Schwern, Michael Cummings and Jos Boumans. Added some more documentation. Added ability to specify except and only as regexes. 2004-10-27 - 2.3 Niceties Allow you to explicitly stop looking for inner packages. Made it nicer to have single element search_dirs and search_paths. 2004-10-08 - 2.2 Dieting Thanks to suggestion and patches from Adam Kennedy Module::Pluggable has dumped some weight and got rid of the none Core dependecies of File::Find::Rule and UNIVERSAL::require 2004-08-25 - 2.1 Small buglette Require inner packages when appropriate. This helps towards making things work with PAR. Thanks to Brian Cassidy. Never released. 2004-08-19 - 2.0 Working inner packages As long as you have require or instantiate set then we'll also find inner packages. Why I didn't fix this way back in 1.3 I don't know. 2004-07-18 - 1.9 Add 'package' option This lets you install a method in another package's namespace. Thanks to Simon Cozens. 2004-07-08 - 1.8 Fix those two options They worked before but now they're more robust. 2004-07-07 - 1.7 Add support for limiting plugins Added 'only' and ''except' options. 2004-06-03 - 1.6 Add a traditional Makefile.PL Even though I think Module::Build is much better. 2004-05-25 - 1.5 Build.PL stupidity Must add prereqs. Doh. 2004-05-25 - 1.4 Multiple instances Made it so you could use it twice in the same package. Removed the inner package stuff inorder to fix it properly. 2004-05-06 - 1.3 Ability to search in inner packages Simon Cozens donated some code to allow us to search inner packages. 2004-05-06 - 1.2 Fix minor buglet Apply a patch from Tom Insam to fix requiring without instantiating and make require failures more verbose. 2003-12-15 - 1.11 Update MANIFEST. So that make dist works properly. 2003-12-15 - 1.1 Make it work with multi level plugins Apparently Foo::Plugin::Bar::Quux doesn't work. Thanks to Darren Chamberlain for spotting this. 2003-12-15 - 1.00 Add some more features Added the ability to require without instantiating (for Tom Insam) Prevented the names from being explicitly sorted (again, for Tom Insam) Added in the ability to provide other search directorys. 2003-11-27 - 0.95 Some Test::More issues Explicitly number the tests which fixes some test more failures 2003-10-21 - 0.9 We can rebuild you, we have the technology Having used this in the wild some changes to make it better. 2003-10-20 - 0.8 Fix. Namespace issues. 2003-10-17 - 0.7 And take your Build.PL with you Pesky MANIFEST.SKIP 2003-10-15 - 0.6 Initial release Be free my pretty. EMANCIPIA! Module-Pluggable-5.2/INSTALL000755 000767 000024 00000000215 12560516306 016035 0ustar00simonstaff000000 000000 Same as practically every other Perl module ... % perl Makefile.PL % make % make test % sudo make install Module-Pluggable-5.2/lib/000755 000767 000024 00000000000 12560516377 015561 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/Makefile.PL000644 000767 000024 00000007765 12560516306 016774 0ustar00simonstaff000000 000000 use strict; use warnings; use ExtUtils::MakeMaker; use File::Spec::Functions qw(catfile); ExtUtils::MakeMaker->VERSION(6.98) if -f '.gitignore'; # VOS and VMS can't handle dodgy plugin names # and VOS can't even unpack them so we create them on the # fly and only run the tests if they're present my %dodgy_files = ( catfile('OddTest', 'Plugin', '-Dodgy.pm') => 'OddTest::Plugin::-Dodgy', catfile('EditorJunk', 'Plugin', '#Bar.pm#') => 'EditorJunk::Bar', catfile('EditorJunk', 'Plugin', '.#Bar.pm') => 'EditorJunk::Bar', ); my @files; unless (grep { lc($^O) eq $_ } qw(vms vos)) { foreach my $test (keys %dodgy_files) { my ($file) = (catfile("t", "lib", $test)=~/^(.*)$/); if (open(FH, ">$file")) { my $name = $dodgy_files{$test}; print FH "package $name;\nsub new {}\n1;"; close(FH); push @files, $file; } } } my %WriteMakefileArgs = ( NAME => 'Module::Pluggable', VERSION_FROM => 'lib/Module/Pluggable.pm', ABSTRACT_FROM => 'lib/Module/Pluggable.pm', AUTHOR => 'Simon Wistow ', LICENSE => 'perl_5', MIN_PERL_VERSION => '5.00503', INSTALLDIRS => ($] >= 5.008009 && $] <= 5.011000 ? 'perl' : 'site'), CONFIGURE_REQUIRES => { 'ExtUtils::MakeMaker' => '0', }, PREREQ_PM => { 'if' => '0', 'File::Basename' => '0', 'File::Spec' => '3.00', 'Exporter' => '5.57', # use Exporter 'import' 'File::Find' => '0', 'File::Spec::Functions' => '0', 'strict' => '0', }, TEST_REQUIRES => { 'Test::More' => '0', 'Cwd' => '0', 'Data::Dumper' => '0', 'File::Copy' => '0', 'File::Find' => '0', 'File::Path' => '0', 'File::Spec::Functions' => '0', 'File::Temp' => '0', 'base' => '0', 'FindBin' => '0', 'strict' => '0', 'warnings' => '0', }, META_MERGE => { 'meta-spec' => { version => 2 }, dynamic_config => 0, resources => { repository => { url => 'https://github.com/simonwistow/Module-Pluggable.git', web => 'https://github.com/simonwistow/Module-Pluggable', type => 'git', }, bugtracker => { mailto => 'bug-Module-Pluggable@rt.cpan.org', web => 'https://rt.cpan.org/Public/Dist/Display.html?Name=Module-Pluggable', }, }, prereqs => { runtime => { recommends => { 'Module::Runtime' => '0.012', }, }, test => { suggests => { 'App::Fatpacker' => '0.010000', }, }, }, optional_features => { module_runtime => { description => "Optionally use Module::Runtime for requiring plugins rather than homegrown system", prereqs => { runtime => { requires => { 'Module::Runtime' => '0.012', } } } } } }, ); # degrade gracefully for older EUMM/older perls if (!eval { ExtUtils::MakeMaker->VERSION('6.6303') }) { $WriteMakefileArgs{BUILD_REQUIRES} = $WriteMakefileArgs{TEST_REQUIRES}; delete $WriteMakefileArgs{TEST_REQUIRES}; } if (!eval { ExtUtils::MakeMaker->VERSION('6.5501') }) { @{$WriteMakefileArgs{PREREQ_PM}}{ keys %{$WriteMakefileArgs{BUILD_REQUIRES}} } = @{$WriteMakefileArgs{BUILD_REQUIRES}}{ keys %{$WriteMakefileArgs{BUILD_REQUIRES}} }; delete $WriteMakefileArgs{BUILD_REQUIRES}; } WriteMakefile(%WriteMakefileArgs); Module-Pluggable-5.2/MANIFEST000644 000767 000024 00000003622 12560516306 016137 0ustar00simonstaff000000 000000 Changes INSTALL lib/Devel/InnerPackage.pm lib/Module/Pluggable.pm lib/Module/Pluggable/Object.pm Makefile.PL MANIFEST This list of files MANIFEST.SKIP META.json META.yml README t/01use.t t/02alsoworks.t t/02works.t t/02works_taint.t t/03diffname.t t/04acmedir.t t/04acmedir_single.t t/04acmepath.t t/04acmepath_single.t t/05postpath.t t/06multipath.t t/07instantiate.t t/08nothing.t t/09require.t t/10innerpack.t t/10innerpack_inner.t t/10innerpack_noinner.t t/10innerpack_onefile.t t/10innerpack_override.t t/10innerpack_super.t t/11usetwice.t t/12only.t t/12onlyarray.t t/12onlyregex.t t/12onlyrequire.t t/13except.t t/13exceptarray.t t/13exceptregex.t t/14package.t t/15topicsafe.t t/16different_extension.t t/17devel_inner_package.t t/18skipped_package.t t/19can_ok_clobber.t t/20dodgy_files.t t/21editor_junk.t t/22trigger.t t/23depth.t t/24local_inc_object.t t/24local_inc_package.t t/25single_letter_package.t t/26inc_hook.t t/27app_fatpacker.t t/acme/Acme/MyTest/Plugin/Foo.pm t/fp/app.pl t/fp/lib/App/TestMPFP/Plugin/A.pm t/lib/Acme/Foo-Bar.pm t/lib/Acme/MyTest/Plugin/Foo.pm t/lib/EditorJunk/Plugin/Bar.pm t/lib/EditorJunk/Plugin/Bar.pm.swo t/lib/EditorJunk/Plugin/Bar.pm.swp t/lib/EditorJunk/Plugin/Bar.pm~ t/lib/EditorJunk/Plugin/Foo.pm t/lib/ExtTest/Plugin/Bar.plugin t/lib/ExtTest/Plugin/Foo.plugin t/lib/ExtTest/Plugin/Quux/Foo.plugin t/lib/InnerTest/Plugin/Foo.pm t/lib/M/X.pm t/lib/MyOtherTest/Plugin/Bar.pm t/lib/MyOtherTest/Plugin/Foo.pm t/lib/MyOtherTest/Plugin/Quux.pm t/lib/MyOtherTest/Plugin/Quux/Foo.pm t/lib/MyTest/Extend/Plugin/Bar.pm t/lib/MyTest/Plugin/Bar.pm t/lib/MyTest/Plugin/Foo.pm t/lib/MyTest/Plugin/Quux/Foo.pm t/lib/No/Middle.pm t/lib/OddTest/Plugin/Foo.pm t/lib/TA/C/A/I.pm t/lib/Text/Abbrev.pm t/lib/TriggerTest/Plugin/After.pm t/lib/TriggerTest/Plugin/CallbackAllow.pm t/lib/TriggerTest/Plugin/CallbackDeny.pm t/lib/TriggerTest/Plugin/Deny.pm t/lib/TriggerTest/Plugin/Error.pm t/lib/Zot/.Zork.pm Module-Pluggable-5.2/MANIFEST.SKIP000644 000767 000024 00000000314 12011255476 016676 0ustar00simonstaff000000 000000 Build$ _build blib Makefile$ \.tar\.gz$ \.svn \.git \.bak$ ^Module-Pluggable t/lib/OddTest/Plugin/-Dodgy.pm t/lib/EditorJunk/Plugin/#Bar.pm# t/lib/EditorJunk/Plugin/.#Bar.pm ^MYMETA\.yml$ ^MYMETA\.json$ Module-Pluggable-5.2/META.json000644 000767 000024 00000004744 12560516377 016445 0ustar00simonstaff000000 000000 { "abstract" : "automatically give your module the ability to have plugins", "author" : [ "Simon Wistow " ], "dynamic_config" : 0, "generated_by" : "ExtUtils::MakeMaker version 7.04, CPAN::Meta::Converter version 2.150005", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Module-Pluggable", "no_index" : { "directory" : [ "t", "inc" ] }, "optional_features" : { "module_runtime" : { "description" : "Optionally use Module::Runtime for requiring plugins rather than homegrown system", "prereqs" : { "runtime" : { "requires" : { "Module::Runtime" : "0.012" } } } } }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "recommends" : { "Module::Runtime" : "0.012" }, "requires" : { "Exporter" : "5.57", "File::Basename" : "0", "File::Find" : "0", "File::Spec" : "3.00", "File::Spec::Functions" : "0", "if" : "0", "perl" : "5.00503", "strict" : "0" } }, "test" : { "requires" : { "Cwd" : "0", "Data::Dumper" : "0", "File::Copy" : "0", "File::Find" : "0", "File::Path" : "0", "File::Spec::Functions" : "0", "File::Temp" : "0", "FindBin" : "0", "Test::More" : "0", "base" : "0", "strict" : "0", "warnings" : "0" }, "suggests" : { "App::Fatpacker" : "0.010000" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "mailto" : "bug-Module-Pluggable@rt.cpan.org", "web" : "https://rt.cpan.org/Public/Dist/Display.html?Name=Module-Pluggable" }, "repository" : { "type" : "git", "url" : "https://github.com/simonwistow/Module-Pluggable.git", "web" : "https://github.com/simonwistow/Module-Pluggable" } }, "version" : "5.2", "x_serialization_backend" : "JSON::PP version 2.27203" } Module-Pluggable-5.2/META.yml000644 000767 000024 00000002440 12560516377 016264 0ustar00simonstaff000000 000000 --- abstract: 'automatically give your module the ability to have plugins' author: - 'Simon Wistow ' build_requires: Cwd: '0' Data::Dumper: '0' ExtUtils::MakeMaker: '0' File::Copy: '0' File::Find: '0' File::Path: '0' File::Spec::Functions: '0' File::Temp: '0' FindBin: '0' Test::More: '0' base: '0' strict: '0' warnings: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 0 generated_by: 'ExtUtils::MakeMaker version 7.04, CPAN::Meta::Converter version 2.150005' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Module-Pluggable no_index: directory: - t - inc optional_features: module_runtime: description: 'Optionally use Module::Runtime for requiring plugins rather than homegrown system' requires: Module::Runtime: '0.012' recommends: Module::Runtime: '0.012' requires: Exporter: '5.57' File::Basename: '0' File::Find: '0' File::Spec: '3.00' File::Spec::Functions: '0' if: '0' perl: '5.00503' strict: '0' resources: bugtracker: https://rt.cpan.org/Public/Dist/Display.html?Name=Module-Pluggable repository: https://github.com/simonwistow/Module-Pluggable.git version: '5.2' x_serialization_backend: 'CPAN::Meta::YAML version 0.016' Module-Pluggable-5.2/README000755 000767 000024 00000024107 12046061324 015664 0ustar00simonstaff000000 000000 NAME Module::Pluggable - automatically give your module the ability to have plugins SYNOPSIS Simple use Module::Pluggable - package MyClass; use Module::Pluggable; and then later ... use MyClass; my $mc = MyClass->new(); # returns the names of all plugins installed under MyClass::Plugin::* my @plugins = $mc->plugins(); EXAMPLE Why would you want to do this? Say you have something that wants to pass an object to a number of different plugins in turn. For example you may want to extract meta-data from every email you get sent and do something with it. Plugins make sense here because then you can keep adding new meta data parsers and all the logic and docs for each one will be self contained and new handlers are easy to add without changing the core code. For that, you might do something like ... package Email::Examiner; use strict; use Email::Simple; use Module::Pluggable require => 1; sub handle_email { my $self = shift; my $email = shift; foreach my $plugin ($self->plugins) { $plugin->examine($email); } return 1; } .. and all the plugins will get a chance in turn to look at it. This can be trivally extended so that plugins could save the email somewhere and then no other plugin should try and do that. Simply have it so that the "examine" method returns 1 if it has saved the email somewhere. You might also wnat to be paranoid and check to see if the plugin has an "examine" method. foreach my $plugin ($self->plugins) { next unless $plugin->can('examine'); last if $plugin->examine($email); } And so on. The sky's the limit. DESCRIPTION Provides a simple but, hopefully, extensible way of having 'plugins' for your module. Obviously this isn't going to be the be all and end all of solutions but it works for me. Essentially all it does is export a method into your namespace that looks through a search path for .pm files and turn those into class names. Optionally it instantiates those classes for you. ADVANCED USAGE Alternatively, if you don't want to use 'plugins' as the method ... package MyClass; use Module::Pluggable sub_name => 'foo'; and then later ... my @plugins = $mc->foo(); Or if you want to look in another namespace package MyClass; use Module::Pluggable search_path => ['Acme::MyClass::Plugin', 'MyClass::Extend']; or directory use Module::Pluggable search_dirs => ['mylibs/Foo']; Or if you want to instantiate each plugin rather than just return the name package MyClass; use Module::Pluggable instantiate => 'new'; and then # whatever is passed to 'plugins' will be passed # to 'new' for each plugin my @plugins = $mc->plugins(@options); alternatively you can just require the module without instantiating it package MyClass; use Module::Pluggable require => 1; since requiring automatically searches inner packages, which may not be desirable, you can turn this off package MyClass; use Module::Pluggable require => 1, inner => 0; You can limit the plugins loaded using the except option, either as a string, array ref or regex package MyClass; use Module::Pluggable except => 'MyClass::Plugin::Foo'; or package MyClass; use Module::Pluggable except => ['MyClass::Plugin::Foo', 'MyClass::Plugin::Bar']; or package MyClass; use Module::Pluggable except => qr/^MyClass::Plugin::(Foo|Bar)$/; and similarly for only which will only load plugins which match. Remember you can use the module more than once package MyClass; use Module::Pluggable search_path => 'MyClass::Filters' sub_name => 'filters'; use Module::Pluggable search_path => 'MyClass::Plugins' sub_name => 'plugins'; and then later ... my @filters = $self->filters; my @plugins = $self->plugins; PLUGIN SEARCHING Every time you call 'plugins' the whole search path is walked again. This allows for dynamically loading plugins even at run time. However this can get expensive and so if you don't expect to want to add new plugins at run time you could do package Foo; use strict; use Module::Pluggable sub_name => '_plugins'; our @PLUGINS; sub plugins { @PLUGINS ||= shift->_plugins } 1; INNER PACKAGES If you have, for example, a file lib/Something/Plugin/Foo.pm that contains package definitions for both "Something::Plugin::Foo" and "Something::Plugin::Bar" then as long as you either have either the require or instantiate option set then we'll also find "Something::Plugin::Bar". Nifty! OPTIONS You can pass a hash of options when importing this module. The options can be ... sub_name The name of the subroutine to create in your namespace. By default this is 'plugins' search_path An array ref of namespaces to look in. search_dirs An array ref of directorys to look in before @INC. instantiate Call this method on the class. In general this will probably be 'new' but it can be whatever you want. Whatever arguments are passed to 'plugins' will be passed to the method. The default is 'undef' i.e just return the class name. require Just require the class, don't instantiate (overrides 'instantiate'); inner If set to 0 will not search inner packages. If set to 1 will override "require". only Takes a string, array ref or regex describing the names of the only plugins to return. Whilst this may seem perverse ... well, it is. But it also makes sense. Trust me. except Similar to "only" it takes a description of plugins to exclude from returning. This is slightly less perverse. package This is for use by extension modules which build on "Module::Pluggable": passing a "package" option allows you to place the plugin method in a different package other than your own. file_regex By default "Module::Pluggable" only looks for *.pm* files. By supplying a new "file_regex" then you can change this behaviour e.g file_regex => qr/\.plugin$/ include_editor_junk By default "Module::Pluggable" ignores files that look like they were left behind by editors. Currently this means files ending in ~ (~), the extensions .swp or .swo, or files beginning with .#. Setting "include_editor_junk" changes "Module::Pluggable" so it does not ignore any files it finds. follow_symlinks Whether, when searching directories, to follow symlinks. Defaults to 1 i.e do follow symlinks. min_depth, max_depth This will allow you to set what 'depth' of plugin will be allowed. So, for example, "MyClass::Plugin::Foo" will have a depth of 3 and "MyClass::Plugin::Foo::Bar" will have a depth of 4 so to only get the former (i.e "MyClass::Plugin::Foo") do package MyClass; use Module::Pluggable max_depth => 3; and to only get the latter (i.e "MyClass::Plugin::Foo::Bar") package MyClass; use Module::Pluggable min_depth => 4; TRIGGERS Various triggers can also be passed in to the options. If any of these triggers return 0 then the plugin will not be returned. before_require Gets passed the plugin name. If 0 is returned then this plugin will not be required either. on_require_error Gets called when there's an error on requiring the plugin. Gets passed the plugin name and the error. The default on_require_error handler is to "carp" the error and return 0. on_instantiate_error Gets called when there's an error on instantiating the plugin. Gets passed the plugin name and the error. The default on_instantiate_error handler is to "carp" the error and return 0. after_require Gets passed the plugin name. If 0 is returned then this plugin will be required but not returned as a plugin. METHODs search_path The method "search_path" is exported into you namespace as well. You can call that at any time to change or replace the search_path. $self->search_path( add => "New::Path" ); # add $self->search_path( new => "New::Path" ); # replace BEHAVIOUR UNDER TEST ENVIRONMENT In order to make testing reliable we exclude anything not from blib if blib.pm is in %INC. However if the module being tested used another module that itself used "Module::Pluggable" then the second module would fail. This was fixed by checking to see if the caller had (^|/)blib/ in their filename. There's an argument that this is the wrong behaviour and that modules should explicitly trigger this behaviour but that particular code has been around for 7 years now and I'm reluctant to change the default behaviour. You can now (as of version 4.1) force Module::Pluggable to look outside blib in a test environment by doing either require Module::Pluggable; $Module::Pluggable::FORCE_SEARCH_ALL_PATHS = 1; import Module::Pluggable; or use Module::Pluggable force_search_all_paths => 1; FUTURE PLANS This does everything I need and I can't really think of any other features I want to add. Famous last words of course Recently tried fixed to find inner packages and to make it 'just work' with PAR but there are still some issues. However suggestions (and patches) are welcome. DEVELOPMENT The master repo for this module is at https://github.com/simonwistow/Module-Pluggable AUTHOR Simon Wistow COPYING Copyright, 2006 Simon Wistow Distributed under the same terms as Perl itself. BUGS None known. SEE ALSO File::Spec, File::Find, File::Basename, Class::Factory::Util, Module::Pluggable::Ordered Module-Pluggable-5.2/t/000755 000767 000024 00000000000 12560516377 015256 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/01use.t000755 000767 000024 00000000225 11732723031 016365 0ustar00simonstaff000000 000000 #!perl -w use strict; use Test::More tests => 3; use_ok('Module::Pluggable'); use_ok('Module::Pluggable::Object'); use_ok('Devel::InnerPackage'); Module-Pluggable-5.2/t/02alsoworks.t000644 000767 000024 00000001156 11732723031 017617 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 5; my $foo; ok($foo = MyOtherTest->new()); my @plugins; my @expected = qw(MyOtherTest::Plugin::Bar MyOtherTest::Plugin::Foo MyOtherTest::Plugin::Quux MyOtherTest::Plugin::Quux::Foo); ok(@plugins = sort $foo->plugins); is_deeply(\@plugins, \@expected, "is deeply"); @plugins = (); ok(@plugins = sort MyOtherTest->plugins); is_deeply(\@plugins, \@expected, "is deeply class"); package MyOtherTest; use strict; use Module::Pluggable; sub new { my $class = shift; return bless {}, $class; } 1; Module-Pluggable-5.2/t/02works.t000755 000767 000024 00000001065 11732723031 016742 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 5; my $foo; ok($foo = MyTest->new()); my @plugins; my @expected = qw(MyTest::Plugin::Bar MyTest::Plugin::Foo MyTest::Plugin::Quux::Foo); ok(@plugins = sort $foo->plugins); is_deeply(\@plugins, \@expected, "is deeply"); @plugins = (); ok(@plugins = sort MyTest->plugins); is_deeply(\@plugins, \@expected, "is deeply class"); package MyTest; use strict; use Module::Pluggable; sub new { my $class = shift; return bless {}, $class; } 1; Module-Pluggable-5.2/t/02works_taint.t000755 000767 000024 00000001376 11732723031 020146 0ustar00simonstaff000000 000000 #!perl -wT # NOTE: Module::Pluggable is going into core # and CORE tests can't modify @INC under taint # so this is a work around to make sure it # still works under taint checking. use strict; use Test::More tests => 5; my $foo; ok($foo = MyTest->new()); my @plugins; my @expected = qw(Module::Pluggable::Object); ok(@plugins = sort $foo->plugins); ok(grep {/Module::Pluggable::Object/} @plugins, "Contains Module::Pluggable::Object"); @plugins = (); ok(@plugins = sort MyTest->plugins); ok(grep {/Module::Pluggable::Object/} @plugins, "Contains Module::Pluggable::Object under class method"); package MyTest; use strict; use Module::Pluggable search_path => 'Module::Pluggable'; sub new { my $class = shift; return bless {}, $class; } 1; Module-Pluggable-5.2/t/03diffname.t000755 000767 000024 00000000707 11732723031 017351 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 3; my $foo; ok($foo = MyTest->new()); my @plugins; my @expected = qw(MyTest::Plugin::Bar MyTest::Plugin::Foo MyTest::Plugin::Quux::Foo); ok(@plugins = sort $foo->foo); is_deeply(\@plugins, \@expected); package MyTest; use strict; use Module::Pluggable ( sub_name => 'foo'); sub new { my $class = shift; return bless {}, $class; } 1; Module-Pluggable-5.2/t/04acmedir.t000644 000767 000024 00000000770 11732723031 017202 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 3; my $foo; ok($foo = MyTest->new()); my @plugins; my @expected = qw(Acme::MyTest::Plugin::Foo); ok(@plugins = sort $foo->plugins); is_deeply(\@plugins, \@expected); package MyTest; use File::Spec::Functions qw(catdir); use strict; use Module::Pluggable search_path => ["Acme::MyTest::Plugin"], search_dirs => [ "t/acme" ]; sub new { my $class = shift; return bless {}, $class; } 1; Module-Pluggable-5.2/t/04acmedir_single.t000644 000767 000024 00000000763 11732723031 020545 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 3; my $foo; ok($foo = MyTest->new()); my @plugins; my @expected = qw(Acme::MyTest::Plugin::Foo); ok(@plugins = sort $foo->plugins); is_deeply(\@plugins, \@expected); package MyTest; use File::Spec::Functions qw(catdir); use strict; use Module::Pluggable search_path => "Acme::MyTest::Plugin", search_dirs => "t/acme" ; sub new { my $class = shift; return bless {}, $class; } 1; Module-Pluggable-5.2/t/04acmepath.t000755 000767 000024 00000000735 11732723031 017364 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 3; my $foo; ok($foo = MyTest->new()); my @plugins; my @expected = qw(Acme::MyTest::Plugin::Foo); ok(@plugins = sort $foo->plugins); is_deeply(\@plugins, \@expected); package MyTest; use File::Spec::Functions qw(catdir); use strict; use Module::Pluggable (search_path => ["Acme::MyTest::Plugin"]); sub new { my $class = shift; return bless {}, $class; } 1; Module-Pluggable-5.2/t/04acmepath_single.t000644 000767 000024 00000000731 11732723031 020716 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 3; my $foo; ok($foo = MyTest->new()); my @plugins; my @expected = qw(Acme::MyTest::Plugin::Foo); ok(@plugins = sort $foo->plugins); is_deeply(\@plugins, \@expected); package MyTest; use File::Spec::Functions qw(catdir); use strict; use Module::Pluggable search_path => "Acme::MyTest::Plugin"; sub new { my $class = shift; return bless {}, $class; } 1; Module-Pluggable-5.2/t/05postpath.t000755 000767 000024 00000000742 11732723031 017443 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 3; my $foo; ok($foo = MyTest->new()); my @plugins; my @expected = qw(MyTest::Extend::Plugin::Bar); ok(@plugins = sort $foo->plugins); is_deeply(\@plugins, \@expected); package MyTest; use File::Spec::Functions qw(catdir); use strict; use Module::Pluggable (search_path => ["MyTest::Extend::Plugin"]); sub new { my $class = shift; return bless {}, $class; } 1; Module-Pluggable-5.2/t/06multipath.t000755 000767 000024 00000001073 12002103774 017604 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 3; my $foo; ok($foo = MyTest->new()); my @plugins; my @expected = qw(Acme::MyTest::Plugin::Foo MyTest::Extend::Plugin::Bar); ok(@plugins = sort $foo->plugins); is_deeply(\@plugins, \@expected); package MyTest; use File::Spec::Functions qw(catdir); use strict; use File::Spec::Functions qw(catdir); use Module::Pluggable (search_path => ["MyTest::Extend::Plugin", "Acme::MyTest::Plugin"]); sub new { my $class = shift; return bless {}, $class; } 1; Module-Pluggable-5.2/t/07instantiate.t000755 000767 000024 00000001463 11732723031 020127 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 6; my $foo; ok($foo = MyTest->new()); my @plugins; ok(@plugins = sort $foo->booga(nork => 'fark')); is(ref $plugins[0],'MyTest::Extend::Plugin::Bar'); is($plugins[0]->nork,'fark'); @plugins = (); eval { @plugins = $foo->wooga( nork => 'fark') }; is($@, ''); is(scalar(@plugins),0); package MyTest; use File::Spec::Functions qw(catdir); use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Module::Pluggable (search_path => ["MyTest::Extend::Plugin"], sub_name => 'booga', instantiate => 'new'); use Module::Pluggable (search_path => ["MyTest::Extend::Plugin"], sub_name => 'wooga', instantiate => 'nosomuchmethod'); sub new { my $class = shift; return bless {}, $class; } 1; Module-Pluggable-5.2/t/08nothing.t000755 000767 000024 00000000721 11732723031 017247 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 2; my $foo; ok($foo = MyTest->new()); my @expected = (); my @plugins = sort $foo->plugins; is_deeply(\@plugins, \@expected); package MyTest; use File::Spec::Functions qw(catdir); use strict; use Module::Pluggable (search_path => ["No::Such::Modules"]); use base qw(Module::Pluggable); sub new { my $class = shift; return bless {}, $class; } 1; Module-Pluggable-5.2/t/09require.t000755 000767 000024 00000000615 11732723031 017260 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 2; my $t = MyTest->new(); ok($t->plugins()); ok(keys %{MyTest::Plugin::Foo::}); package MyTest; use File::Spec::Functions qw(catdir); use strict; use Module::Pluggable (require => 1); use base qw(Module::Pluggable); sub new { my $class = shift; return bless {}, $class; } 1; Module-Pluggable-5.2/t/10innerpack.t000644 000767 000024 00000001124 11732723031 017537 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 4; my $t = InnerTest->new(); my %plugins = map { $_ => 1 } $t->plugins; ok(keys %plugins, "Got some plugins"); ok($plugins{'InnerTest::Plugin::Foo'}, "Got Foo"); ok($plugins{'InnerTest::Plugin::Bar'}, "Got Bar - the inner package"); ok($plugins{'InnerTest::Plugin::Quux'}, "Got Quux - the other inner package"); package InnerTest; use strict; use Module::Pluggable require => 1; use base qw(Module::Pluggable); sub new { my $class = shift; return bless {}, $class; } 1; Module-Pluggable-5.2/t/10innerpack_inner.t000644 000767 000024 00000001003 11732723031 020726 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 3; my $t = InnerTest->new(); my %plugins = map { $_ => 1 } $t->plugins; ok(keys %plugins, "Got some plugins"); ok($plugins{'InnerTest::Plugin::Foo'}, "Got Foo"); ok($plugins{'InnerTest::Plugin::Bar'}, "Got Bar - the inner package"); package InnerTest; use strict; use Module::Pluggable inner => 1; use base qw(Module::Pluggable); sub new { my $class = shift; return bless {}, $class; } 1; Module-Pluggable-5.2/t/10innerpack_noinner.t000644 000767 000024 00000001031 11732723031 021264 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 3; my $t = InnerTest->new(); my %plugins = map { $_ => 1 } $t->plugins; ok(keys %plugins, "Got some plugins"); ok($plugins{'InnerTest::Plugin::Foo'}, "Got Foo"); ok(!$plugins{'InnerTest::Plugin::Bar'}, "Didn't get Bar - the inner package"); package InnerTest; use strict; use Module::Pluggable require => 1, inner => 0; use base qw(Module::Pluggable); sub new { my $class = shift; return bless {}, $class; } 1; Module-Pluggable-5.2/t/10innerpack_onefile.t000644 000767 000024 00000001077 11732723031 021247 0ustar00simonstaff000000 000000 #!perl -wT use strict; use Test::More tests => 2; use Data::Dumper; my $mc = MyClass->new(); my $mc2 = MyClass2->new(); is_deeply([$mc->plugins], [qw(MyClass::Plugin::MyPlugin)], "Got inner plugin"); is_deeply([$mc2->plugins], [], "Didn't get plugin"); package MyClass::Plugin::MyPlugin; sub pretty { print "I am pretty" }; package MyClass; use Module::Pluggable inner => 1; sub new { return bless {}, $_[0] } package MyClass2; use Module::Pluggable search_path => "MyClass::Plugin", inner => 0; sub new { return bless {}, $_[0] } 1; Module-Pluggable-5.2/t/10innerpack_override.t000644 000767 000024 00000001021 11732723031 021432 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 3; my $t = InnerTest->new(); my %plugins = map { $_ => 1 } $t->plugins; ok(keys %plugins, "Got some plugins"); ok($plugins{'InnerTest::Plugin::Foo'}, "Got Foo"); ok($plugins{'InnerTest::Plugin::Bar'}, "Got Bar - the inner package"); package InnerTest; use strict; use Module::Pluggable require => 0, inner => 1; use base qw(Module::Pluggable); sub new { my $class = shift; return bless {}, $class; } 1; Module-Pluggable-5.2/t/10innerpack_super.t000644 000767 000024 00000000674 11732723031 020766 0ustar00simonstaff000000 000000 #!perl -wT use Test::More tests => 3; use strict; use_ok('Devel::InnerPackage'); Bar->whee; is_deeply([Devel::InnerPackage::list_packages("Bar")],[], "Don't pick up ::SUPER pseudo stash"); is_deeply([Devel::InnerPackage::list_packages("Foo")],['Foo::Bar'], "Still pick up other inner package"); package Foo; sub whee { 1; } package Foo::Bar; sub whee {} package Bar; use base 'Foo'; sub whee { shift->SUPER::whee; 2; } 1; Module-Pluggable-5.2/t/11usetwice.t000644 000767 000024 00000001355 11732723031 017424 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 3; my $foo; ok($foo = MyTest->new()); my @plugins; my @expected = qw(MyTest::Extend::Plugin::Bar MyTest::Plugin::Bar MyTest::Plugin::Foo MyTest::Plugin::Quux::Foo); push @plugins, $foo->plugins; push @plugins, $foo->foo; @plugins = sort @plugins; is_deeply(\@plugins, \@expected); @plugins = (); push @plugins, MyTest->plugins; push @plugins, MyTest->foo; @plugins = sort @plugins; is_deeply(\@plugins, \@expected); package MyTest; use strict; use Module::Pluggable; use Module::Pluggable ( search_path => [ "MyTest::Extend::Plugin" ] , sub_name => 'foo' ); sub new { my $class = shift; return bless {}, $class; } 1; Module-Pluggable-5.2/t/12only.t000644 000767 000024 00000002043 11732723031 016551 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 10; { my $foo; ok($foo = MyTest->new()); my @plugins; my @expected = qw(MyTest::Plugin::Foo); ok(@plugins = sort $foo->plugins); is_deeply(\@plugins, \@expected); @plugins = (); ok(@plugins = sort MyTest->plugins); is_deeply(\@plugins, \@expected); } { my $foo; ok($foo = MyTestSub->new()); my @plugins; my @expected = qw(MyTest::Plugin::Foo); ok(@plugins = sort $foo->plugins); is_deeply(\@plugins, \@expected); @plugins = (); ok(@plugins = sort MyTestSub->plugins); is_deeply(\@plugins, \@expected); } package MyTest; use strict; use Module::Pluggable only => "MyTest::Plugin::Foo"; sub new { my $class = shift; return bless {}, $class; } package MyTestSub; use strict; use Module::Pluggable search_path => "MyTest::Plugin"; sub new { my $class = shift; my $self = bless {}, $class; $self->only("MyTest::Plugin::Foo"); return $self; } 1; Module-Pluggable-5.2/t/12onlyarray.t000644 000767 000024 00000002052 11732723031 017610 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 10; { my $foo; ok($foo = MyTest->new()); my @plugins; my @expected = qw(MyTest::Plugin::Foo); ok(@plugins = sort $foo->plugins); is_deeply(\@plugins, \@expected); @plugins = (); ok(@plugins = sort MyTest->plugins); is_deeply(\@plugins, \@expected); } { my $foo; ok($foo = MyTestSub->new()); my @plugins; my @expected = qw(MyTest::Plugin::Foo); ok(@plugins = sort $foo->plugins); is_deeply(\@plugins, \@expected); @plugins = (); ok(@plugins = sort MyTestSub->plugins); is_deeply(\@plugins, \@expected); } package MyTest; use strict; use Module::Pluggable only => [ "MyTest::Plugin::Foo" ]; sub new { my $class = shift; return bless {}, $class; } package MyTestSub; use strict; use Module::Pluggable search_path => "MyTest::Plugin"; sub new { my $class = shift; my $self = bless {}, $class; $self->only(["MyTest::Plugin::Foo"]); return $self; } 1; Module-Pluggable-5.2/t/12onlyregex.t000644 000767 000024 00000002052 11732723031 017604 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 10; { my $foo; ok($foo = MyTest->new()); my @plugins; my @expected = qw(MyTest::Plugin::Foo); ok(@plugins = sort $foo->plugins); is_deeply(\@plugins, \@expected); @plugins = (); ok(@plugins = sort MyTest->plugins); is_deeply(\@plugins, \@expected); } { my $foo; ok($foo = MyTestSub->new()); my @plugins; my @expected = qw(MyTest::Plugin::Foo); ok(@plugins = sort $foo->plugins); is_deeply(\@plugins, \@expected); @plugins = (); ok(@plugins = sort MyTestSub->plugins); is_deeply(\@plugins, \@expected); } package MyTest; use strict; use Module::Pluggable only => qr/MyTest::Plugin::Foo$/; sub new { my $class = shift; return bless {}, $class; } package MyTestSub; use strict; use Module::Pluggable search_path => "MyTest::Plugin"; sub new { my $class = shift; my $self = bless {}, $class; $self->only(qr/MyTest::Plugin::Foo$/); return $self; } 1; Module-Pluggable-5.2/t/12onlyrequire.t000644 000767 000024 00000000664 11732723031 020155 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 2; my @packages = eval { Zot->_dist_types }; is($@, '', "No warnings"); is(scalar(@packages), 0, "Correctly only got 1 package"); package Zot; use strict; use Module::Pluggable ( sub_name => '_dist_types', search_path => __PACKAGE__, only => qr/Zot::\w+$/, require => 1, ); 1; Module-Pluggable-5.2/t/13except.t000644 000767 000024 00000002137 11732723031 017065 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 10; { my $foo; ok($foo = MyTest->new()); my @plugins; my @expected = qw(MyTest::Plugin::Bar MyTest::Plugin::Quux::Foo); ok(@plugins = sort $foo->plugins); is_deeply(\@plugins, \@expected); @plugins = (); ok(@plugins = sort MyTest->plugins); is_deeply(\@plugins, \@expected); } { my $foo; ok($foo = MyTestSub->new()); my @plugins; my @expected = qw(MyTest::Plugin::Bar MyTest::Plugin::Quux::Foo); ok(@plugins = sort $foo->plugins); is_deeply(\@plugins, \@expected); @plugins = (); ok(@plugins = sort MyTestSub->plugins); is_deeply(\@plugins, \@expected); } package MyTest; use strict; use Module::Pluggable except => "MyTest::Plugin::Foo"; sub new { my $class = shift; return bless {}, $class; } package MyTestSub; use strict; use Module::Pluggable search_path => "MyTest::Plugin"; sub new { my $class = shift; my $self = bless {}, $class; $self->except("MyTest::Plugin::Foo"); return $self; } 1; Module-Pluggable-5.2/t/13exceptarray.t000644 000767 000024 00000002146 11732723031 020124 0ustar00simonstaff000000 000000 #!perl -wT use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 10; { my $foo; ok($foo = MyTest->new()); my @plugins; my @expected = qw(MyTest::Plugin::Bar MyTest::Plugin::Quux::Foo); ok(@plugins = sort $foo->plugins); is_deeply(\@plugins, \@expected); @plugins = (); ok(@plugins = sort MyTest->plugins); is_deeply(\@plugins, \@expected); } { my $foo; ok($foo = MyTestSub->new()); my @plugins; my @expected = qw(MyTest::Plugin::Bar MyTest::Plugin::Quux::Foo); ok(@plugins = sort $foo->plugins); is_deeply(\@plugins, \@expected); @plugins = (); ok(@plugins = sort MyTestSub->plugins); is_deeply(\@plugins, \@expected); } package MyTest; use strict; use Module::Pluggable except => [ "MyTest::Plugin::Foo" ]; sub new { my $class = shift; return bless {}, $class; } package MyTestSub; use strict; use Module::Pluggable search_path => "MyTest::Plugin"; sub new { my $class = shift; my $self = bless {}, $class; $self->except(["MyTest::Plugin::Foo"]); return $self; } 1; Module-Pluggable-5.2/t/13exceptregex.t000644 000767 000024 00000002144 11732723031 020116 0ustar00simonstaff000000 000000 #!perl -wT use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 10; { my $foo; ok($foo = MyTest->new()); my @plugins; my @expected = qw(MyTest::Plugin::Bar MyTest::Plugin::Quux::Foo); ok(@plugins = sort $foo->plugins); is_deeply(\@plugins, \@expected); @plugins = (); ok(@plugins = sort MyTest->plugins); is_deeply(\@plugins, \@expected); } { my $foo; ok($foo = MyTestSub->new()); my @plugins; my @expected = qw(MyTest::Plugin::Bar MyTest::Plugin::Quux::Foo); ok(@plugins = sort $foo->plugins); is_deeply(\@plugins, \@expected); @plugins = (); ok(@plugins = sort MyTestSub->plugins); is_deeply(\@plugins, \@expected); } package MyTest; use strict; use Module::Pluggable except => qr/MyTest::Plugin::Foo/; sub new { my $class = shift; return bless {}, $class; } package MyTestSub; use strict; use Module::Pluggable search_path => "MyTest::Plugin"; sub new { my $class = shift; my $self = bless {}, $class; $self->except(qr/MyTest::Plugin::Foo/); return $self; } 1; Module-Pluggable-5.2/t/14package.t000644 000767 000024 00000001114 11732723031 017163 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 5; my $foo; ok($foo = MyTest->new()); my @plugins; my @expected = qw(MyTest::Plugin::Bar MyTest::Plugin::Foo MyTest::Plugin::Quux::Foo); ok(@plugins = sort $foo->plugins); is_deeply(\@plugins, \@expected); @plugins = (); ok(@plugins = sort MyTest->plugins); is_deeply(\@plugins, \@expected); package MyTest; use strict; sub new { return bless {}, $_[0] } package MyOtherTest; use strict; use Module::Pluggable ( package => "MyTest" ); sub new { return bless {}, $_[0] } 1; Module-Pluggable-5.2/t/15topicsafe.t000644 000767 000024 00000000414 11732723031 017550 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More 'no_plan'; use Module::Pluggable search_path => 'Acme::MyTest'; my $topic = "topic"; for ($topic) { main->plugins; } is($topic, 'topic', "we've got the right topic"); Module-Pluggable-5.2/t/16different_extension.t000755 000767 000024 00000001127 11732723031 021643 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 5; my $foo; ok($foo = ExtTest->new()); my @plugins; my @expected = qw(ExtTest::Plugin::Bar ExtTest::Plugin::Foo ExtTest::Plugin::Quux::Foo); ok(@plugins = sort $foo->plugins); is_deeply(\@plugins, \@expected, "is deeply"); @plugins = (); ok(@plugins = sort ExtTest->plugins); is_deeply(\@plugins, \@expected, "is deeply class"); package ExtTest; use strict; use Module::Pluggable file_regex => qr/\.plugin$/; sub new { my $class = shift; return bless {}, $class; } 1; Module-Pluggable-5.2/t/17devel_inner_package.t000644 000767 000024 00000000447 11732723031 021550 0ustar00simonstaff000000 000000 #!perl -w use Test::More tests => 3; use Devel::InnerPackage qw(list_packages); use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); my @packages; use_ok("TA::C::A::I"); ok(@packages = list_packages("TA::C::A::I")); is_deeply([sort @packages], [qw(TA::C::A::I::A TA::C::A::I::A::B)]); Module-Pluggable-5.2/t/18skipped_package.t000644 000767 000024 00000000420 11732723031 020705 0ustar00simonstaff000000 000000 #!perl -w use Test::More tests => 1; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Devel::InnerPackage qw(list_packages); use No::Middle; my @p = list_packages("No::Middle"); is_deeply([ sort @p ], [ qw(No::Middle::Package::A No::Middle::Package::B) ]); Module-Pluggable-5.2/t/19can_ok_clobber.t000644 000767 000024 00000001526 12113007365 020525 0ustar00simonstaff000000 000000 #!/usr/bin/perl use strict; use warnings; use Data::Dumper; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests=>5; #use_ok( 'MyTest' ); #diag "Module::Pluggable::VERSION $Module::Pluggable::VERSION"; my @plugins = sort MyTest->plugins; my @plugins_after; use_ok( 'MyTest::Plugin::Foo' ); ok( my $foo = MyTest::Plugin::Foo->new() ); @plugins_after = MyTest->plugins; is_deeply( \@plugins_after, \@plugins, "plugins haven't been clobbered", ) or diag Dumper(\@plugins_after,\@plugins); can_ok ($foo, 'frobnitz'); @plugins_after = sort MyTest->plugins; is_deeply( \@plugins_after, \@plugins, "plugins haven't been clobbered", ) or diag Dumper(\@plugins_after,\@plugins); package MyTest; use strict; use Module::Pluggable; sub new { my $class = shift; return bless {}, $class; } 1; Module-Pluggable-5.2/t/20dodgy_files.t000755 000767 000024 00000003210 11732723031 020057 0ustar00simonstaff000000 000000 #!perl -w BEGIN { if ($^O eq 'VMS' || $^O eq 'VOS') { print "1..0 # Skip: can't handle misspelled plugin names\n"; exit; } } use strict; use FindBin; use Test::More; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use File::Spec::Functions qw(catfile); my ($dodgy_file) = (catfile($FindBin::Bin, "lib", "OddTest", "Plugin", "-Dodgy.pm")=~/^(.*)$/); unless (-f $dodgy_file) { plan skip_all => "Can't handle misspelled plugin names\n"; } else { plan tests => 5; } my $foo; ok($foo = OddTest->new()); my @plugins; my @expected = ('OddTest::Plugin::-Dodgy', 'OddTest::Plugin::Foo'); ok(@plugins = sort $foo->plugins); is_deeply(\@plugins, \@expected, "is deeply"); my @odd_plugins; my @odd_expected = qw(OddTest::Plugin::Foo); ok(@odd_plugins = sort $foo->odd_plugins); is_deeply(\@odd_plugins, \@odd_expected, "is deeply"); package OddTest::Pluggable; use Data::Dumper; use base qw(Module::Pluggable::Object); sub find_files { my $self = shift; my @files = $self->SUPER::find_files(@_); return grep { !/(^|\/)-/ } $self->SUPER::find_files(@_) ; } package OddTest; use strict; use Module::Pluggable; sub new { my $class = shift; return bless {}, $class; } sub odd_plugins { my $self = shift; my %opts; my ($pkg, $file) = caller; # the default name for the method is 'plugins' my $sub = $opts{'sub_name'} || 'plugins'; # get our package my ($package) = $opts{'package'} || "OddTest"; $opts{filename} = $file; $opts{package} = $package; my $op = OddTest::Pluggable->new( package => ref($self) ); return $op->plugins(@_); } 1; Module-Pluggable-5.2/t/21editor_junk.t000644 000767 000024 00000002042 11732723031 020104 0ustar00simonstaff000000 000000 #!perl -w use Test::More; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Module::Pluggable::Object; use File::Spec::Functions qw(catfile); my ($dodgy_file) = (catfile($FindBin::Bin,"lib", "EditorJunk", "Plugin", "#Bar.pm#")=~/^(.*)$/); unless (-f $dodgy_file) { plan skip_all => "Can't handle plugin names with octothorpes\n"; } else { plan tests => 4; } my $foo; ok($foo = EditorJunk->new()); my @plugins; my @expected = qw(EditorJunk::Plugin::Bar EditorJunk::Plugin::Foo); ok(@plugins = sort $foo->plugins); is_deeply(\@plugins, \@expected, "is deeply"); my $mpo = Module::Pluggable::Object->new( package => 'EditorJunk', filename => __FILE__, include_editor_junk => 1, ); @expected = ('EditorJunk::Plugin::.#Bar', 'EditorJunk::Plugin::Bar', 'EditorJunk::Plugin::Foo'); @plugins = sort $mpo->plugins(); is_deeply(\@plugins, \@expected, "is deeply"); package EditorJunk; use strict; use Module::Pluggable; sub new { my $class = shift; return bless {}, $class; } 1; Module-Pluggable-5.2/t/22trigger.t000644 000767 000024 00000003001 12012505062 017221 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 7; my $foo; my @plugins; my @errors; ok($foo = TriggerTest->new(), "Created new TriggerTest"); ok(@plugins = $foo->plugins, "Ran plugins"); ok(@errors = $foo->errors, "Got errors"); is_deeply([sort @plugins], ['TriggerTest::Plugin::After', 'TriggerTest::Plugin::CallbackAllow'], "Got the correct plugins"); is_deeply([@errors], ['TriggerTest::Plugin::Error'], "Got the correct errors"); ok(_is_loaded('TriggerTest::Plugin::CallbackDeny'), "CallbackDeny has been required"); ok(!_is_loaded('TriggerTest::Plugin::Deny'), "Deny has not been required"); # Stolen from Module::Loaded by Chris Williams (bingOs) sub _is_loaded { my $pm = shift; my $file = __PACKAGE__->_pm_to_file( $pm ) or return; return $INC{$file} if exists $INC{$file}; return; } sub _pm_to_file { my $pkg = shift; my $pm = shift or return; my $file = join '/', split '::', $pm; $file .= '.pm'; return $file; } package TriggerTest; our @ERRORS; use strict; use Module::Pluggable require => 1, on_require_error => sub { my $p = shift; push @ERRORS, $p; return 0 }, before_require => sub { my $p = shift; return !($p eq "TriggerTest::Plugin::Deny") }, after_require => sub { my $p = shift; return !($p->can('exclude') && $p->exclude) }; sub new { my $class = shift; return bless {}, $class; } sub errors { @ERRORS; } 1; Module-Pluggable-5.2/t/23depth.t000644 000767 000024 00000001557 12046055305 016710 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 2; my $min = MinTest->new(); my $max = MaxTest->new(); is_deeply([sort qw(MyOtherTest::Plugin::Bar MyOtherTest::Plugin::Foo MyOtherTest::Plugin::Quux)], [sort $max->plugins], "min depth"); is_deeply([qw(MyOtherTest::Plugin::Quux::Foo)], [sort $min->plugins], "max depth"); package MinTest; use File::Spec::Functions qw(catdir); use strict; use File::Spec::Functions qw(catdir); use Module::Pluggable search_path => "MyOtherTest::Plugin", min_depth => 4; sub new { my $class = shift; return bless {}, $class; } package MaxTest; use File::Spec::Functions qw(catdir); use strict; use File::Spec::Functions qw(catdir); use Module::Pluggable search_path => "MyOtherTest::Plugin", max_depth => 3; sub new { my $class = shift; return bless {}, $class; } 1;Module-Pluggable-5.2/t/24local_inc_object.t000644 000767 000024 00000001267 12151037177 021060 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use Test::More tests => 2; eval { require 'Text::BibTex' }; my $bibtex = !$@; SKIP: { skip "This test fails when Text::BibTex is installed", 2 if $bibtex; my $inc = IncTest->new(); my ($ta) = grep { ref($_) eq 'Text::Abbrev'} eval { local ($^W) = 0; $inc->plugins }; ok($ta); is($ta->MPCHECK, "HELLO"); }; package IncTest; use Module::Pluggable search_path => "Text", search_dirs => "t/lib", instantiate => 'module_pluggable', on_require_error => sub { }, on_instantiate_error => sub { }; sub new { my $class = shift; return bless {}, $class; } 1; Module-Pluggable-5.2/t/24local_inc_package.t000644 000767 000024 00000000657 12151037177 021207 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use Test::More tests => 1; eval { require 'Text::BibTex' }; my $bibtex = !$@; SKIP: { skip "This test fails when Text::BibTex is installed", 2 if $bibtex; IncTest->new()->plugins; is(Text::Abbrev->MPCHECK, "HELLO"); } package IncTest; use Module::Pluggable search_path => "Text", search_dirs => "t/lib", require => 1; sub new { my $class = shift; return bless {}, $class; } 1;Module-Pluggable-5.2/t/25single_letter_package.t000755 000767 000024 00000000774 12231524124 022120 0ustar00simonstaff000000 000000 #!perl -w use strict; use FindBin; use lib (($FindBin::Bin."/lib")=~/^(.*)$/); use Test::More tests => 5; my $foo; ok($foo = M->new()); my @plugins; my @expected = qw(M::X); ok(@plugins = sort $foo->plugins); is_deeply(\@plugins, \@expected, "is deeply"); @plugins = (); ok(@plugins = sort M->plugins); is_deeply(\@plugins, \@expected, "is deeply class"); package M; use strict; use Module::Pluggable search_path => "M"; sub new { my $class = shift; return bless {}, $class; } 1; Module-Pluggable-5.2/t/26inc_hook.t000755 000767 000024 00000001217 12255157674 017412 0ustar00simonstaff000000 000000 #!perl -w use strict; use Test::More tests => 2; my @plugins = Foo->plugins; is($plugins[0], 'IncHook::Test', "found module"); is($plugins[0]->found_it, 'IncHook::Test', "ran module"); package IncHook; use strict; sub new { return bless {}, shift } sub IncHook::INC { my ($self, $filename) = @_; return unless $filename eq 'IncHook/Test.pm'; my @sub = ('package IncHook::Test; sub found_it { return __PACKAGE__ }; 1;'); return sub { defined($_ = shift @sub) }; } sub files { qw(IncHook/Test.pm) } package Foo; use strict; use Module::Pluggable require => 1, search_path => 'IncHook'; BEGIN { unshift @INC, IncHook->new }; 1;Module-Pluggable-5.2/t/27app_fatpacker.t000755 000767 000024 00000003570 12255161073 020412 0ustar00simonstaff000000 000000 #!perl use strict; use warnings; use Test::More; BEGIN { my $need_version = "0.10.0"; eval "use App::FatPacker $need_version ; 1; " or plan skip_all => "App::FatPacker >= $need_version not available"; } use Cwd 'cwd'; use File::Temp; use File::Copy; use File::Find; use File::Path 'mkpath'; # use legacy interface for backwards compatibility use File::Spec::Functions qw(catdir catfile splitdir); # prepare directory for App::FatPacker my $testdir = File::Temp->newdir; my $fatlib = catdir($testdir->dirname, 'fatlib'); # copy our Module::Pluggable to $tempdir/fatlib mkpath $fatlib; copy_dir('lib', $fatlib, 1); # Copy the test application and its plugins to $tempdir/lib copy_dir(catdir('t', 'fp'), $testdir->dirname, 2); # fatpack it. fatpacker requires files be in the current directory my $cwd = cwd; my $packed = eval { chdir $testdir or die "unable to chdir to $testdir\n"; my $fp = App::FatPacker->new; $fp->fatpack_file('app.pl'); }; my $err = $@; chdir $cwd; BAIL_OUT("error fatpacking test application: $err") if $@; # write packed application to a file outside of the test dir to # make sure there's no way it can see its modules my $packed_file = File::Temp->new; $packed_file->print($packed); $packed_file->close; # run it (and it's included tests ) require_ok $packed_file; done_testing; sub copy_dir { my ($from, $to, $shift) = @_; find( sub { my @p = splitdir($File::Find::dir); splice(@p, 0, $shift); my $ddir = catdir($to, @p); if (-d $_) { $ddir = catdir($ddir, $_); mkpath $ddir unless -d $ddir; } else { unless (copy($_, $ddir)) { my $file = catfile( $File::Find::dir, $_ ); die "error copying $file to $ddir: $!\n"; } } }, $from ); } Module-Pluggable-5.2/t/acme/000755 000767 000024 00000000000 12560516377 016163 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/fp/000755 000767 000024 00000000000 12560516377 015663 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/000755 000767 000024 00000000000 12560516377 016024 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/Acme/000755 000767 000024 00000000000 12560516377 016671 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/EditorJunk/000755 000767 000024 00000000000 12560516377 020102 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/ExtTest/000755 000767 000024 00000000000 12560516377 017424 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/InnerTest/000755 000767 000024 00000000000 12560516377 017737 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/M/000755 000767 000024 00000000000 12560516377 016220 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/MyOtherTest/000755 000767 000024 00000000000 12560516377 020253 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/MyTest/000755 000767 000024 00000000000 12560516377 017251 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/No/000755 000767 000024 00000000000 12560516377 016400 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/OddTest/000755 000767 000024 00000000000 12560516377 017372 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/TA/000755 000767 000024 00000000000 12560516377 016330 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/Text/000755 000767 000024 00000000000 12560516377 016750 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/TriggerTest/000755 000767 000024 00000000000 12560516377 020267 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/Zot/000755 000767 000024 00000000000 12560516377 016600 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/Zot/.Zork.pm000644 000767 000024 00000000000 11732723031 020112 0ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/TriggerTest/Plugin/000755 000767 000024 00000000000 12560516377 021525 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/TriggerTest/Plugin/After.pm000644 000767 000024 00000000047 12002065255 023106 0ustar00simonstaff000000 000000 package TriggerTest::Plugin::After; 1;Module-Pluggable-5.2/t/lib/TriggerTest/Plugin/CallbackAllow.pm000644 000767 000024 00000000115 12002065255 024534 0ustar00simonstaff000000 000000 package TriggerTest::Plugin::CallbackAllow; sub exclude { return 0; } 1;Module-Pluggable-5.2/t/lib/TriggerTest/Plugin/CallbackDeny.pm000644 000767 000024 00000000114 12002065255 024354 0ustar00simonstaff000000 000000 package TriggerTest::Plugin::CallbackDeny; sub exclude { return 1; } 1;Module-Pluggable-5.2/t/lib/TriggerTest/Plugin/Deny.pm000644 000767 000024 00000000046 12002065255 022743 0ustar00simonstaff000000 000000 package TriggerTest::Plugin::Deny; 1;Module-Pluggable-5.2/t/lib/TriggerTest/Plugin/Error.pm000644 000767 000024 00000000045 12002065255 023134 0ustar00simonstaff000000 000000 package TriggerTest::Plugin::Error; Module-Pluggable-5.2/t/lib/Text/Abbrev.pm000644 000767 000024 00000000164 12013017762 020473 0ustar00simonstaff000000 000000 package Text::Abbrev; use strict; sub module_pluggable { return bless {}, shift; } sub MPCHECK { "HELLO" } 1;Module-Pluggable-5.2/t/lib/TA/C/000755 000767 000024 00000000000 12560516377 016512 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/TA/C/A/000755 000767 000024 00000000000 12560516377 016672 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/TA/C/A/I.pm000644 000767 000024 00000000165 11732723031 017405 0ustar00simonstaff000000 000000 package TA::C::A::I; sub foo { } package TA::C::A::I::A; sub foo { } package TA::C::A::I::A::B; sub foo { } 1; Module-Pluggable-5.2/t/lib/OddTest/Plugin/000755 000767 000024 00000000000 12560516377 020630 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/OddTest/Plugin/Foo.pm000644 000767 000024 00000000057 11732723031 021676 0ustar00simonstaff000000 000000 package OddFiles/Plugin/Foo.pm sub new {} 1; Module-Pluggable-5.2/t/lib/No/Middle.pm000644 000767 000024 00000000177 11732723031 020124 0ustar00simonstaff000000 000000 package No::Middle; sub foo {} package No::Middle::Package::A; sub foo {} package No::Middle::Package::B; sub foo {} 1; Module-Pluggable-5.2/t/lib/MyTest/Extend/000755 000767 000024 00000000000 12560516377 020500 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/MyTest/Plugin/000755 000767 000024 00000000000 12560516377 020507 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/MyTest/Plugin/Bar.pm000755 000767 000024 00000000062 11732723031 021535 0ustar00simonstaff000000 000000 package MyTest::Plugin::Bar; use strict; 1; Module-Pluggable-5.2/t/lib/MyTest/Plugin/Foo.pm000755 000767 000024 00000000145 11732723031 021556 0ustar00simonstaff000000 000000 package MyTest::Plugin::Foo; use strict; sub new { return bless {}, $_[0]; } sub frobnitz {} 1; Module-Pluggable-5.2/t/lib/MyTest/Plugin/Quux/000755 000767 000024 00000000000 12560516377 021451 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/MyTest/Plugin/Quux/Foo.pm000755 000767 000024 00000000070 11732723031 022515 0ustar00simonstaff000000 000000 package MyTest::Plugin::Quux::Foo; use strict; 1; Module-Pluggable-5.2/t/lib/MyTest/Extend/Plugin/000755 000767 000024 00000000000 12560516377 021736 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/MyTest/Extend/Plugin/Bar.pm000755 000767 000024 00000000256 11732723031 022771 0ustar00simonstaff000000 000000 package MyTest::Extend::Plugin::Bar; use strict; sub new { my $class = shift; my %self = @_; return bless \%self, $class; } sub nork { return $_[0]->{'nork'}; } 1; Module-Pluggable-5.2/t/lib/MyOtherTest/Plugin/000755 000767 000024 00000000000 12560516377 021511 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/MyOtherTest/Plugin/Bar.pm000644 000767 000024 00000000063 11732723031 022535 0ustar00simonstaff000000 000000 package MyOtherTest::Plugin::Bar; use strict; 1; Module-Pluggable-5.2/t/lib/MyOtherTest/Plugin/Foo.pm000644 000767 000024 00000000063 11732723031 022554 0ustar00simonstaff000000 000000 package MyOtherTest::Plugin::Foo; use strict; 1; Module-Pluggable-5.2/t/lib/MyOtherTest/Plugin/Quux/000755 000767 000024 00000000000 12560516377 022453 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/MyOtherTest/Plugin/Quux.pm000644 000767 000024 00000000064 11732723031 022774 0ustar00simonstaff000000 000000 package MyOtherTest::Plugin::Quux; use strict; 1; Module-Pluggable-5.2/t/lib/MyOtherTest/Plugin/Quux/Foo.pm000644 000767 000024 00000000071 11732723031 023515 0ustar00simonstaff000000 000000 package MyOtherTest::Plugin::Quux::Foo; use strict; 1; Module-Pluggable-5.2/t/lib/M/X.pm000644 000767 000024 00000000123 12231524057 016746 0ustar00simonstaff000000 000000 package M::X; use strict; sub new { return bless {}, $_[0]; } sub frobnitz {} 1; Module-Pluggable-5.2/t/lib/InnerTest/Plugin/000755 000767 000024 00000000000 12560516377 021175 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/InnerTest/Plugin/Foo.pm000644 000767 000024 00000000315 11732723031 022240 0ustar00simonstaff000000 000000 package InnerTest::Plugin::Foo; use strict; our $FOO = 1; package InnerTest::Plugin::Bar; use strict; sub bar {} package InnerTest::Plugin::Quux; use strict; use base qw(InnerTest::Plugin::Bar); 1; Module-Pluggable-5.2/t/lib/ExtTest/Plugin/000755 000767 000024 00000000000 12560516377 020662 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/ExtTest/Plugin/Bar.plugin000755 000767 000024 00000000062 11732723031 022572 0ustar00simonstaff000000 000000 package MyTest::Plugin::Bar; use strict; 1; Module-Pluggable-5.2/t/lib/ExtTest/Plugin/Foo.plugin000755 000767 000024 00000000062 11732723031 022611 0ustar00simonstaff000000 000000 package MyTest::Plugin::Foo; use strict; 1; Module-Pluggable-5.2/t/lib/ExtTest/Plugin/Quux/000755 000767 000024 00000000000 12560516377 021624 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/ExtTest/Plugin/Quux/Foo.plugin000755 000767 000024 00000000070 11732723031 023552 0ustar00simonstaff000000 000000 package MyTest::Plugin::Quux::Foo; use strict; 1; Module-Pluggable-5.2/t/lib/EditorJunk/Plugin/000755 000767 000024 00000000000 12560516377 021340 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/EditorJunk/Plugin/Bar.pm000644 000767 000024 00000000056 11732723031 022366 0ustar00simonstaff000000 000000 package EditorJunk::Bar; use strict; 1; Module-Pluggable-5.2/t/lib/EditorJunk/Plugin/Bar.pm.swo000644 000767 000024 00000000056 11732723031 023175 0ustar00simonstaff000000 000000 package EditorJunk::Bar; use strict; 1; Module-Pluggable-5.2/t/lib/EditorJunk/Plugin/Bar.pm.swp000644 000767 000024 00000000056 11732723031 023176 0ustar00simonstaff000000 000000 package EditorJunk::Bar; use strict; 1; Module-Pluggable-5.2/t/lib/EditorJunk/Plugin/Bar.pm~000644 000767 000024 00000000056 11732723031 022564 0ustar00simonstaff000000 000000 package EditorJunk::Bar; use strict; 1; Module-Pluggable-5.2/t/lib/EditorJunk/Plugin/Foo.pm000644 000767 000024 00000000056 11732723031 022405 0ustar00simonstaff000000 000000 package EditorJunk::Foo; use strict; 1; Module-Pluggable-5.2/t/lib/Acme/Foo-Bar.pm000644 000767 000024 00000000061 11732723031 020434 0ustar00simonstaff000000 000000 package Acme::FooBar; our $quux = "hello"; 1; Module-Pluggable-5.2/t/lib/Acme/MyTest/000755 000767 000024 00000000000 12560516377 020116 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/Acme/MyTest/Plugin/000755 000767 000024 00000000000 12560516377 021354 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/lib/Acme/MyTest/Plugin/Foo.pm000755 000767 000024 00000000070 11732723031 022420 0ustar00simonstaff000000 000000 package Acme::MyTest::Plugin::Foo; use strict; 1; Module-Pluggable-5.2/t/fp/app.pl000644 000767 000024 00000000370 12255161012 016757 0ustar00simonstaff000000 000000 #!/usr/bin/env perl use strict; use warnings; use Test::More; my @plugins = App::TestMPFP->plugins(); is_deeply([@plugins], ['App::TestMPFP::Plugin::A'], 'found expected plugins'); package App::TestMPFP; use Module::Pluggable require => 1; 1; Module-Pluggable-5.2/t/fp/lib/000755 000767 000024 00000000000 12560516377 016431 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/fp/lib/App/000755 000767 000024 00000000000 12560516377 017151 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/fp/lib/App/TestMPFP/000755 000767 000024 00000000000 12560516377 020553 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/fp/lib/App/TestMPFP/Plugin/000755 000767 000024 00000000000 12560516377 022011 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/fp/lib/App/TestMPFP/Plugin/A.pm000644 000767 000024 00000000045 12255160020 022503 0ustar00simonstaff000000 000000 package App::TestMPFP::Plugin::A; 1; Module-Pluggable-5.2/t/acme/Acme/000755 000767 000024 00000000000 12560516377 017030 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/acme/Acme/MyTest/000755 000767 000024 00000000000 12560516377 020255 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/acme/Acme/MyTest/Plugin/000755 000767 000024 00000000000 12560516377 021513 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/t/acme/Acme/MyTest/Plugin/Foo.pm000644 000767 000024 00000000070 11732723031 022554 0ustar00simonstaff000000 000000 package Acme::MyTest::Plugin::Foo; use strict; 1; Module-Pluggable-5.2/lib/Devel/000755 000767 000024 00000000000 12560516377 016620 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/lib/Module/000755 000767 000024 00000000000 12560516377 017006 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/lib/Module/Pluggable/000755 000767 000024 00000000000 12560516377 020710 5ustar00simonstaff000000 000000 Module-Pluggable-5.2/lib/Module/Pluggable.pm000755 000767 000024 00000030430 12560247660 021245 0ustar00simonstaff000000 000000 package Module::Pluggable; use strict; use vars qw($VERSION $FORCE_SEARCH_ALL_PATHS); use Module::Pluggable::Object; use if $] > 5.017, 'deprecate'; # ObQuote: # Bob Porter: Looks like you've been missing a lot of work lately. # Peter Gibbons: I wouldn't say I've been missing it, Bob! $VERSION = '5.2'; $FORCE_SEARCH_ALL_PATHS = 0; sub import { my $class = shift; my %opts = @_; my ($pkg, $file) = caller; # the default name for the method is 'plugins' my $sub = $opts{'sub_name'} || 'plugins'; # get our package my ($package) = $opts{'package'} || $pkg; $opts{filename} = $file; $opts{package} = $package; $opts{force_search_all_paths} = $FORCE_SEARCH_ALL_PATHS unless exists $opts{force_search_all_paths}; my $finder = Module::Pluggable::Object->new(%opts); my $subroutine = sub { my $self = shift; return $finder->plugins(@_) }; my $searchsub = sub { my $self = shift; my ($action,@paths) = @_; $finder->{'search_path'} = ["${package}::Plugin"] if ($action eq 'add' and not $finder->{'search_path'} ); push @{$finder->{'search_path'}}, @paths if ($action eq 'add'); $finder->{'search_path'} = \@paths if ($action eq 'new'); return $finder->{'search_path'}; }; my $onlysub = sub { my ($self, $only) = @_; if (defined $only) { $finder->{'only'} = $only; }; return $finder->{'only'}; }; my $exceptsub = sub { my ($self, $except) = @_; if (defined $except) { $finder->{'except'} = $except; }; return $finder->{'except'}; }; no strict 'refs'; no warnings qw(redefine prototype); *{"$package\::$sub"} = $subroutine; *{"$package\::search_path"} = $searchsub; *{"$package\::only"} = $onlysub; *{"$package\::except"} = $exceptsub; } 1; =pod =head1 NAME Module::Pluggable - automatically give your module the ability to have plugins =head1 SYNOPSIS Simple use Module::Pluggable - package MyClass; use Module::Pluggable; and then later ... use MyClass; my $mc = MyClass->new(); # returns the names of all plugins installed under MyClass::Plugin::* my @plugins = $mc->plugins(); =head1 EXAMPLE Why would you want to do this? Say you have something that wants to pass an object to a number of different plugins in turn. For example you may want to extract meta-data from every email you get sent and do something with it. Plugins make sense here because then you can keep adding new meta data parsers and all the logic and docs for each one will be self contained and new handlers are easy to add without changing the core code. For that, you might do something like ... package Email::Examiner; use strict; use Email::Simple; use Module::Pluggable require => 1; sub handle_email { my $self = shift; my $email = shift; foreach my $plugin ($self->plugins) { $plugin->examine($email); } return 1; } .. and all the plugins will get a chance in turn to look at it. This can be trivially extended so that plugins could save the email somewhere and then no other plugin should try and do that. Simply have it so that the C method returns C<1> if it has saved the email somewhere. You might also want to be paranoid and check to see if the plugin has an C method. foreach my $plugin ($self->plugins) { next unless $plugin->can('examine'); last if $plugin->examine($email); } And so on. The sky's the limit. =head1 DESCRIPTION Provides a simple but, hopefully, extensible way of having 'plugins' for your module. Obviously this isn't going to be the be all and end all of solutions but it works for me. Essentially all it does is export a method into your namespace that looks through a search path for .pm files and turn those into class names. Optionally it instantiates those classes for you. =head1 ADVANCED USAGE Alternatively, if you don't want to use 'plugins' as the method ... package MyClass; use Module::Pluggable sub_name => 'foo'; and then later ... my @plugins = $mc->foo(); Or if you want to look in another namespace package MyClass; use Module::Pluggable search_path => ['Acme::MyClass::Plugin', 'MyClass::Extend']; or directory use Module::Pluggable search_dirs => ['mylibs/Foo']; Or if you want to instantiate each plugin rather than just return the name package MyClass; use Module::Pluggable instantiate => 'new'; and then # whatever is passed to 'plugins' will be passed # to 'new' for each plugin my @plugins = $mc->plugins(@options); alternatively you can just require the module without instantiating it package MyClass; use Module::Pluggable require => 1; since requiring automatically searches inner packages, which may not be desirable, you can turn this off package MyClass; use Module::Pluggable require => 1, inner => 0; You can limit the plugins loaded using the except option, either as a string, array ref or regex package MyClass; use Module::Pluggable except => 'MyClass::Plugin::Foo'; or package MyClass; use Module::Pluggable except => ['MyClass::Plugin::Foo', 'MyClass::Plugin::Bar']; or package MyClass; use Module::Pluggable except => qr/^MyClass::Plugin::(Foo|Bar)$/; and similarly for only which will only load plugins which match. Remember you can use the module more than once package MyClass; use Module::Pluggable search_path => 'MyClass::Filters' sub_name => 'filters'; use Module::Pluggable search_path => 'MyClass::Plugins' sub_name => 'plugins'; and then later ... my @filters = $self->filters; my @plugins = $self->plugins; =head1 PLUGIN SEARCHING Every time you call 'plugins' the whole search path is walked again. This allows for dynamically loading plugins even at run time. However this can get expensive and so if you don't expect to want to add new plugins at run time you could do package Foo; use strict; use Module::Pluggable sub_name => '_plugins'; our @PLUGINS; sub plugins { @PLUGINS ||= shift->_plugins } 1; =head1 INNER PACKAGES If you have, for example, a file B that contains package definitions for both C and C then as long as you either have either the B or B option set then we'll also find C. Nifty! =head1 OPTIONS You can pass a hash of options when importing this module. The options can be ... =head2 sub_name The name of the subroutine to create in your namespace. By default this is 'plugins' =head2 search_path An array ref of namespaces to look in. =head2 search_dirs An array ref of directories to look in before @INC. =head2 instantiate Call this method on the class. In general this will probably be 'new' but it can be whatever you want. Whatever arguments are passed to 'plugins' will be passed to the method. The default is 'undef' i.e just return the class name. =head2 require Just require the class, don't instantiate (overrides 'instantiate'); =head2 inner If set to 0 will B search inner packages. If set to 1 will override C. =head2 only Takes a string, array ref or regex describing the names of the only plugins to return. Whilst this may seem perverse ... well, it is. But it also makes sense. Trust me. =head2 except Similar to C it takes a description of plugins to exclude from returning. This is slightly less perverse. =head2 package This is for use by extension modules which build on C: passing a C option allows you to place the plugin method in a different package other than your own. =head2 file_regex By default C only looks for I<.pm> files. By supplying a new C then you can change this behaviour e.g file_regex => qr/\.plugin$/ =head2 include_editor_junk By default C ignores files that look like they were left behind by editors. Currently this means files ending in F<~> (~), the extensions F<.swp> or F<.swo>, or files beginning with F<.#>. Setting C changes C so it does not ignore any files it finds. =head2 follow_symlinks Whether, when searching directories, to follow symlinks. Defaults to 1 i.e do follow symlinks. =head2 min_depth, max_depth This will allow you to set what 'depth' of plugin will be allowed. So, for example, C will have a depth of 3 and C will have a depth of 4 so to only get the former (i.e C) do package MyClass; use Module::Pluggable max_depth => 3; and to only get the latter (i.e C) package MyClass; use Module::Pluggable min_depth => 4; =head1 TRIGGERS Various triggers can also be passed in to the options. If any of these triggers return 0 then the plugin will not be returned. =head2 before_require Gets passed the plugin name. If 0 is returned then this plugin will not be required either. =head2 on_require_error Gets called when there's an error on requiring the plugin. Gets passed the plugin name and the error. The default on_require_error handler is to C the error and return 0. =head2 on_instantiate_error Gets called when there's an error on instantiating the plugin. Gets passed the plugin name and the error. The default on_instantiate_error handler is to C the error and return 0. =head2 after_require Gets passed the plugin name. If 0 is returned then this plugin will be required but not returned as a plugin. =head1 METHODs =head2 search_path The method C is exported into you namespace as well. You can call that at any time to change or replace the search_path. $self->search_path( add => "New::Path" ); # add $self->search_path( new => "New::Path" ); # replace =head1 BEHAVIOUR UNDER TEST ENVIRONMENT In order to make testing reliable we exclude anything not from blib if blib.pm is in %INC. However if the module being tested used another module that itself used C then the second module would fail. This was fixed by checking to see if the caller had (^|/)blib/ in their filename. There's an argument that this is the wrong behaviour and that modules should explicitly trigger this behaviour but that particular code has been around for 7 years now and I'm reluctant to change the default behaviour. You can now (as of version 4.1) force Module::Pluggable to look outside blib in a test environment by doing either require Module::Pluggable; $Module::Pluggable::FORCE_SEARCH_ALL_PATHS = 1; import Module::Pluggable; or use Module::Pluggable force_search_all_paths => 1; =head1 @INC hooks and App::FatPacker If a module's @INC has a hook and that hook is an object which has a C method then we will try and require those files too. See C for an example. This has allowed L (as of version 0.10.0) to provide support for Module::Pluggable. This should also, theoretically, allow someone to modify PAR to do the same thing. =head1 Module::Require recommended Up until version 5.2 L used a string C to require plugins. This has now been changed to optionally use L and it's C method when available and fall back to using a path based C when not. It's recommended, but not required, that you install Module::Runtime. =head1 FUTURE PLANS This does everything I need and I can't really think of any other features I want to add. Famous last words of course (not least because we're up to version 5.0 at the time of writing). However suggestions (and patches) are always welcome. =head1 DEVELOPMENT The master repo for this module is at https://github.com/simonwistow/Module-Pluggable =head1 AUTHOR Simon Wistow =head1 COPYING Copyright, 2006 Simon Wistow Distributed under the same terms as Perl itself. =head1 BUGS None known. =head1 SEE ALSO L, L, L, L, L =cut Module-Pluggable-5.2/lib/Module/Pluggable/Object.pm000755 000767 000024 00000031105 12560247660 022453 0ustar00simonstaff000000 000000 package Module::Pluggable::Object; use strict; use File::Find (); use File::Basename; use File::Spec::Functions qw(splitdir catdir curdir catfile abs2rel); use Carp qw(croak carp confess); use Devel::InnerPackage; use vars qw($VERSION $MR); use if $] > 5.017, 'deprecate'; $VERSION = '5.2'; BEGIN { eval { require Module::Runtime }; unless ($@) { Module::Runtime->import('require_module'); } else { *require_module = sub { my $module = shift; my $path = $module . ".pm"; $path =~ s{::}{/}g; require $path; }; } } sub new { my $class = shift; my %opts = @_; return bless \%opts, $class; } ### Eugggh, this code smells ### This is what happens when you keep adding patches ### *sigh* sub plugins { my $self = shift; my @args = @_; # override 'require' $self->{'require'} = 1 if $self->{'inner'}; my $filename = $self->{'filename'}; my $pkg = $self->{'package'}; # Get the exception params instantiated $self->_setup_exceptions; # automatically turn a scalar search path or namespace into a arrayref for (qw(search_path search_dirs)) { $self->{$_} = [ $self->{$_} ] if exists $self->{$_} && !ref($self->{$_}); } # default search path is '::::Plugin' $self->{'search_path'} ||= ["${pkg}::Plugin"]; # default error handler $self->{'on_require_error'} ||= sub { my ($plugin, $err) = @_; carp "Couldn't require $plugin : $err"; return 0 }; $self->{'on_instantiate_error'} ||= sub { my ($plugin, $err) = @_; carp "Couldn't instantiate $plugin: $err"; return 0 }; # default whether to follow symlinks $self->{'follow_symlinks'} = 1 unless exists $self->{'follow_symlinks'}; # check to see if we're running under test my @SEARCHDIR = exists $INC{"blib.pm"} && defined $filename && $filename =~ m!(^|/)blib/! && !$self->{'force_search_all_paths'} ? grep {/blib/} @INC : @INC; # add any search_dir params unshift @SEARCHDIR, @{$self->{'search_dirs'}} if defined $self->{'search_dirs'}; # set our @INC up to include and prefer our search_dirs if necessary my @tmp = @INC; unshift @tmp, @{$self->{'search_dirs'} || []}; local @INC = @tmp if defined $self->{'search_dirs'}; my @plugins = $self->search_directories(@SEARCHDIR); push(@plugins, $self->handle_inc_hooks($_, @SEARCHDIR)) for @{$self->{'search_path'}}; push(@plugins, $self->handle_innerpackages($_)) for @{$self->{'search_path'}}; # return blank unless we've found anything return () unless @plugins; # remove duplicates # probably not necessary but hey ho my %plugins; for(@plugins) { next unless $self->_is_legit($_); $plugins{$_} = 1; } # are we instantiating or requiring? if (defined $self->{'instantiate'}) { my $method = $self->{'instantiate'}; my @objs = (); foreach my $package (sort keys %plugins) { next unless $package->can($method); my $obj = eval { $package->$method(@_) }; $self->{'on_instantiate_error'}->($package, $@) if $@; push @objs, $obj if $obj; } return @objs; } else { # no? just return the names my @objs= sort keys %plugins; return @objs; } } sub _setup_exceptions { my $self = shift; my %only; my %except; my $only; my $except; if (defined $self->{'only'}) { if (ref($self->{'only'}) eq 'ARRAY') { %only = map { $_ => 1 } @{$self->{'only'}}; } elsif (ref($self->{'only'}) eq 'Regexp') { $only = $self->{'only'} } elsif (ref($self->{'only'}) eq '') { $only{$self->{'only'}} = 1; } } if (defined $self->{'except'}) { if (ref($self->{'except'}) eq 'ARRAY') { %except = map { $_ => 1 } @{$self->{'except'}}; } elsif (ref($self->{'except'}) eq 'Regexp') { $except = $self->{'except'} } elsif (ref($self->{'except'}) eq '') { $except{$self->{'except'}} = 1; } } $self->{_exceptions}->{only_hash} = \%only; $self->{_exceptions}->{only} = $only; $self->{_exceptions}->{except_hash} = \%except; $self->{_exceptions}->{except} = $except; } sub _is_legit { my $self = shift; my $plugin = shift; my %only = %{$self->{_exceptions}->{only_hash}||{}}; my %except = %{$self->{_exceptions}->{except_hash}||{}}; my $only = $self->{_exceptions}->{only}; my $except = $self->{_exceptions}->{except}; my $depth = () = split '::', $plugin, -1; return 0 if (keys %only && !$only{$plugin} ); return 0 unless (!defined $only || $plugin =~ m!$only! ); return 0 if (keys %except && $except{$plugin} ); return 0 if (defined $except && $plugin =~ m!$except! ); return 0 if defined $self->{max_depth} && $depth>$self->{max_depth}; return 0 if defined $self->{min_depth} && $depth<$self->{min_depth}; return 1; } sub search_directories { my $self = shift; my @SEARCHDIR = @_; my @plugins; # go through our @INC foreach my $dir (@SEARCHDIR) { push @plugins, $self->search_paths($dir); } return @plugins; } sub search_paths { my $self = shift; my $dir = shift; my @plugins; my $file_regex = $self->{'file_regex'} || qr/\.pm$/; # and each directory in our search path foreach my $searchpath (@{$self->{'search_path'}}) { # create the search directory in a cross platform goodness way my $sp = catdir($dir, (split /::/, $searchpath)); # if it doesn't exist or it's not a dir then skip it next unless ( -e $sp && -d _ ); # Use the cached stat the second time my @files = $self->find_files($sp); # foreach one we've found foreach my $file (@files) { # untaint the file; accept .pm only next unless ($file) = ($file =~ /(.*$file_regex)$/); # parse the file to get the name my ($name, $directory, $suffix) = fileparse($file, $file_regex); next if (!$self->{include_editor_junk} && $self->_is_editor_junk($name)); $directory = abs2rel($directory, $sp); # If we have a mixed-case package name, assume case has been preserved # correctly. Otherwise, root through the file to locate the case-preserved # version of the package name. my @pkg_dirs = (); if ( $name eq lc($name) || $name eq uc($name) ) { my $pkg_file = catfile($sp, $directory, "$name$suffix"); open PKGFILE, "<$pkg_file" or die "search_paths: Can't open $pkg_file: $!"; my $in_pod = 0; while ( my $line = ) { $in_pod = 1 if $line =~ m/^=\w/; $in_pod = 0 if $line =~ /^=cut/; next if ($in_pod || $line =~ /^=cut/); # skip pod text next if $line =~ /^\s*#/; # and comments if ( $line =~ m/^\s*package\s+(.*::)?($name)\s*;/i ) { @pkg_dirs = split /::/, $1 if defined $1;; $name = $2; last; } } close PKGFILE; } # then create the class name in a cross platform way $directory =~ s/^[a-z]://i if($^O =~ /MSWin32|dos/); # remove volume my @dirs = (); if ($directory) { ($directory) = ($directory =~ /(.*)/); @dirs = grep(length($_), splitdir($directory)) unless $directory eq curdir(); for my $d (reverse @dirs) { my $pkg_dir = pop @pkg_dirs; last unless defined $pkg_dir; $d =~ s/\Q$pkg_dir\E/$pkg_dir/i; # Correct case } } else { $directory = ""; } my $plugin = join '::', $searchpath, @dirs, $name; next unless $plugin =~ m!(?:[a-z\d]+)[a-z\d]*!i; $self->handle_finding_plugin($plugin, \@plugins) } # now add stuff that may have been in package # NOTE we should probably use all the stuff we've been given already # but then we can't unload it :( push @plugins, $self->handle_innerpackages($searchpath); } # foreach $searchpath return @plugins; } sub _is_editor_junk { my $self = shift; my $name = shift; # Emacs (and other Unix-y editors) leave temp files ending in a # tilde as a backup. return 1 if $name =~ /~$/; # Emacs makes these files while a buffer is edited but not yet # saved. return 1 if $name =~ /^\.#/; # Vim can leave these files behind if it crashes. return 1 if $name =~ /\.sw[po]$/; return 0; } sub handle_finding_plugin { my $self = shift; my $plugin = shift; my $plugins = shift; my $no_req = shift || 0; return unless $self->_is_legit($plugin); unless (defined $self->{'instantiate'} || $self->{'require'}) { push @$plugins, $plugin; return; } $self->{before_require}->($plugin) || return if defined $self->{before_require}; unless ($no_req) { my $tmp = $@; my $res = eval { require_module($plugin) }; my $err = $@; $@ = $tmp; if ($err) { if (defined $self->{on_require_error}) { $self->{on_require_error}->($plugin, $err) || return; } else { return; } } } $self->{after_require}->($plugin) || return if defined $self->{after_require}; push @$plugins, $plugin; } sub find_files { my $self = shift; my $search_path = shift; my $file_regex = $self->{'file_regex'} || qr/\.pm$/; # find all the .pm files in it # this isn't perfect and won't find multiple plugins per file #my $cwd = Cwd::getcwd; my @files = (); { # for the benefit of perl 5.6.1's Find, localize topic local $_; File::Find::find( { no_chdir => 1, follow => $self->{'follow_symlinks'}, wanted => sub { # Inlined from File::Find::Rule C< name => '*.pm' > return unless $File::Find::name =~ /$file_regex/; (my $path = $File::Find::name) =~ s#^\\./##; push @files, $path; } }, $search_path ); } #chdir $cwd; return @files; } sub handle_inc_hooks { my $self = shift; my $path = shift; my @SEARCHDIR = @_; my @plugins; for my $dir ( @SEARCHDIR ) { next unless ref $dir && eval { $dir->can( 'files' ) }; foreach my $plugin ( $dir->files ) { $plugin =~ s/\.pm$//; $plugin =~ s{/}{::}g; next unless $plugin =~ m!^${path}::!; $self->handle_finding_plugin( $plugin, \@plugins ); } } return @plugins; } sub handle_innerpackages { my $self = shift; return () if (exists $self->{inner} && !$self->{inner}); my $path = shift; my @plugins; foreach my $plugin (Devel::InnerPackage::list_packages($path)) { $self->handle_finding_plugin($plugin, \@plugins, 1); } return @plugins; } 1; =pod =head1 NAME Module::Pluggable::Object - automatically give your module the ability to have plugins =head1 SYNOPSIS Simple use Module::Pluggable - package MyClass; use Module::Pluggable::Object; my $finder = Module::Pluggable::Object->new(%opts); print "My plugins are: ".join(", ", $finder->plugins)."\n"; =head1 DESCRIPTION Provides a simple but, hopefully, extensible way of having 'plugins' for your module. Obviously this isn't going to be the be all and end all of solutions but it works for me. Essentially all it does is export a method into your namespace that looks through a search path for .pm files and turn those into class names. Optionally it instantiates those classes for you. This object is wrapped by C. If you want to do something odd or add non-general special features you're probably best to wrap this and produce your own subclass. =head1 OPTIONS See the C docs. =head1 AUTHOR Simon Wistow =head1 COPYING Copyright, 2006 Simon Wistow Distributed under the same terms as Perl itself. =head1 BUGS None known. =head1 SEE ALSO L =cut Module-Pluggable-5.2/lib/Devel/InnerPackage.pm000755 000767 000024 00000004661 12560247654 021516 0ustar00simonstaff000000 000000 package Devel::InnerPackage; use strict; use Exporter 5.57 'import'; use vars qw($VERSION @EXPORT_OK); use if $] > 5.017, 'deprecate'; $VERSION = '0.4'; @EXPORT_OK = qw(list_packages); =pod =head1 NAME Devel::InnerPackage - find all the inner packages of a package =head1 SYNOPSIS use Foo::Bar; use Devel::InnerPackage qw(list_packages); my @inner_packages = list_packages('Foo::Bar'); =head1 DESCRIPTION Given a file like this package Foo::Bar; sub foo {} package Foo::Bar::Quux; sub quux {} package Foo::Bar::Quirka; sub quirka {} 1; then list_packages('Foo::Bar'); will return Foo::Bar::Quux Foo::Bar::Quirka =head1 METHODS =head2 list_packages Return a list of all inner packages of that package. =cut sub list_packages { my $pack = shift; $pack .= "::" unless $pack =~ m!::$!; no strict 'refs'; my @packs; my @stuff = grep !/^(main|)::$/, keys %{$pack}; for my $cand (grep /::$/, @stuff) { $cand =~ s!::$!!; my @children = list_packages($pack.$cand); push @packs, "$pack$cand" unless $cand =~ /^::/ || !__PACKAGE__->_loaded($pack.$cand); # or @children; push @packs, @children; } return grep {$_ !~ /::(::ISA::CACHE|SUPER)/} @packs; } ### XXX this is an inlining of the Class-Inspector->loaded() ### method, but inlined to remove the dependency. sub _loaded { my ($class, $name) = @_; no strict 'refs'; # Handle by far the two most common cases # This is very fast and handles 99% of cases. return 1 if defined ${"${name}::VERSION"}; return 1 if @{"${name}::ISA"}; # Are there any symbol table entries other than other namespaces foreach ( keys %{"${name}::"} ) { next if substr($_, -2, 2) eq '::'; return 1 if defined &{"${name}::$_"}; } # No functions, and it doesn't have a version, and isn't anything. # As an absolute last resort, check for an entry in %INC my $filename = join( '/', split /(?:'|::)/, $name ) . '.pm'; return 1 if defined $INC{$filename}; ''; } =head1 AUTHOR Simon Wistow =head1 COPYING Copyright, 2005 Simon Wistow Distributed under the same terms as Perl itself. =head1 BUGS None known. =cut 1;