File Coverage

blib/lib/Sub/NonRole.pm
Criterion Covered Total %
statement 60 60 100.0
branch 12 16 75.0
condition n/a
subroutine 15 15 100.0
pod 1 1 100.0
total 88 92 95.6


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