File Coverage

blib/lib/Method/Delegation.pm
Criterion Covered Total %
statement 68 78 87.1
branch 29 38 76.3
condition 5 8 62.5
subroutine 13 14 92.8
pod 1 1 100.0
total 116 139 83.4


line stmt bran cond sub pod time code
1             package Method::Delegation;
2              
3 2     2   152093 use 5.006;
  2         14  
4 2     2   9 use strict;
  2         3  
  2         31  
5 2     2   9 use warnings;
  2         4  
  2         52  
6 2     2   9 use Carp;
  2         3  
  2         99  
7 2     2   762 use Sub::Install;
  2         2815  
  2         7  
8 2     2   71 use base 'Exporter';
  2         5  
  2         951  
9             our @EXPORT = qw(delegate); ## no critic
10             our $VERSION = '0.02';
11              
12             sub delegate {
13 10     10 1 500 my %arg_for = @_;
14              
15 10         24 my ( $package, undef, undef ) = caller;
16             my $delegate = delete $arg_for{to}
17 10 100       227 or croak("You must supply a 'to' argument to delegate()");
18             my $methods = delete $arg_for{methods}
19 9 100       26 or croak("You must supply a 'methods' argument to delegate()");
20 8         10 my $args = delete $arg_for{args};
21 8         12 my $if_true = delete $arg_for{if_true};
22 8         10 my $else_return = delete $arg_for{else_return};
23 8         9 my $override = delete $arg_for{override};
24              
25 8 50 66     20 if ( defined $else_return && !defined $if_true ) {
26 0         0 croak(
27             "You must supply a 'if_true' argument if 'else_return' is defined"
28             );
29             }
30              
31 8 100       22 if ( 'ARRAY' eq ref $methods ) {
    100          
    100          
32 2         4 $methods = { map { $_ => $_ } @$methods };
  4         9  
33             }
34             elsif ( !ref $methods ) {
35 3         8 $methods = { $methods => $methods };
36             }
37             elsif ( 'HASH' ne ref $methods ) {
38 1         10 croak("I don't know how to delegate to '$delegate' from '$methods'");
39             }
40              
41 7 50       19 unless ( keys %$methods ) {
42 0         0 croak("You have not provideed any methods to delegate");
43             }
44 7 50       18 if ( keys %arg_for ) {
45 0         0 my $unknown = join ', ' => sort keys %arg_for;
46 0         0 croak("Unknown keys supplied to delegate(): $unknown");
47             }
48              
49 7 100 100     25 if ( ( $if_true || '' ) eq "1" ) {
50 3         4 $if_true = $delegate;
51             }
52 7         15 _assert_valid_method_name($delegate);
53 7 100       16 _assert_valid_method_name($if_true) if defined $if_true;
54              
55 7         20 while ( my ( $method, $to ) = each %$methods ) {
56 9         117 _assert_valid_method_name($method);
57 8         13 _assert_valid_method_name($to);
58              
59 8         9 my $coderef;
60 8 100       11 if ($if_true) {
61 6 50       10 if ($args) {
62             $coderef = sub {
63 0     0   0 my $self = shift;
64 0 0       0 if ( $self->$if_true ) {
65 0         0 return $self->$delegate->$to(@_);
66             }
67 0 0       0 return defined $else_return ? $else_return : ();
68 0         0 };
69             }
70             else {
71             $coderef = sub {
72 4     4   866 my $self = shift;
73 4 100       13 if ( $self->$if_true ) {
74 1         8 return $self->$delegate->$to;
75             }
76 3 100       21 return defined $else_return ? $else_return : ();
77 6         19 };
78             }
79             }
80             else {
81 2 100       5 if ($args) {
82             $coderef = sub {
83 1     1   497 my $self = shift;
84 1         4 return $self->$delegate->$to(@_);
85 1         4 };
86             }
87             else {
88             $coderef = sub {
89 1     1   521 my $self = shift;
90 1         5 return $self->$delegate->$to;
91 1         4 };
92             }
93             }
94              
95             {
96 2     2   12 no strict 'refs'; ## no critic
  2         4  
  2         463  
  8         10  
97 8 50 33     16 if ( !$override && defined *{"${package}::$method"}{CODE} ) {
  8         47  
98 0         0 croak(
99             "Package '$package' already has a method named '$method'"
100             );
101             }
102             }
103              
104 8         17 _install_delegate( $coderef, $package, $method );
105             }
106             }
107              
108             sub _install_delegate {
109 8     8   12 my ( $coderef, $package, $method ) = @_;
110              
111 8         26 Sub::Install::install_sub(
112             {
113             code => $coderef,
114             into => $package,
115             as => $method,
116             }
117             );
118             }
119              
120             sub _assert_valid_method_name {
121 28     28   33 my $name = shift;
122 28 100       75 if ( $name =~ /^[a-z_][a-z0-9_]*$/i ) {
123 27         37 return $name;
124             }
125 1         9 croak("Illegal method name: '$name'");
126             }
127              
128             1;
129              
130             __END__