File Coverage

lib/MooseX/Extended/Role.pm
Criterion Covered Total %
statement 69 69 100.0
branch 9 12 75.0
condition 2 3 66.6
subroutine 15 15 100.0
pod 0 1 0.0
total 95 100 95.0


line stmt bran cond sub pod time code
1              
2             # ABSTRACT: MooseX::Extended roles
3              
4             use strict;
5 6     6   15806 use warnings;
  6         35  
  6         250  
6 6     6   29 use Moose::Exporter;
  6         10  
  6         130  
7 6     6   489 use MooseX::Extended::Core qw(
  6         6774  
  6         54  
8 6         362 field
9             param
10             _debug
11             _assert_import_list_is_valid
12             _enabled_features
13             _disabled_warnings
14             _our_import
15             _our_init_meta
16             );
17 6     6   291 use MooseX::Role::WarnOnConflict ();
  6         8  
18 6     6   2542 use Moose::Role;
  6         433915  
  6         194  
19 6     6   47 use Moose::Meta::Role;
  6         12  
  6         31  
20 6     6   28234 use namespace::autoclean ();
  6         14  
  6         169  
21 6     6   569 use Import::Into;
  6         7508  
  6         149  
22 6     6   40 use true;
  6         10  
  6         119  
23 6     6   1259 use feature _enabled_features();
  6         15650  
  6         38  
24 6     6   6073 no warnings _disabled_warnings();
  6         11  
  6         29  
25 6     6   37  
  6         11  
  6         21  
26             our $VERSION = '0.34';
27              
28             # Should this be in the metaclass? It feels like it should, but
29             # the MOP really doesn't support these edge cases.
30             my %CONFIG_FOR;
31              
32             my ( $class, %args ) = @_;
33             my @caller = caller(0);
34 24     24   41215 $args{_import_type} = 'role';
35 24         113 $args{_caller_eval} = ( $caller[1] =~ /^\(eval/ );
36 24         133 my $target_class = _assert_import_list_is_valid( $class, \%args );
37 24         82 my @with_meta = grep { not $args{excludes}{$_} } qw(field param);
38 24         95 if (@with_meta) {
39 23         44 @with_meta = ( with_meta => [@with_meta] );
  46         102  
40 23 50       57 }
41 23         53 my ( $import, undef, undef ) = Moose::Exporter->setup_import_methods(
42             @with_meta,
43 23         82 );
44             _our_import( $class, $import, $target_class );
45             }
46 23         10408  
47             my $for_class = $params{for_class};
48             _our_init_meta( $class, \&_apply_default_features, %params );
49 23     23 0 1477 return $for_class->meta;
  23         38  
  23         60  
  23         28  
50 23         37 }
51 23         91  
52 23         319  
53             if ( my $types = $config->{types} ) {
54             _debug("$for_class: importing types '@$types'");
55 23     23   25 MooseX::Extended::Types->import::into( $for_class, @$types );
  23         31  
  23         33  
  23         27  
  23         26  
56             }
57 23 100       50  
58 2         17 Carp->import::into($for_class) unless $config->{excludes}{carp};
59 2         28 namespace::autoclean->import::into($for_class) unless $config->{excludes}{autoclean};
60             true->import unless $config->{excludes}{true} || $config->{_caller_eval}; # https://github.com/Ovid/moosex-extended/pull/34
61             MooseX::Role::WarnOnConflict->import::into($for_class) unless $config->{excludes}{WarnOnConflict};
62 23 50       10122  
63 23 50       4748 feature->import( _enabled_features() );
64 23 100 66     4158 warnings->unimport(_disabled_warnings);
65 23 100       4228  
66             Moose::Role->init_meta( ##
67 23         112205 %$params, ##
68 23         77 metaclass => 'Moose::Meta::Role'
69             );
70 23         119 }
71              
72             1;
73              
74              
75             =pod
76              
77             =encoding UTF-8
78              
79             =head1 NAME
80              
81             MooseX::Extended::Role - MooseX::Extended roles
82              
83             =head1 VERSION
84              
85             version 0.34
86              
87             =head1 SYNOPSIS
88              
89             package Not::Corinna::Role::Created {
90             use MooseX::Extended::Role types => ['PositiveInt'];
91              
92             field created => ( isa => PositiveInt, default => sub { time } );
93             }
94              
95             Similar to L<MooseX::Extended>, providing almost everything that module provides.
96             However, for obvious reasons, it does not include L<MooseX::StrictConstructor>
97             or make your class immutable, or set the C3 mro.
98              
99             Note that there is no need to add a C<1> at the end of the role.
100              
101             =head1 CONFIGURATION
102              
103             You may pass an import list to L<MooseX::Extended::Role>.
104              
105             use MooseX::Extended::Role
106             excludes => [qw/WarnOnConflict carp/], # I don't want these features
107             types => [qw/compile PositiveInt HashRef/]; # I want these type tools
108              
109             =head2 C<types>
110              
111             Allows you to import any types provided by L<MooseX::Extended::Types>.
112              
113             This:
114              
115             use MooseX::Extended::Role types => [qw/compile PositiveInt HashRef/];
116              
117             Is identical to this:
118              
119             use MooseX::Extended::Role;
120             use MooseX::Extended::Types qw( compile PositiveInt HashRef );
121              
122             =head2 C<excludes>
123              
124             You may find some features to be annoying, or even cause potential bugs (e.g.,
125             if you have a `croak` method, our importing of C<Carp::croak> will be a
126             problem. You can exclude the following:
127              
128             =over 4
129              
130             =item * C<WarnOnConflict>
131              
132             use MooseX::Extended::Role excludes => ['WarnOnConflict'];
133              
134             Excluding this removes the C<MooseX::Role::WarnOnConflict> role.
135              
136             =item * C<autoclean>
137              
138             use MooseX::Extended::Role excludes => ['autoclean'];
139              
140             Excluding this will no longer import C<namespace::autoclean>.
141              
142             =item * C<carp>
143              
144             use MooseX::Extended::Role excludes => ['carp'];
145              
146             Excluding this will no longer import C<Carp::croak> and C<Carp::carp>.
147              
148             =item * C<true>
149              
150             use MooseX::Extended::Role excludes => ['true'];
151              
152             Excluding this will require your module to end in a true value.
153              
154             =item * C<param>
155              
156             use MooseX::Extended::Role excludes => ['param'];
157              
158             Excluding this will make the C<param> function unavailable.
159              
160             =item * C<field>
161              
162             use MooseX::Extended::Role excludes => ['field'];
163              
164             Excluding this will make the C<field> function unavailable.
165              
166             =back
167              
168             =head2 C<includes>
169              
170             Some experimental features are useful, but might not be quite what you want.
171              
172             use MooseX::Extended::Role includes => [qw/multi/];
173              
174             multi sub foo ($self, $x) { ... }
175             multi sub foo ($self, $x, $y ) { ... }
176              
177             See L<MooseX::Extended::Manual::Includes> for more information.
178              
179             =head1 IDENTICAL METHOD NAMES IN CLASSES AND ROLES
180              
181             In L<Moose> if a class defines a method of the name as the method of a role
182             it's consuming, the role's method is I<silently> discarded. With
183             L<MooseX::Extended::Role>, you get a warning. This makes maintenance easier
184             when to prevent you from accidentally overriding a method.
185              
186             For example:
187              
188             package My::Role {
189             use MooseX::Extended::Role;
190              
191             sub name {'Ovid'}
192             }
193              
194             package My::Class {
195             use MooseX::Extended;
196             with 'My::Role';
197             sub name {'Bob'}
198             }
199              
200             The above code will still run, but you'll get a very verbose warning:
201              
202             The class My::Class has implicitly overridden the method (name) from
203             role My::Role. If this is intentional, please exclude the method from
204             composition to silence this warning (see Moose::Cookbook::Roles::Recipe2)
205              
206             To silence the warning, just be explicit about your intent:
207              
208             package My::Class {
209             use MooseX::Extended;
210             with 'My::Role' => { -excludes => ['name'] };
211             sub name {'Bob'}
212             }
213              
214             Alternately, you can exclude this feature. We don't recommend this, but it
215             might be useful if you're refactoring a legacy Moose system.
216              
217             use MooseX::Extended::Role excludes => [qw/WarnOnConflict/];
218              
219             =head1 ATTRIBUTE SHORTCUTS
220              
221             C<param> and C<field> in roles allow the same L<attribute
222             shortcuts|MooseX::Extended::Manual::Shortcuts> as L<MooseX::Extended>.
223              
224             =head1 BUGS AND LIMITATIONS
225              
226             If the MooseX::Extended::Role is loaded via I<stringy> eval, C<true> is not
227             loaded, This is because there were intermittant errors (maybe 1 out of 5
228             times) being thrown. Removing this feature under stringy eval solves this. See
229             L<this github ticket for more
230             infomration|https://github.com/Ovid/moosex-extended/pull/34>.
231              
232             =head1 REDUCING BOILERPLATE
233              
234             Let's say you've settled on the following feature set:
235              
236             use MooseX::Extended::Role
237             excludes => [qw/WarnOnConflict carp/],
238             includes => [qw/multi/];
239              
240             And you keep typing that over and over. We've removed a lot of boilerplate,
241             but we've added different boilerplate. Instead, just create
242             C<My::Custom::Moose::Role> and C<use My::Custom::Moose::Role;>. See
243             L<MooseX::Extended::Role::Custom> for details.
244              
245             =head1 AUTHOR
246              
247             Curtis "Ovid" Poe <curtis.poe@gmail.com>
248              
249             =head1 COPYRIGHT AND LICENSE
250              
251             This software is Copyright (c) 2022 by Curtis "Ovid" Poe.
252              
253             This is free software, licensed under:
254              
255             The Artistic License 2.0 (GPL Compatible)
256              
257             =cut