File Coverage

blib/lib/Sub/NonRole.pm
Criterion Covered Total %
statement 36 60 60.0
branch 3 16 18.7
condition n/a
subroutine 12 15 80.0
pod 1 1 100.0
total 52 92 56.5


line stmt bran cond sub pod time code
1             package Sub::NonRole;
2              
3 2     2   126183 use 5.008;
  2         10  
  2         173  
4 2     2   13 use strict;
  2         4  
  2         111  
5              
6             BEGIN {
7 2     2   81 $Sub::NonRole::AUTHORITY = 'cpan:TOBYINK';
8 2         73 $Sub::NonRole::VERSION = '0.004';
9             }
10              
11 2     2   2363 use Hook::AfterRuntime;
  2         16516  
  2         168  
12 2     2   1927 use MooX::CaptainHook -all;
  2         21143  
  2         19  
13 2     2   2036 use Sub::Identify 'get_code_info';
  2         5522  
  2         138  
14              
15 2     2   12 use base 'Sub::Talisman';
  2         4  
  2         1657  
16              
17             sub import
18             {
19 2     2   26 shift->setup_for(scalar(caller), @_);
20             }
21              
22             sub setup_for
23             {
24 2     2 1 6 my ($class, $caller) = @_;
25 2         16 $class->SUPER::setup_for($caller, { attribute => 'NonRole'});
26 2     2   3075 after_runtime { $class->_post_process($caller) };
  2         129  
27             }
28              
29             sub _post_process
30             {
31 2     2   7 my ($class, $caller) = @_;
32            
33 2 50       151 my @subs =
34 2         31 map { /^\Q$caller\E::([^:]+)$/ ? $1 : () }
35             $class->get_subs("$caller\::NonRole");
36 2         7 push @subs, 'FETCH_CODE_ATTRIBUTES';
37            
38 2 50       38 if (exists $Role::Tiny::INFO{$caller})
39             {
40 2         46 $Role::Tiny::INFO{$caller}{not_methods}{$_} = $caller->can($_) for @subs;
41            
42             on_application {
43 2     2   31101 my ($role, $pkg) = @{ $_[0] };
  2         12  
44 2         27 } $caller;
45            
46             on_inflation {
47 0 0   0   0 if ($_->name eq $caller) {
48 0         0 require Moose::Util::MetaRole;
49 0         0 _mk_moose_trait();
50 0         0 $_[0][0] = Moose::Util::MetaRole::apply_metaroles(
51             for => $caller,
52             role_metaroles => {
53             role => ['Sub::NonRole::Trait::Role'],
54             },
55             );
56 0         0 @{ $_[0][0]->non_role_methods } = @subs;
  0         0  
57             }
58 2         6060 } $caller;
59             }
60            
61 2 50       35 $INC{'Class/MOP.pm'} or return;
62 0 0         my $class_of = 'Class::MOP'->can('class_of') or return;
63            
64 0           require Moose::Util::MetaRole;
65 0           _mk_moose_trait();
66 0           my $meta = $class_of->($caller);
67            
68 0 0         if ($meta->can('has_role_generator')) # lolcat
69             {
70 0           _mk_moose_trait_param();
71 0           my $P_mc = $meta->parameters_metaclass;
72 0           my $P_rg = $meta->role_generator;
73 0           $meta = Moose::Util::MetaRole::apply_metaroles(
74             for => $caller,
75             role_metaroles => {
76             role => ['Sub::NonRole::Trait::ParameterizableRole'],
77             },
78             );
79 0           $meta->parameters_metaclass($P_mc);
80 0           $meta->role_generator($P_rg);
81             }
82             else # standard Moose role
83             {
84 0           $meta = Moose::Util::MetaRole::apply_metaroles(
85             for => $caller,
86             role_metaroles => {
87             role => ['Sub::NonRole::Trait::Role'],
88             },
89             );
90             }
91            
92 0           @{ $meta->non_role_methods } = @subs;
  0            
93             }
94              
95             my $made_it;
96             sub _mk_moose_trait
97             {
98 0 0   0     return if $made_it++;
99 0           eval q{
100             package Sub::NonRole::Trait::Role;
101             use Moose::Role;
102             has non_role_methods => (
103             is => 'ro',
104             isa => 'ArrayRef',
105             default => sub { [] },
106             );
107             around _get_local_methods => sub {
108             my $orig = shift;
109             my $self = shift;
110             my %return = map { $_->name => $_ } $self->$orig(@_);
111             delete @return{ @{$self->non_role_methods} };
112             return values %return;
113             };
114             around get_method_list => sub {
115             my $orig = shift;
116             my $self = shift;
117             my %return = map { $_ => 1 } $self->$orig(@_);
118             delete @return{ @{$self->non_role_methods} };
119             return keys %return;
120             };
121             };
122             }
123              
124             my $made_it_param;
125             sub _mk_moose_trait_param
126             {
127 0 0   0     return if $made_it_param++;
128 0           eval q{
129             package Sub::NonRole::Trait::ParameterizableRole;
130             use Moose::Role;
131             with 'Sub::NonRole::Trait::Role';
132             # around generate_role => sub {
133             # my $orig = shift;
134             # my $self = shift;
135             # my $role = $self->$orig(@_);
136             # return $role;
137             # };
138             };
139             }
140              
141             1;
142              
143             __END__
144              
145             =head1 NAME
146              
147             Sub::NonRole - prevent some subs from appearing in a role's API
148              
149             =head1 SYNOPSIS
150              
151             package My::Role {
152             use Moose::Role;
153             use Sub::NonRole;
154            
155             sub some_function {
156             ...;
157             }
158            
159             sub other_function : NonRole {
160             ...;
161             }
162             }
163            
164             package My::Class {
165             use Moose;
166             with 'My::Role';
167             }
168            
169             My::Class->some_function(); # ok
170             My::Class->other_function(); # no such method!
171              
172             =head1 DESCRIPTION
173              
174             This module allows you to mark certain subs within a role as not being
175             part of the role's API. This means that they will not be copied across
176             into packages which consume the role.
177              
178             The subs can still be called as:
179              
180             My::Role->other_function();
181             My::Role::other_function();
182              
183             It should work with L<Role::Tiny>, L<Moo::Role>, L<Moose::Role> and
184             L<MooseX::Role::Parameterized> roles.
185              
186             =head2 Developer API
187              
188             =over
189              
190             =item C<< Sub::NonRole->setup_for($role) >>
191              
192             If you wish to import the Sub::NonRole functionality into another package,
193             this is how to do it.
194              
195             =item C<< $role->meta->non_role_methods >>
196              
197             For Moose roles (but not Moo or Role::Tiny ones) you can access the
198             C<non_role_methods> attribute on the role's meta object to get an arrayref
199             of non-role method names.
200              
201             =back
202              
203             =head1 BUGS
204              
205             Currently when consuming a Moo role within a Moose class, Sub::NonRole
206             can cause a warning to be issued in the global cleanup phase. This is
207             unlikely to result in serious problems; it's just annoying.
208              
209             In older Perls (before 5.10.1 I believe), importing Sub::Role into a package
210             without actually applying the attribute to any subs can cause a crash with
211             the error message I<< Internal error: Your::Package symbol went missing >>.
212             Once you've applied the C<:NonRole> attribute to a sub, everything should be
213             OK.
214              
215             Please report any other bugs to
216             L<http://rt.cpan.org/Dist/Display.html?Queue=Sub-NonRole>.
217              
218             =head1 SEE ALSO
219              
220             L<Role::Tiny>, L<Moo::Role>, L<Moose::Role>.
221              
222             =head1 AUTHOR
223              
224             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
225              
226             =head1 COPYRIGHT AND LICENCE
227              
228             This software is copyright (c) 2013 by Toby Inkster.
229              
230             This is free software; you can redistribute it and/or modify it under
231             the same terms as the Perl 5 programming language system itself.
232              
233             =head1 DISCLAIMER OF WARRANTIES
234              
235             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
236             WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
237             MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
238