File Coverage

lib/Class/Roles.pm
Criterion Covered Total %
statement 64 64 100.0
branch 14 16 87.5
condition 3 8 37.5
subroutine 14 14 100.0
pod 0 7 0.0
total 95 109 87.1


line stmt bran cond sub pod time code
1             package Class::Roles;
2              
3 4     4   67028 use strict;
  4         84  
  4         247  
4 4     4   26 use Scalar::Util 'blessed';
  4         8  
  4         660  
5              
6 4     4   32 use vars '$VERSION';
  4         13  
  4         2492  
7             $VERSION = '0.30';
8              
9             my %actions =
10             (
11             role => \&role,
12             does => \&does,
13             multi => \&multi,
14             apply => \&apply,
15             );
16              
17             my (%roles, %does);
18              
19             sub import
20             {
21 17     17   8289 my $caller = caller();
22 17         138 my $self = shift;
23              
24 17 100       69 if ( @_ % 2 != 0 )
25             {
26 1         8 require Carp;
27 1         28 Carp::croak( 'Improper argument list' );
28             }
29              
30 16         116 while (my ($name, $value) = splice( @_, 0, 2 ))
31             {
32 12 100       55 unless (exists $actions{ $name })
33             {
34 1         8 require Carp;
35 1         15 Carp::croak( "Unknown action '$name'" );
36             }
37 11         45 $actions{ $name }->( $caller, $value );
38             }
39             }
40              
41             sub role
42             {
43 4     4 0 6 my ($caller, $role) = @_;
44 4 100       17 $role = [ $role ] unless ref $role eq 'ARRAY';
45 4   50     25 $roles{ $caller } ||= [];
46              
47 4         16 install_methods( $caller, $caller, @$role );
48             }
49              
50             sub multi
51             {
52 1     1 0 3 my ($caller, $multi) = @_;
53              
54 1         5 while (my ($role, $methods) = each %$multi)
55             {
56 2 50       9 $methods = [ $methods ] unless ref $methods eq 'ARRAY';
57 2         6 install_methods( $caller, $role, @$methods );
58             }
59             }
60              
61             sub apply
62             {
63 1     1 0 4 my ($caller, $args) = @_;
64 1         4 my ($role, $to) = @$args{ qw( role to ) };
65 1         4 does( $to, $role );
66             }
67              
68             sub does
69             {
70 6     6 0 13 my ($caller, $role) = @_;
71              
72 4     4   26 no strict 'refs';
  4         10  
  4         719  
73 6         11 for my $method (@{ $roles{ $role } })
  6         27  
74             {
75 9         21 my ($name, $code) = @$method;
76 9         38 my $export_name = $caller . '::' . $name;
77 9 100       12 *{ $export_name } = $code unless defined &{ $export_name };
  8         41  
  9         1005  
78             }
79              
80 6         212 $does{ $caller }{ $role } = 1;
81             }
82              
83             sub install_methods
84             {
85 6     6 0 14 my ($source, $role, @methods) = @_;
86              
87 4     4   29 no strict 'refs';
  4         9  
  4         895  
88              
89 6         11 for my $method (@methods)
90             {
91 9         18 push @{ $roles{ $role } },
  9         4694  
92 9         12 [ $method, \&{ $source . '::' . $method } ];
93             }
94             }
95              
96             sub universal_does
97             {
98 13     13 0 4051 my ($invocant, $role) = @_;
99 13   33     238 my $class = blessed $invocant || $invocant;
100              
101 13 100       188 return 1 if $class eq $role;
102 12 100       222 return 1 if exists $does{ $class }{ $role };
103              
104 6         17 return check_isa( $class, $role );
105             }
106              
107             sub check_isa
108             {
109 6     6 0 11 my ($class, $role) = @_;
110              
111 4     4   24 no strict 'refs';
  4         6  
  4         756  
112              
113 6         8 my @isa = @{ $class . '::ISA' };
  6         31  
114 6         14 for my $parent (@isa)
115             {
116 1 50 33     7 return 1 if $parent->does( $role ) or check_isa( $parent, $role );
117             }
118              
119 5         25 return;
120             }
121              
122             *UNIVERSAL::does = \&universal_does;
123              
124             1;
125             __END__