File Coverage

blib/lib/AutoRole.pm
Criterion Covered Total %
statement 94 111 84.6
branch 51 66 77.2
condition 17 34 50.0
subroutine 8 8 100.0
pod n/a
total 170 219 77.6


line stmt bran cond sub pod time code
1             package AutoRole;
2              
3             =head1 NAME
4              
5             AutoRole - Compiletime OR runtime mixin of traits/roles/mixins/your-word-here.
6              
7             $Id: AutoRole.pm,v 1.8 2011-10-06 16:55:06 paul Exp $
8              
9             =cut
10              
11 1     1   1084 use strict;
  1         3  
  1         52  
12 1     1   5 use warnings;
  1         2  
  1         676  
13              
14             $AutoRole::VERSION = '0.04';
15              
16             sub import {
17 26     26   17839 my ($class, @args) = @_;
18 26         121 my ($pkg, $file, $line) = caller;
19 26         37 my ($module, $how, %list);
20              
21 26         67 while (@args) {
22 57   50     130 my $item = shift(@args) || next;
23 57 50 0     232 if ($item eq 'class') { $module = shift(@args) || die "Missing class name at $file line $line\n"; next }
  0 50       0  
  0 50       0  
24 0   0     0 elsif ($item eq 'how') { $how = shift(@args) || die "Missing how type at $file line $line\n"; next }
  0         0  
25 0 0       0 elsif ($item =~ m{methods?}x) { $args[0] = [$args[0]] if ! ref $args[0]; next }
  0         0  
26              
27 57 100       102 if (ref $item) {
28 14 100       32 if (ref $item eq 'ARRAY') { @list{ @$item } = @$item; next }
  1         4  
  1         5  
29 13 100       33 if (ref $item eq 'Regexp') { $how = 'compile'; push @{ $list{'*'} }, $item; next }
  6         7  
  6         4  
  6         16  
  6         15  
30 7         30 while (my ($k, $v) = each %$item) {
31 9 50       19 next if ! $v;
32 9 100       22 if ($k eq '*') { push @{ $list{'*'} }, ref($v) eq 'ARRAY' ? @$v : ref($v) ? $v : qr{.}x; next }
  4 100       5  
  4 100       21  
  4         17  
33 5 100 100     41 $list{$k} = (ref($v) || $v =~ /^[^\W\d]\w+$/x) ? $v : $k;
34             }
35 7         24 next;
36             }
37 43 100       139 if ($item =~ /^(?:compile|autoload|autorequire)$/x) { $how = $item }
  7 100       22  
    100          
38 2         617 elsif ($item eq '*') { push @{ $list{'*'} }, qr{.}x }
  2         31  
39 26         67 elsif (! $module) { $module = $item }
40 8         29 else { $list{$item} = $item }
41             }
42              
43 26 50       55 die "Missing class name at $file line $line\n" if ! $module;
44 26         66 (my $module_file = "$module.pm") =~ s{::}{/}xg;
45 26 100       62 if (! scalar keys %list) {
46 3 50 66     14 if (!$how || $how eq 'compile') { $list{'*'} = [qr{.}x] }
  3         15  
47 0         0 else { die "Missing list of methods to load at $file line $line\n" }
48             }
49 26   100     82 $how ||= 'autorequire';
50 1     1   17 no strict 'refs';
  1         2  
  1         194  
51              
52 26         45 my $star = delete $list{'*'};
53 26 100       58 if ($star) {
54 14         507 require $module_file;
55 13         17 for my $k (grep {defined &{"${module}::$_"}} keys %{"${module}::"}) {
  39         32  
  39         1097  
  13         54  
56 39   66     53 $list{$k} ||= $k for grep {$k =~ $_} @$star;
  45         342  
57             }
58 13 100       57 die "No methods found matching @$star for loading at $file line $line\n"
59             if ! scalar keys %list;
60             }
61              
62 24 100       63 $how = 'compile' if $INC{$module_file};
63 24 100       68 if ($how eq 'compile') {
    100          
    50          
64 15         62 require $module_file;
65             } elsif ($how eq 'autoload') {
66 1     1   5 no warnings;
  1         1  
  1         584  
67 2   50     8 my $ref = ${"${pkg}::AUTOROLE"} ||= {};
  2         47  
68 2         4 my $code = \&{"${pkg}::AUTOLOAD"};
  2         20  
69 2         10 *{"${pkg}::AUTOLOAD"} = sub {
70 2 50 50 2   4454 my $dest = ($AutoRole::AUTOLOAD || ${"${pkg}::AUTOLOAD"} || q{}) =~ /::(.+)$/x ? $1 : return;
71 2 50       10 if (exists $ref->{$dest}) {
72 2         475 require $module_file;
73 1   50     25 *{"${pkg}::$dest"} = $module->can($dest) || die "No such method as ${module}::$dest - $file line $line\n";
  1         8  
74 1         3 goto &{"${pkg}::$dest"}; # avoid inserting ourselves into the stack
  1         10  
75             }
76 0 0 0     0 if ($code ||= $pkg->SUPER::can('AUTOLOAD')) {
77 0         0 local ${"${pkg}::AUTOLOAD"} = "${pkg}::$dest";
  0         0  
78 0         0 return $code->(@_);
79             }
80 2         27 };
81             } elsif ($how ne 'autorequire') {
82 0         0 die "How type \"$how\" is invalid at $file line $line\n";
83             }
84              
85 24         59 foreach my $src (keys %list) {
86 48 100       116 foreach my $dest (ref($list{$src}) ? @{ $list{$src} } : $list{$src}) {
  2         6  
87 50 100 66     43 if (defined &{"${pkg}::$dest"}) {
  50 50       137  
  49         286  
88 1         19 die "Method name conflict - ${pkg}::$dest already exists - $file line $line\n";
89 2         11 } elsif (defined(${"${pkg}::AUTOROLE"}) && exists(${"${pkg}::AUTOROLE"}->{$dest})) {
90 0         0 die "Method name conflict -- ${pkg}::$dest is already set to autoload - $file line $line\n";
91             }
92              
93 49 100       95 if ($how eq 'compile') {
    100          
94 36         29 *{"${pkg}::$dest"} = *{"${module}::$src"}{'CODE'};
  36         138  
  36         82  
95             } elsif ($how eq 'autoload') {
96 2         3 ${"${pkg}::AUTOROLE"}->{$dest} = $src;
  2         14  
97             } else {
98 11         55 *{"${pkg}::$dest"} = sub {
99 1     1   1263 require $module_file;
100 1     1   7 no warnings;
  1         2  
  1         251  
101 0   0     0 *{"${pkg}::$dest"} = $module->can($src) || die "No such method as ${module}::$src - $file line $line\n";
  0         0  
102 0         0 goto &{"${pkg}::$dest"}; # avoid inserting ourselves into the stack
  0         0  
103 11         80 };
104             }
105             }
106             }
107 23 50 66     812 return ($star && wantarray) ? [sort keys %list] : 1;
108             }
109              
110             1;
111              
112             __END__