File Coverage

blib/lib/Mouse/Util/MetaRole.pm
Criterion Covered Total %
statement 32 57 56.1
branch 12 34 35.2
condition 4 9 44.4
subroutine 5 8 62.5
pod 2 3 66.6
total 55 111 49.5


line stmt bran cond sub pod time code
1             package Mouse::Util::MetaRole;
2 109     109   38755 use Mouse::Util; # enables strict and warnings
  109         127  
  109         930  
3 109     109   416 use Scalar::Util ();
  109         124  
  109         56425  
4              
5             sub apply_metaclass_roles {
6 0     0 0 0 my %args = @_;
7 0         0 _fixup_old_style_args(\%args);
8              
9 0         0 return apply_metaroles(%args);
10             }
11              
12             sub apply_metaroles {
13 30     30 1 137 my %args = @_;
14              
15             my $for = Scalar::Util::blessed($args{for})
16             ? $args{for}
17 30 100       166 : Mouse::Util::get_metaclass_by_name( $args{for} );
18              
19 30 50       86 if(!$for){
20 0         0 Carp::confess("You must pass an initialized class, but '$args{for}' has no metaclass");
21             }
22              
23 30 100       104 if ( Mouse::Util::is_a_metarole($for) ) {
24 1         3 return _make_new_metaclass( $for, $args{role_metaroles}, 'role' );
25             }
26             else {
27 29         55 return _make_new_metaclass( $for, $args{class_metaroles}, 'class' );
28             }
29             }
30              
31             sub _make_new_metaclass {
32 30     30   36 my($for, $roles, $primary) = @_;
33              
34 30 50       21 return $for unless keys %{$roles};
  30         93  
35              
36             my $new_metaclass = exists($roles->{$primary})
37 30 100       131 ? _make_new_class( ref $for, $roles->{$primary} ) # new class with traits
38             : ref $for;
39              
40 30         39 my %classes;
41              
42 30         27 for my $key ( grep { $_ ne $primary } keys %{$roles} ) {
  35         72  
  30         54  
43 10         10 my $metaclass;
44 10   33     66 my $attr = $for->can($metaclass = ($key . '_metaclass'))
45             || $for->can($metaclass = ($key . '_class'))
46             || $for->throw_error("Unknown metaclass '$key'");
47              
48             $classes{ $metaclass }
49 10         31 = _make_new_class( $for->$attr(), $roles->{$key} );
50             }
51              
52 30         154 return $new_metaclass->reinitialize( $for, %classes );
53             }
54              
55              
56             sub _fixup_old_style_args {
57 0     0   0 my $args = shift;
58              
59 0 0 0     0 return if $args->{class_metaroles} || $args->{roles_metaroles};
60              
61             $args->{for} = delete $args->{for_class}
62 0 0       0 if exists $args->{for_class};
63              
64 0         0 my @old_keys = qw(
65             attribute_metaclass_roles
66             method_metaclass_roles
67             wrapped_method_metaclass_roles
68             instance_metaclass_roles
69             constructor_class_roles
70             destructor_class_roles
71             error_class_roles
72              
73             application_to_class_class_roles
74             application_to_role_class_roles
75             application_to_instance_class_roles
76             application_role_summation_class_roles
77             );
78              
79             my $for = Scalar::Util::blessed($args->{for})
80             ? $args->{for}
81 0 0       0 : Mouse::Util::get_metaclass_by_name( $args->{for} );
82              
83 0         0 my $top_key;
84 0 0       0 if( Mouse::Util::is_a_metaclass($for) ){
85 0         0 $top_key = 'class_metaroles';
86              
87             $args->{class_metaroles}{class} = delete $args->{metaclass_roles}
88 0 0       0 if exists $args->{metaclass_roles};
89             }
90             else {
91 0         0 $top_key = 'role_metaroles';
92              
93             $args->{role_metaroles}{role} = delete $args->{metaclass_roles}
94 0 0       0 if exists $args->{metaclass_roles};
95             }
96              
97 0         0 for my $old_key (@old_keys) {
98 0         0 my ($new_key) = $old_key =~ /^(.+)_(?:class|metaclass)_roles$/;
99              
100             $args->{$top_key}{$new_key} = delete $args->{$old_key}
101 0 0       0 if exists $args->{$old_key};
102             }
103              
104 0         0 return;
105             }
106              
107              
108             sub apply_base_class_roles {
109 0     0 1 0 my %options = @_;
110              
111 0         0 my $for = $options{for_class};
112              
113 0         0 my $meta = Mouse::Util::class_of($for);
114              
115             my $new_base = _make_new_class(
116             $for,
117             $options{roles},
118 0         0 [ $meta->superclasses() ],
119             );
120              
121 0 0       0 $meta->superclasses($new_base)
122             if $new_base ne $meta->name();
123 0         0 return;
124             }
125              
126             sub _make_new_class {
127 35     35   40 my($existing_class, $roles, $superclasses) = @_;
128              
129 35 50       64 if(!$superclasses){
130 35 50       64 return $existing_class if !$roles;
131              
132 35         86 my $meta = Mouse::Meta::Class->initialize($existing_class);
133              
134             return $existing_class
135 35 50 100     33 if !grep { !ref($_) && !$meta->does_role($_) } @{$roles};
  44         158  
  35         49  
136             }
137              
138 35 50       125 return Mouse::Meta::Class->create_anon_class(
139             superclasses => $superclasses ? $superclasses : [$existing_class],
140             roles => $roles,
141             cache => 1,
142             )->name();
143             }
144              
145             1;
146             __END__