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