File Coverage

blib/lib/MooX/Role/Parameterized.pm
Criterion Covered Total %
statement 89 95 93.6
branch 27 34 79.4
condition 14 21 66.6
subroutine 17 18 94.4
pod 5 6 83.3
total 152 174 87.3


line stmt bran cond sub pod time code
1             package MooX::Role::Parameterized;
2 15     15   1443916 use v5.12;
  15         61  
3 15     15   114 use strict;
  15         32  
  15         501  
4 15     15   87 use warnings;
  15         42  
  15         1447  
5              
6             our $VERSION = '0.701'; # VERSION
7              
8             # ABSTRACT: roles with composition parameters
9              
10 15     15   8740 use Module::Runtime qw(use_module);
  15         31936  
  15         119  
11 15     15   1114 use Carp qw(carp croak);
  15         32  
  15         1066  
12 15     15   106 use Exporter qw(import);
  15         26  
  15         483  
13 15     15   5096 use Moo::Role qw();
  15         133727  
  15         445  
14 15     15   8426 use MooX::BuildClass;
  15         186207  
  15         121  
15 15     15   10760 use MooX::Role::Parameterized::Mop;
  15         53  
  15         25010  
16              
17             our @EXPORT = qw(parameter role apply apply_roles_to_target);
18              
19             our $VERBOSE = 0;
20              
21             our %INFO;
22              
23             sub apply {
24 0 0   0 1 0 carp "apply method is deprecated, please use 'apply_roles_to_target'"
25             if $VERBOSE;
26              
27 0         0 goto &apply_roles_to_target;
28             }
29              
30             sub apply_roles_to_target {
31 26     26 1 1017107 my ( $role, $args, %extra ) = @_;
32              
33 26 50       134 croak
34             "unable to apply parameterized role: not an MooX::Role::Parameterized"
35             if !__PACKAGE__->is_role($role);
36              
37 26 100       128 $args = [$args] if ref($args) ne ref( [] );
38              
39 26 100       172 my $target = defined( $extra{target} ) ? $extra{target} : (caller)[0];
40              
41 26 100 66     410 if ( exists $INFO{$role}
      66        
42             && exists $INFO{$role}{code_for}
43             && ref $INFO{$role}{code_for} eq "CODE" )
44             {
45 25         220 my $mop = MooX::Role::Parameterized::Mop->new(
46             target => $target,
47             role => $role
48             );
49              
50 25         92 my $parameter_definition_klass =
51             _fetch_parameter_definition_klass($role);
52              
53 25         49 foreach my $params ( @{$args} ) {
  25         68  
54 27 100       86 if ( defined $parameter_definition_klass ) {
55 5         6 eval { $params = $parameter_definition_klass->new($params); };
  5         60  
56              
57 5 100       3768 croak(
58             "unable to apply parameterized role '${role}' to '${target}': $@"
59             ) if $@;
60             }
61              
62 26         185 $INFO{$role}{code_for}->( $params, $mop );
63             }
64             }
65              
66 25         5411 Moo::Role->apply_roles_to_package( $target, $role );
67             }
68              
69             sub role(&) { ##no critic (Subroutines::ProhibitSubroutinePrototypes)
70 14     14 1 245444 my $package = (caller)[0];
71              
72 14   100     246 $INFO{$package} ||= { is_role => 1 };
73              
74             croak "role subroutine called multiple times on '$package'"
75 14 50       53 if exists $INFO{$package}{code_for};
76              
77 14         46 $INFO{$package}{code_for} = shift;
78             }
79              
80             sub parameter {
81 5     5 1 657636 my $package = (caller)[0];
82              
83 5   50     55 $INFO{$package} ||= { is_role => 1 };
84              
85 5   50     11 push @{ $INFO{$package}{parameters_definition} ||= [] }, \@_;
  5         38  
86             }
87              
88             sub is_role {
89 47     47 1 8749 my ( $klass, $role ) = @_;
90              
91 47   66     392 return !!( $INFO{$role} && $INFO{$role}->{is_role} );
92             }
93              
94             sub build_apply_roles_to_package {
95 14     14 0 76 my ( $klass, $orig ) = @_;
96              
97             return sub {
98 15     15   546220 my $target = (caller)[0];
99              
100 15         240 while (@_) {
101 19         47 my $role = shift;
102              
103 19         43 eval { use_module($role) };
  19         98  
104              
105 19 100       27939 if ( MooX::Role::Parameterized->is_role($role) ) {
106 16         44 my $params = [ {} ];
107              
108 16 100 66     110 if ( @_ && ref $_[0] ) {
109 13         36 $params = shift;
110              
111 13 100       75 $params = [$params] if ref($params) ne ref( [] );
112             }
113              
114 16         39 foreach my $args ( @{$params} ) {
  16         44  
115 17         798 $role->apply_roles_to_target( $args, target => $target );
116             }
117              
118 15         34728 next;
119             }
120              
121 3 100 66     24 if ( defined $orig && ref $orig eq 'CODE' ) {
122 2         11 $orig->($role);
123              
124 2         6138 next;
125             }
126              
127 1 50       8 if ( Moo::Role->is_role($role) ) {
128 0         0 Moo::Role->apply_roles_to_package( $target, $role );
129 0         0 eval {
130 0         0 Moo::Role->_maybe_reset_handlemoose($target); ##no critic(Subroutines::ProtectPrivateSubs)
131             };
132              
133 0         0 next;
134             }
135              
136 1         88 croak "Can't apply role to '${target}' - '${role}' is neither a "
137             . "MooX::Role::Parameterized, Moo::Role or Role::Tiny role";
138             }
139 14         166 };
140             }
141              
142              
143             sub _fetch_parameter_definition_klass {
144 25     25   193 my $role = shift;
145              
146 25 50       96 return if !exists $INFO{$role};
147              
148 25 100       127 if ( !exists $INFO{$role}{parameter_definition_klass} ) {
149 23 100       101 return if !exists $INFO{$role}{parameters_definition};
150              
151 3         7 my $parameters_definition = $INFO{$role}{parameters_definition};
152              
153             $INFO{$role}{parameter_definition_klass} =
154 3         8 _create_parameters_klass( $role, $parameters_definition );
155              
156 3         84 delete $INFO{$role}{parameters_definition};
157             }
158              
159 5         14 return $INFO{$role}{parameter_definition_klass};
160             }
161              
162             sub _create_parameters_klass {
163 3     3   7 my ( $package, $parameters_definition ) = @_;
164              
165 3         5 my $klass = "${package}::__MOOX_ROLE_PARAMETERIZED_PARAMS__";
166              
167 3 50       37 return $klass if $klass->isa("Moo::Object");
168              
169 3         10 my @klass_definition = ( extends => "Moo::Object" );
170              
171 3         6 foreach my $parameter_definition ( @{$parameters_definition} ) {
  3         7  
172 3         7 push @klass_definition, has => $parameter_definition;
173             }
174              
175 3         19 BuildClass $klass => @klass_definition;
176              
177 3         54220 return $klass;
178             }
179              
180             1;
181             __END__