File Coverage

blib/lib/Package/Pkg.pm
Criterion Covered Total %
statement 127 147 86.3
branch 55 84 65.4
condition 8 14 57.1
subroutine 21 23 91.3
pod 2 12 16.6
total 213 280 76.0


line stmt bran cond sub pod time code
1             package Package::Pkg;
2             {
3             $Package::Pkg::VERSION = '0.0020';
4             }
5             # ABSTRACT: Handy package munging utilities
6              
7              
8 6     6   531293 use strict;
  6         14  
  6         225  
9 6     6   34 use warnings;
  6         13  
  6         183  
10              
11 6     6   6191 use Class::Load ':all';
  6         248378  
  6         1084  
12             require Sub::Install;
13 6     6   57 use Try::Tiny;
  6         12  
  6         310  
14 6     6   35 use Carp;
  6         10  
  6         616  
15              
16             our $pkg = __PACKAGE__;
17 51     51 0 2193 sub pkg { $pkg }
18             __PACKAGE__->export( pkg => \&pkg );
19              
20             {
21 6     6   30 no warnings 'once';
  6         10  
  6         11915  
22             *package = \&name;
23             }
24              
25             sub name {
26 29     29 1 50 my $self = shift;
27 29 100       48 my $package = join '::', map { ref $_ ? ref $_ : $_ } @_;
  68         213  
28 29         179 $package =~ s/:{2,}/::/g;
29 29 100       84 return '' if $package eq '::';
30 27 100       73 if ( $package =~ m/^::/ ) {
31 6         26 my $caller = caller;
32 6         93 $package = "$caller$package";
33             }
34 27         111 return $package;
35             }
36              
37             sub load_name {
38 0     0 0 0 my $self = shift;
39 0         0 my $package = $self->name( @_ );
40 0         0 $self->load( $package );
41 0         0 return $package;
42             }
43              
44 4     4   46 sub _is_package_loaded ($) { return is_class_loaded( $_[0] ) }
45              
46             sub _package2pm ($) {
47 1     1   2 my $package = shift;
48 1         3 my $pm = $package . '.pm';
49 1         6 $pm =~ s{::}{/}g;
50 1         4 return $pm;
51             }
52              
53             sub lexicon {
54 2     2 0 4 my $self = shift;
55 2         18 require Package::Pkg::Lexicon;
56 2         15 my $lexicon = Package::Pkg::Lexicon->new;
57 2 100       15 $lexicon->add( @_ ) if @_;
58 2         9 return $lexicon;
59             }
60              
61             sub loader {
62 1     1 0 13 my $self = shift;
63 1         690 require Package::Pkg::Loader;
64 1 50       12 my $namespacelist = ref $_[0] eq 'ARRAY' ? shift : [ splice @_, 0, @_ ];
65 1         15 Package::Pkg::Loader->new( namespacelist => $namespacelist, @_ );
66             }
67              
68             sub load {
69 0     0 0 0 my $self = shift;
70 0 0       0 my $package = @_ > 1 ? $self->name( @_ ) : $_[0];
71 0         0 return Mouse::Util::load_class( $package );
72             }
73              
74             sub softload {
75 4     4 0 6 my $self = shift;
76 4 50       19 my $package = @_ > 1 ? $self->name( @_ ) : $_[0];
77            
78 4 100       9 return $package if _is_package_loaded( $package );
79              
80 1         4 my $pm = _package2pm $package;
81              
82             return $package if try {
83 1     1   102 local $SIG{__DIE__};
84 1         499 require $pm;
85 0         0 return 1;
86             }
87             catch {
88 1 50   1   48 unless (/^Can't locate \Q$pm\E in \@INC/) {
89 0         0 confess "Couldn't load package ($package) because: $_";
90             }
91 1         23 return;
92 1 50       15 };
93             }
94              
95             # pkg->install( name => sub { ... } =>
96             sub install {
97 41     41 1 61 my $self = shift;
98 41         46 my %install;
99 41 50       324 if ( @_ == 1 ) { %install = %{ $_[0] } }
  0 100       0  
  0 100       0  
100             elsif ( @_ == 2 ) {
101 9 100 66     58 if ( $_[1] && $_[1] =~ m/::$/ ) { @install{qw/ code into /} = @_ }
  4         16  
102 5         19 else { @install{qw/ code as /} = @_ }
103             }
104 5         22 elsif ( @_ == 3 ) { @install{qw/ code into as /} = @_ }
105 27         93 else { %install = @_ }
106              
107 41         110 my ( $from, $code, $into, $_into, $as, ) = @install{qw/ from code into _into as /};
108 41         91 undef %install;
109              
110 41 50       118 die "Missing code (@_)" unless defined $code;
111              
112 41 100       87 if ( ref $code eq 'CODE' ) {
113 25 50       58 die "Invalid (superfluous) from ($from) with code reference (@_)" if defined $from;
114             }
115             else {
116 16 100       50 if ( defined $from )
    100          
117 4 50       11 { die "Invalid code ($code) with from ($from)" if $code =~ m/::/ }
118             elsif ( $code =~ m/::/) {
119 9         11 $code =~ s/^<//; # Silently allow <Package::subroutine
120 9         22 ( $from, $code ) = $self->split2( $code );
121             }
122 3         10 else { $from = caller }
123             }
124              
125 41 100 100     285 if ( defined $as && $as =~ m/::/) {
    50          
    0          
126 17 50       33 die "Invalid as ($as) with into ($into)" if defined $into;
127 17         50 ( $into, $as ) = $self->split2( $as );
128             }
129             elsif ( defined $into ) {
130 24 100       79 if ( $into =~ s/::$// ) { }
131             }
132             elsif ( defined $_into ) {
133 0         0 $into = $_into;
134             }
135              
136 41 100       100 if ( defined $as ) {}
    100          
137 5         5 elsif ( ! ref $code ) { $as = $code }
138 2         27 else { die "Missing as (@_)" }
139              
140 39 50       79 die "Missing into (@_)" unless defined $into;
141              
142 39         121 @install{qw/ code into as /} = ( $code, $into, $as );
143 39 100       83 $install{from} = $from if defined $from;
144 39         129 Sub::Install::install_sub( \%install );
145             }
146              
147             sub split {
148 26     26 0 29 my $self = shift;
149 26         29 my $target = shift;
150 26 50 33     129 return unless defined $target && length $target;
151 26         136 return split m/::/, $target;
152             }
153              
154             sub split2 {
155 26     26 0 32 my $self = shift;
156 26 50       52 return unless my @split = $self->split( @_ );
157 26 50       81 return $split[0] if 1 == @split;
158 26         45 my $name = pop @split;
159 26         106 return( join( '::', @split ), $name );
160             }
161              
162             sub export {
163 7     7 0 15 my $self = shift;
164 7         34 my $exporter = $self->exporter( @_ );
165              
166 7         37 my $package = caller;
167 7         160 $self->install( code => $exporter, as => "${package}::import" );
168             }
169              
170             sub exporter {
171 7     7 0 14 my $self = shift;
172 7         12 my ( %index, %group, $default_export );
173 7         92 %group = ( default => [], optional => [], all => [] );
174 7         16 $default_export = 1;
175              
176 7         33 while ( @_ ) {
177 7         15 local $_ = shift;
178 7         12 my ( $group, @install );
179 7 50       69 if ( $_ eq '-' ) { undef $default_export }
  0 50       0  
    50          
    50          
    50          
180 0         0 elsif ( $_ eq '+' ) { $default_export = 1 }
181 0         0 elsif ( s/^\+// ) { $group = 'default' }
182 0         0 elsif ( s/^\-// ) { $group = 'optional' }
183 7         13 elsif ( $default_export ) { $group = 'default' }
184 0         0 else { $group = 'optional' }
185              
186 7         13 my $name = $_;
187              
188 7         12 push @install, $name;
189 7 50       25 if ( @_ ) {
190 7         13 my $value = shift;
191 7 50       1466 if ( ref $value eq 'CODE' ) { push @install, $value }
  7 0       26  
192 0         0 elsif ( $value =~ s/^<// ) { push @install, $value }
193 0         0 else { unshift @_, $value }
194             }
195              
196 7   50     9 push @{ $group{$group} ||= [] }, $name;
  7         42  
197 7         43 $index{$name} = \@install;
198             }
199 7         20 $group{all} = [ map { @$_ } @group{qw/ default optional /} ];
  14         37  
200              
201             my $exporter = sub {
202 10     10   4094 my ( $class ) = @_;
203              
204 10         30 my $package = caller;
205 10         167 my @arguments = splice @_, 1;
206            
207 10         14 my @exporting;
208 10 50       30 if ( ! @arguments ) {
209 10         15 push @exporting, @{ $group{default} };
  10         28  
210             }
211             else {
212 0         0 @exporting = @arguments;
213             }
214              
215 10         23 for my $name ( @exporting ) {
216 10 50       35 my $install = $index{$name} or die "Unrecognized export ($name)";
217 10         20 my $as = $install->[0];
218 10   33     33 my $code = $install->[1] || "${class}::$as";
219 10         34 __PACKAGE__->install( as => $as, code => $code, into => $package );
220             }
221 7         39 };
222              
223 7         21 return $exporter;
224             }
225              
226             1;
227              
228             __END__
229             =pod
230              
231             =head1 NAME
232              
233             Package::Pkg - Handy package munging utilities
234              
235             =head1 VERSION
236              
237             version 0.0020
238              
239             =head1 SYNOPSIS
240              
241             First, import a new keyword: C<pkg>
242              
243             use Package::Pkg;
244              
245             Package name formation:
246              
247             pkg->name( 'Xy', 'A' ) # Xy::A
248             pkg->name( $object, qw/ Cfg / ); # (ref $object)::Cfg
249              
250             Subroutine installation:
251              
252             pkg->install( sub { ... } => 'MyPackage::myfunction' );
253              
254             # myfunction in MyPackage is now useable
255             MyPackage->myfunction( ... );
256              
257             Subroutine exporting:
258              
259             package MyPackage;
260              
261             use Package::Pkg;
262              
263             sub this { ... }
264              
265             # Setup an exporter (literally sub import { ... }) for
266             # MyPackage, exporting 'this' and 'that'
267             pkg->export( that => sub { ... }, 'this' );
268              
269             package main;
270              
271             use MyPackage;
272              
273             this( ... );
274              
275             that( ... );
276              
277             =head1 DESCRIPTION
278              
279             Package::Pkg is a collection of useful, miscellaneous package-munging utilities. Functionality is accessed via the imported C<pkg> keyword, although you can also invoke functions directly from the package (C<Package::Pkg>)
280              
281             =head1 USAGE
282              
283             =head2 pkg->install( ... )
284              
285             Install a subroutine, similar to L<Sub::Install>
286              
287             This method takes a number of parameters and also has a two- and three-argument form (see below)
288              
289             # Install an anonymous subroutine as Banana::magic
290             pkg->install( code => sub { ... } , as => 'Banana::magic' )
291             pkg->install( code => sub { ... } , into => 'Banana::magic' ) # Bzzzt! Throws an error!
292              
293             # Install the subroutine Apple::xyzzy as Banana::magic
294             pkg->install( code => 'Apple::xyzzy', as => 'Banana::magic' )
295             pkg->install( code => 'Apple::xyzzy', into => 'Banana', as => 'magic' )
296             pkg->install( from => 'Apple', code => 'xyzzy', as => 'Banana::magic' )
297             pkg->install( from => 'Apple', code => 'xyzzy', into => 'Banana', as => 'magic' )
298              
299             # Install the subroutine Apple::xyzzy as Banana::xyzzy
300             pkg->install( code => 'Apple::xyzzy', as => 'Banana::xyzzy' )
301             pkg->install( code => 'Apple::xyzzy', into => 'Banana' )
302             pkg->install( from => 'Apple', code => 'xyzzy', as => 'Banana::xyzzy' )
303             pkg->install( from => 'Apple', code => 'xyzzy', into => 'Banana' )
304              
305             With implicit C<from> (via C<caller()>)
306              
307             package Apple;
308              
309             sub xyzzy { ... }
310              
311             # Install the subroutine Apple::xyzzy as Banana::xyzzy
312             pkg->install( code => 'xyzzy', as => 'Banana::xyzzy' ) # 'from' is implicitly 'Apple'
313             pkg->install( code => \&xyzzy, as => 'Banana::xyzzy' )
314              
315             Acceptable parameters are:
316              
317             code A subroutine reference,
318             A package-with-name identifier, or
319             The name of a subroutine in the calling package
320              
321             from (optional) A package identifier
322             If :code is an identifier, then :from is the package where
323             the subroutine can be found
324             If :code is an identifier and :from is not given, then :from
325             is assumed to be the calling package (via caller())
326              
327             as The name of the subroutine to install as. Can be a simple name
328             (when paired with :into) or a full package-with-name
329              
330             into (optional) A package identifier
331             If :as is given, then the full name of the installed
332             subroutine is (:into)::(:as)
333              
334             If :as is not given and we can derive a simple name from
335             :code (It is a package-with-name identifier), then :as will be
336             the name identifier part of :code
337              
338             =head2 pkg->install( $code => $as )
339              
340             This is the two-argument form of subroutine installation
341              
342             Install $code subroutine as $as
343              
344             pkg->install( sub { ... } => 'Banana::xyzzy' )
345              
346             pkg->install( 'Scalar::Util::blessed' => 'Banana::xyzzy' )
347              
348             pkg->install( 'Scalar::Util::blessed' => 'Banana::' )
349              
350             pkg->install( sub { ... } => 'Banana::' ) # Bzzzt! Throws an error!
351              
352             $code should be:
353              
354             =over
355              
356             =item * A CODE reference
357              
358             sub { ... }
359              
360             =item * A package-with-name identifier
361              
362             Scalar::Util::blessed
363              
364             =item * The name of a subroutine in the calling package
365              
366             sub xyzzy { ... }
367              
368             pkg->install( 'xyzzy' => ... )
369              
370             =back
371              
372             $as should be:
373              
374             =over
375              
376             =item * A package-with-name identifier
377              
378             Acme::Xyzzy::magic
379              
380             =item * A package identifier (with a trailing ::)
381              
382             Acme::Xyzzy::
383              
384             =back
385              
386             =head2 pkg->install( $code => $into, $as )
387              
388             This is the three-argument form of subroutine installation
389              
390             pkg->install( sub { ... } => 'Banana', 'xyzzy' )
391              
392             pkg->install( sub { ... } => 'Banana::', 'xyzzy' )
393              
394             pkg->install( 'Scalar::Util::blessed' => 'Banana', 'xyzzy' )
395              
396             pkg->install( 'Scalar::Util::blessed' => 'Banana::', 'xyzzy' )
397              
398             $code can be the same as the two argument form
399              
400             $into should be:
401              
402             =over
403              
404             =item * A package identifier (trailing :: is optional)
405              
406             Acme::Xyzzy::
407              
408             Acme::Xyzzy
409              
410             =back
411              
412             $as should be:
413              
414             =over
415              
416             =item * A name (the name of the subroutine)
417              
418             xyzzy
419              
420             magic
421              
422             =back
423              
424             =head2 $package = pkg->name( $part, [ $part, ..., $part ] )
425              
426             Return a namespace composed by joining each $part with C<::>
427              
428             Superfluous/redundant C<::> are automatically cleaned up and stripped from the resulting $package
429              
430             If the first part leads with a C<::>, the the calling package will be prepended to $package
431              
432             pkg->name( 'Xy', 'A::', '::B' ) # Xy::A::B
433             pkg->name( 'Xy', 'A::' ) # Xy::A::
434            
435             {
436             package Zy;
437              
438             pkg->name( '::', 'A::', '::B' ) # Zy::A::B
439             pkg->name( '::Xy::A::B' ) # Zy::Xy::A::B
440             }
441              
442             In addition, if any part is blessed, C<name> will resolve that part to the package that the part makes reference to:
443              
444             my $object = bless {}, 'Xyzzy';
445             pkg->name( $object, qw/ Cfg / ); # Xyzzy::Cfg
446              
447             =head1 SEE ALSO
448              
449             L<Sub::Install>
450              
451             L<Sub::Exporter>
452              
453             =head1 AUTHOR
454              
455             Robert Krimen <robertkrimen@gmail.com>
456              
457             =head1 COPYRIGHT AND LICENSE
458              
459             This software is copyright (c) 2012 by Robert Krimen.
460              
461             This is free software; you can redistribute it and/or modify it under
462             the same terms as the Perl 5 programming language system itself.
463              
464             =cut
465