File Coverage

blib/lib/Type/Tiny/Role.pm
Criterion Covered Total %
statement 68 68 100.0
branch 18 28 64.2
condition 5 12 41.6
subroutine 23 23 100.0
pod 5 5 100.0
total 119 136 87.5


line stmt bran cond sub pod time code
1             package Type::Tiny::Role;
2              
3 32     32   72203 use 5.008001;
  32         132  
4 32     32   250 use strict;
  32         67  
  32         821  
5 32     32   154 use warnings;
  32         91  
  32         1993  
6              
7             BEGIN {
8 32     32   100 $Type::Tiny::Role::AUTHORITY = 'cpan:TOBYINK';
9 32         1569 $Type::Tiny::Role::VERSION = '2.003_000';
10             }
11              
12             $Type::Tiny::Role::VERSION =~ tr/_//d;
13              
14 32     32   238 use Scalar::Util qw< blessed weaken >;
  32         71  
  32         3969  
15              
16 1     1   6 sub _croak ($;@) { require Error::TypeTiny; goto \&Error::TypeTiny::croak }
  1         4  
17              
18 32     32   821 use Exporter::Tiny 1.004001 ();
  32         5449  
  32         793  
19 32     32   9708 use Type::Tiny::ConstrainedObject ();
  32         73  
  32         27635  
20             our @ISA = qw( Type::Tiny::ConstrainedObject Exporter::Tiny );
21              
22 3     3   9 sub _short_name { 'Role' }
23              
24             sub _exporter_fail {
25 1     1   151 my ( $class, $name, $opts, $globals ) = @_;
26 1         2 my $caller = $globals->{into};
27            
28 1 50       6 $opts->{name} = $name unless exists $opts->{name}; $opts->{name} =~ s/:://g;
  1         4  
29 1 50       7 $opts->{role} = $name unless exists $opts->{role};
30 1         3 my $type = $class->new($opts);
31            
32             $INC{'Type/Registry.pm'}
33             ? 'Type::Registry'->for_class( $caller )->add_type( $type )
34             : ( $Type::Registry::DELAYED{$caller}{$type->name} = $type )
35 1 50 33     24 unless( ref($caller) or $caller eq '-lexical' or $globals->{'lexical'} );
    50 33        
36 1         2 return map +( $_->{name} => $_->{code} ), @{ $type->exportables };
  1         6  
37             }
38              
39             my %cache;
40              
41             sub new {
42 65     65 1 726 my $proto = shift;
43 65 100       351 my %opts = ( @_ == 1 ) ? %{ $_[0] } : @_;
  2         7  
44 65 100       292 _croak "Need to supply role name" unless exists $opts{role};
45 64         375 return $proto->SUPER::new( %opts );
46             }
47              
48 93     93 1 699 sub role { $_[0]{role} }
49 426   66 426 1 2294 sub inlined { $_[0]{inlined} ||= $_[0]->_build_inlined }
50              
51 834     834 1 3120 sub has_inlined { !!1 }
52              
53 1492     1492   3697 sub _is_null_constraint { 0 }
54              
55             sub _build_constraint {
56 20     20   54 my $self = shift;
57 20         53 my $role = $self->role;
58             return sub {
59 31 50   31   124 blessed( $_ ) and do {
60 31   33     110 my $method = $_->can( 'DOES' ) || $_->can( 'isa' );
61 31         230 $_->$method( $role );
62             }
63 20         144 };
64             } #/ sub _build_constraint
65              
66             sub _build_inlined {
67 61     61   143 my $self = shift;
68 61         199 my $role = $self->role;
69             sub {
70 426     426   676 my $var = $_[1];
71 426         1469 my $code =
72             qq{Scalar::Util::blessed($var) and do { my \$method = $var->can('DOES')||$var->can('isa'); $var->\$method(q[$role]) }};
73 426 100       934 return qq{do { use Scalar::Util (); $code }} if $Type::Tiny::AvoidCallbacks;
74 377         803 $code;
75 61         435 };
76             } #/ sub _build_inlined
77              
78             sub _build_default_message {
79 2     2   6 my $self = shift;
80 2         4 my $c = $self->role;
81             return sub {
82 1     1   4 sprintf '%s did not pass type constraint (not DOES %s)',
83             Type::Tiny::_dd( $_[0] ), $c;
84             }
85 2 100       8 if $self->is_anon;
86 1         3 my $name = "$self";
87             return sub {
88 1     1   5 sprintf '%s did not pass type constraint "%s" (not DOES %s)',
89             Type::Tiny::_dd( $_[0] ), $name, $c;
90 1         11 };
91             } #/ sub _build_default_message
92              
93             sub validate_explain {
94 2     2 1 4 my $self = shift;
95 2         4 my ( $value, $varname ) = @_;
96 2 50       5 $varname = '$_' unless defined $varname;
97            
98 2 50       18 return undef if $self->check( $value );
99 2 50       31 return ["Not a blessed reference"] unless blessed( $value );
100 2 50       8 return ["Reference provides no DOES method to check roles"]
101             unless $value->can( 'DOES' );
102            
103 2 50       7 my $display_var = $varname eq q{$_} ? '' : sprintf( ' (in %s)', $varname );
104            
105             return [
106 2         6 sprintf( '"%s" requires that the reference does %s', $self, $self->role ),
107             sprintf( "The reference%s doesn't %s", $display_var, $self->role ),
108             ];
109             } #/ sub validate_explain
110              
111             1;
112              
113             __END__
114              
115             =pod
116              
117             =encoding utf-8
118              
119             =head1 NAME
120              
121             Type::Tiny::Role - type constraints based on the "DOES" method
122              
123             =head1 SYNOPSIS
124              
125             Using via L<Types::Standard>:
126              
127             package Local::Horse {
128             use Moo;
129             use Types::Standard qw( Str ConsumerOf );
130            
131             has name => (
132             is => 'ro',
133             isa => Str,
134             );
135            
136             has owner => (
137             is => 'ro',
138             isa => ConsumerOf[ 'Local::Traits::DoesOwnership' ],
139             default => sub { Local::Person->new },
140             );
141             }
142              
143             Using Type::Tiny::Class's export feature:
144              
145             package Local::Horse {
146             use Moo;
147             use Types::Standard qw( Str );
148             use Type::Tiny::Role (
149             Owner => { role => 'Local::Traits::DoesOwnership' },
150             );
151            
152             has name => (
153             is => 'ro',
154             isa => Str,
155             );
156            
157             has owner => (
158             is => 'ro',
159             isa => Owner,
160             default => sub { Local::Person->new },
161             );
162             }
163              
164             Using Type::Tiny::Role's object-oriented interface:
165              
166             package Local::Horse {
167             use Moo;
168             use Types::Standard qw( Str );
169             use Type::Tiny::Class;
170            
171             my $Owner = Type::Tiny::Role->new(
172             role => 'Local::Traits::DoesOwnership',
173             );
174            
175             has name => (
176             is => 'ro',
177             isa => Str,
178             );
179            
180             has owner => (
181             is => 'ro',
182             isa => $Owner,
183             default => sub { Local::Person->new },
184             );
185             }
186              
187             Using Type::Utils's functional interface:
188              
189             package Local::Horse {
190             use Moo;
191             use Types::Standard qw( Str );
192             use Type::Utils;
193            
194             my $Owner = role_type 'Local::Traits::DoesOwnership';
195            
196             has name => (
197             is => 'ro',
198             isa => Str,
199             );
200            
201             has owner => (
202             is => 'ro',
203             isa => $Owner,
204             default => sub { Local::Person->new },
205             );
206             }
207              
208             =head1 STATUS
209              
210             This module is covered by the
211             L<Type-Tiny stability policy|Type::Tiny::Manual::Policies/"STABILITY">.
212              
213             =head1 DESCRIPTION
214              
215             Type constraints of the general form C<< { $_->DOES("Some::Role") } >>.
216              
217             This package inherits from L<Type::Tiny>; see that for most documentation.
218             Major differences are listed below:
219              
220             =head2 Attributes
221              
222             =over
223              
224             =item C<role>
225              
226             The role for the constraint.
227              
228             Note that this package doesn't subscribe to any particular flavour of roles
229             (L<Moose::Role>, L<Mouse::Role>, L<Moo::Role>, L<Role::Tiny>, etc). It simply
230             trusts the object's C<DOES> method (see L<UNIVERSAL>).
231              
232             =item C<constraint>
233              
234             Unlike Type::Tiny, you I<cannot> pass a constraint coderef to the constructor.
235             Instead rely on the default.
236              
237             =item C<inlined>
238              
239             Unlike Type::Tiny, you I<cannot> pass an inlining coderef to the constructor.
240             Instead rely on the default.
241              
242             =item C<parent>
243              
244             Parent is always B<Types::Standard::Object>, and cannot be passed to the
245             constructor.
246              
247             =back
248              
249             =head2 Methods
250              
251             =over
252              
253             =item C<< stringifies_to($constraint) >>
254              
255             See L<Type::Tiny::ConstrainedObject>.
256              
257             =item C<< numifies_to($constraint) >>
258              
259             See L<Type::Tiny::ConstrainedObject>.
260              
261             =item C<< with_attribute_values($attr1 => $constraint1, ...) >>
262              
263             See L<Type::Tiny::ConstrainedObject>.
264              
265             =back
266              
267             =head2 Exports
268              
269             Type::Tiny::Role can be used as an exporter.
270              
271             use Type::Tiny::Role 'MyApp::Printable';
272              
273             This will export the following functions into your namespace:
274              
275             =over
276              
277             =item C<< MyAppPrintable >>
278              
279             =item C<< is_MyAppPrintable( $value ) >>
280              
281             =item C<< assert_MyAppPrintable( $value ) >>
282              
283             =item C<< to_MyAppPrintable( $value ) >>
284              
285             =back
286              
287             Multiple types can be exported at once:
288              
289             use Type::Tiny::Role qw( MyApp::Printable MyApp::Sendable );
290              
291             =head1 BUGS
292              
293             Please report any bugs to
294             L<https://github.com/tobyink/p5-type-tiny/issues>.
295              
296             =head1 SEE ALSO
297              
298             L<Type::Tiny::Manual>.
299              
300             L<Type::Tiny>.
301              
302             L<Moose::Meta::TypeConstraint::Role>.
303              
304             =head1 AUTHOR
305              
306             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
307              
308             =head1 COPYRIGHT AND LICENCE
309              
310             This software is copyright (c) 2013-2014, 2017-2023 by Toby Inkster.
311              
312             This is free software; you can redistribute it and/or modify it under
313             the same terms as the Perl 5 programming language system itself.
314              
315             =head1 DISCLAIMER OF WARRANTIES
316              
317             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
318             WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
319             MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.