[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/se3-unattended/var/se3/unattended/install/linuxaux/opt/perl/lib/5.10.0/Module/ -> Pluggable.pm (source)

   1  package Module::Pluggable;
   2  
   3  use strict;
   4  use vars qw($VERSION);
   5  use Module::Pluggable::Object;
   6  
   7  # ObQuote:
   8  # Bob Porter: Looks like you've been missing a lot of work lately. 
   9  # Peter Gibbons: I wouldn't say I've been missing it, Bob! 
  10  
  11  
  12  $VERSION = '3.6';
  13  
  14  sub import {
  15      my $class        = shift;
  16      my %opts         = @_;
  17  
  18      my ($pkg, $file) = caller; 
  19      # the default name for the method is 'plugins'
  20      my $sub          = $opts{'sub_name'}  || 'plugins';
  21      # get our package 
  22      my ($package)    = $opts{'package'} || $pkg;
  23      $opts{filename}  = $file;
  24      $opts{package}   = $package;
  25  
  26  
  27      my $finder       = Module::Pluggable::Object->new(%opts);
  28      my $subroutine   = sub { my $self = shift; return $finder->plugins(@_) };
  29  
  30      my $searchsub = sub {
  31                my $self = shift;
  32                my ($action,@paths) = @_;
  33  
  34                $finder->{'search_path'} = ["$package}::Plugin"] if ($action eq 'add'  and not   $finder->{'search_path'} );
  35                push @{$finder->{'search_path'}}, @paths      if ($action eq 'add');
  36                $finder->{'search_path'}       = \@paths      if ($action eq 'new');
  37                return $finder->{'search_path'};
  38      };
  39  
  40  
  41      my $onlysub = sub {
  42          my ($self, $only) = @_;
  43  
  44          if (defined $only) {
  45              $finder->{'only'} = $only;
  46          };
  47          
  48          return $finder->{'only'};
  49      };
  50  
  51      my $exceptsub = sub {
  52          my ($self, $except) = @_;
  53  
  54          if (defined $except) {
  55              $finder->{'except'} = $except;
  56          };
  57          
  58          return $finder->{'except'};
  59      };
  60  
  61  
  62      no strict 'refs';
  63      no warnings 'redefine';
  64      *{"$package\::$sub"}    = $subroutine;
  65      *{"$package\::search_path"} = $searchsub;
  66      *{"$package\::only"}        = $onlysub;
  67      *{"$package\::except"}      = $exceptsub;
  68  
  69  }
  70  
  71  1;
  72  
  73  =pod
  74  
  75  =head1 NAME
  76  
  77  Module::Pluggable - automatically give your module the ability to have plugins
  78  
  79  =head1 SYNOPSIS
  80  
  81  
  82  Simple use Module::Pluggable -
  83  
  84      package MyClass;
  85      use Module::Pluggable;
  86      
  87  
  88  and then later ...
  89  
  90      use MyClass;
  91      my $mc = MyClass->new();
  92      # returns the names of all plugins installed under MyClass::Plugin::*
  93      my @plugins = $mc->plugins(); 
  94  
  95  =head1 EXAMPLE
  96  
  97  Why would you want to do this? Say you have something that wants to pass an
  98  object to a number of different plugins in turn. For example you may 
  99  want to extract meta-data from every email you get sent and do something
 100  with it. Plugins make sense here because then you can keep adding new 
 101  meta data parsers and all the logic and docs for each one will be 
 102  self contained and new handlers are easy to add without changing the 
 103  core code. For that, you might do something like ...
 104  
 105      package Email::Examiner;
 106  
 107      use strict;
 108      use Email::Simple;
 109      use Module::Pluggable require => 1;
 110  
 111      sub handle_email {
 112          my $self  = shift;
 113          my $email = shift;
 114  
 115          foreach my $plugin ($self->plugins) {
 116              $plugin->examine($email);
 117          }
 118  
 119          return 1;
 120      }
 121  
 122  
 123  
 124  .. and all the plugins will get a chance in turn to look at it.
 125  
 126  This can be trivally extended so that plugins could save the email
 127  somewhere and then no other plugin should try and do that. 
 128  Simply have it so that the C<examine> method returns C<1> if 
 129  it has saved the email somewhere. You might also wnat to be paranoid
 130  and check to see if the plugin has an C<examine> method.
 131  
 132          foreach my $plugin ($self->plugins) {
 133              next unless $plugin->can('examine');
 134              last if     $plugin->examine($email);
 135          }
 136  
 137  
 138  And so on. The sky's the limit.
 139  
 140  
 141  =head1 DESCRIPTION
 142  
 143  Provides a simple but, hopefully, extensible way of having 'plugins' for 
 144  your module. Obviously this isn't going to be the be all and end all of
 145  solutions but it works for me.
 146  
 147  Essentially all it does is export a method into your namespace that 
 148  looks through a search path for .pm files and turn those into class names. 
 149  
 150  Optionally it instantiates those classes for you.
 151  
 152  =head1 ADVANCED USAGE
 153  
 154      
 155  Alternatively, if you don't want to use 'plugins' as the method ...
 156      
 157      package MyClass;
 158      use Module::Pluggable sub_name => 'foo';
 159  
 160  
 161  and then later ...
 162  
 163      my @plugins = $mc->foo();
 164  
 165  
 166  Or if you want to look in another namespace
 167  
 168      package MyClass;
 169      use Module::Pluggable search_path => ['Acme::MyClass::Plugin', 'MyClass::Extend'];
 170  
 171  or directory 
 172  
 173      use Module::Pluggable search_dirs => ['mylibs/Foo'];
 174  
 175  
 176  Or if you want to instantiate each plugin rather than just return the name
 177  
 178      package MyClass;
 179      use Module::Pluggable instantiate => 'new';
 180  
 181  and then
 182  
 183      # whatever is passed to 'plugins' will be passed 
 184      # to 'new' for each plugin 
 185      my @plugins = $mc->plugins(@options); 
 186  
 187  
 188  alternatively you can just require the module without instantiating it
 189  
 190      package MyClass;
 191      use Module::Pluggable require => 1;
 192  
 193  since requiring automatically searches inner packages, which may not be desirable, you can turn this off
 194  
 195  
 196      package MyClass;
 197      use Module::Pluggable require => 1, inner => 0;
 198  
 199  
 200  You can limit the plugins loaded using the except option, either as a string,
 201  array ref or regex
 202  
 203      package MyClass;
 204      use Module::Pluggable except => 'MyClass::Plugin::Foo';
 205  
 206  or
 207  
 208      package MyClass;
 209      use Module::Pluggable except => ['MyClass::Plugin::Foo', 'MyClass::Plugin::Bar'];
 210  
 211  or
 212  
 213      package MyClass;
 214      use Module::Pluggable except => qr/^MyClass::Plugin::(Foo|Bar)$/;
 215  
 216  
 217  and similarly for only which will only load plugins which match.
 218  
 219  Remember you can use the module more than once
 220  
 221      package MyClass;
 222      use Module::Pluggable search_path => 'MyClass::Filters' sub_name => 'filters';
 223      use Module::Pluggable search_path => 'MyClass::Plugins' sub_name => 'plugins';
 224  
 225  and then later ...
 226  
 227      my @filters = $self->filters;
 228      my @plugins = $self->plugins;
 229  
 230  =head1 INNER PACKAGES
 231  
 232  If you have, for example, a file B<lib/Something/Plugin/Foo.pm> that
 233  contains package definitions for both C<Something::Plugin::Foo> and 
 234  C<Something::Plugin::Bar> then as long as you either have either 
 235  the B<require> or B<instantiate> option set then we'll also find 
 236  C<Something::Plugin::Bar>. Nifty!
 237  
 238  =head1 OPTIONS
 239  
 240  You can pass a hash of options when importing this module.
 241  
 242  The options can be ...
 243  
 244  =head2 sub_name
 245  
 246  The name of the subroutine to create in your namespace. 
 247  
 248  By default this is 'plugins'
 249  
 250  =head2 search_path
 251  
 252  An array ref of namespaces to look in. 
 253  
 254  =head2 search_dirs 
 255  
 256  An array ref of directorys to look in before @INC.
 257  
 258  =head2 instantiate
 259  
 260  Call this method on the class. In general this will probably be 'new'
 261  but it can be whatever you want. Whatever arguments are passed to 'plugins' 
 262  will be passed to the method.
 263  
 264  The default is 'undef' i.e just return the class name.
 265  
 266  =head2 require
 267  
 268  Just require the class, don't instantiate (overrides 'instantiate');
 269  
 270  =head2 inner
 271  
 272  If set to 0 will B<not> search inner packages. 
 273  If set to 1 will override C<require>.
 274  
 275  =head2 only
 276  
 277  Takes a string, array ref or regex describing the names of the only plugins to 
 278  return. Whilst this may seem perverse ... well, it is. But it also 
 279  makes sense. Trust me.
 280  
 281  =head2 except
 282  
 283  Similar to C<only> it takes a description of plugins to exclude 
 284  from returning. This is slightly less perverse.
 285  
 286  =head2 package
 287  
 288  This is for use by extension modules which build on C<Module::Pluggable>:
 289  passing a C<package> option allows you to place the plugin method in a
 290  different package other than your own.
 291  
 292  =head2 file_regex
 293  
 294  By default C<Module::Pluggable> only looks for I<.pm> files.
 295  
 296  By supplying a new C<file_regex> then you can change this behaviour e.g
 297  
 298      file_regex => qr/\.plugin$/
 299  
 300  
 301  
 302  =head1 METHODs
 303  
 304  =head2 search_path
 305  
 306  The method C<search_path> is exported into you namespace as well. 
 307  You can call that at any time to change or replace the 
 308  search_path.
 309  
 310      $self->search_path( add => "New::Path" ); # add
 311      $self->search_path( new => "New::Path" ); # replace
 312  
 313  
 314  
 315  =head1 FUTURE PLANS
 316  
 317  This does everything I need and I can't really think of any other 
 318  features I want to add. Famous last words of course
 319  
 320  Recently tried fixed to find inner packages and to make it 
 321  'just work' with PAR but there are still some issues.
 322  
 323  
 324  However suggestions (and patches) are welcome.
 325  
 326  =head1 AUTHOR
 327  
 328  Simon Wistow <simon@thegestalt.org>
 329  
 330  =head1 COPYING
 331  
 332  Copyright, 2006 Simon Wistow
 333  
 334  Distributed under the same terms as Perl itself.
 335  
 336  =head1 BUGS
 337  
 338  None known.
 339  
 340  =head1 SEE ALSO
 341  
 342  L<File::Spec>, L<File::Find>, L<File::Basename>, L<Class::Factory::Util>, L<Module::Pluggable::Ordered>
 343  
 344  =cut 
 345  
 346  


Generated: Tue Mar 17 22:47:18 2015 Cross-referenced by PHPXref 0.7.1