File Coverage

lib/Types/Interface.pm
Criterion Covered Total %
statement 24 24 100.0
branch n/a
condition n/a
subroutine 8 8 100.0
pod n/a
total 32 32 100.0


line stmt bran cond sub pod time code
1 1     1   76271 use 5.008;
  1         4  
  1         75  
2 1     1   8 use strict;
  1         1  
  1         35  
3 1     1   5 use warnings;
  1         7  
  1         77  
4              
5             package Types::Interface;
6              
7             our $AUTHORITY = 'cpan:TOBYINK';
8             our $VERSION = '0.002';
9              
10 1     1   6 use Carp qw( croak );
  1         3  
  1         80  
11 1     1   919 use Role::Inspector qw( get_role_info );
  1         7203  
  1         16  
12 1     1   1258 use Type::Library -base, -declare => qw( ClassDoesInterface ObjectDoesInterface );
  1         21721  
  1         12  
13 1     1   3257 use Types::LoadableClass qw( LoadableClass );
  1         112503  
  1         12  
14 1     1   431 use Types::Standard qw( Object );
  1         3  
  1         7  
15              
16             my %common = (
17             constraint_generator => sub {
18             my ($role, %opts) = @_;
19             my $info = get_role_info($role)
20             or croak("$role does not seem to be a role");
21             my @methods = @{$info->{api}};
22             @methods = grep(!/\A_/, @methods)
23             if exists($opts{private}) && !$opts{private};
24            
25             return sub {
26             $_->DOES($role) or do {
27             my $ok = 1;
28             for my $method (@methods) {
29             $_->can($method) or ($ok=0, next);
30             }
31             $ok;
32             };
33             };
34             },
35            
36             inline_generator => sub {
37             my ($role, %opts) = @_;
38             my $info = get_role_info($role)
39             or croak("$role does not seem to be a role");
40             my @methods = @{$info->{api}};
41             @methods = grep(!/\A_/, @methods)
42             if exists($opts{private}) && !$opts{private};
43            
44             return sub {
45             my $var = $_[1];
46             return (
47             undef,
48             sprintf(
49             '(%s->DOES(%s) or (%s))',
50             $var,
51             B::perlstring($role),
52             join(
53             ' and ',
54             map(
55             sprintf('%s->can(%s)', $var, B::perlstring($_)),
56             @methods,
57             ),
58             ),
59             ),
60             );
61             };
62             },
63             );
64              
65             __PACKAGE__->meta->add_type({
66             name => ClassDoesInterface,
67             parent => LoadableClass,
68             %common,
69             });
70              
71             __PACKAGE__->meta->add_type({
72             name => ObjectDoesInterface,
73             parent => Object,
74             %common,
75             });
76              
77             1;
78              
79             __END__
80              
81             =pod
82              
83             =encoding utf-8
84              
85             =head1 NAME
86              
87             Types::Interface - fuzzy role constraints
88              
89             =head1 SYNOPSIS
90              
91             package MyApp::Role::FooBar {
92             use Moose::Role;
93            
94             requires qw( foo bar );
95             }
96            
97             package MyApp::Class::FooBar {
98             use Moose;
99            
100             # Note, the following line is commented out!
101             # with qw( MyApp::Role::FooBar );
102            
103             sub foo { 1 }
104             sub bar { 2 }
105             }
106            
107             package MyApp::Class::Main {
108             use Moose;
109             use Types::Interface qw(ObjectDoesInterface);
110            
111             has foobar => (
112             is => 'ro',
113             isa => ObjectDoesInterface['MyApp::Role::FooBar'],
114             );
115             }
116            
117             # This is ok...
118             my $obj = MyApp::Class::Main->new(
119             foobar => MyApp::Class::FooBar->new(),
120             );
121              
122             =head1 DESCRIPTION
123              
124             Types::Interface provides a type constraint library suitable for
125             L<Moose>, L<Mouse>, and L<Moo> attributes, L<Kavorka> signatures,
126             and any other place where type constraints might be used.
127              
128             The type constraints it provides are based on the idea that an
129             object or class might fulfil all the requirements for a role without
130             explicitly consuming the role.
131              
132             =head2 Type Constraints
133              
134             This module provides the following type constraints:
135              
136             =over
137              
138             =item C<< ObjectDoesInterface[$role] >>
139              
140             This type constraint accepts any object where C<< $object->DOES($role) >>
141             returns true, B<or> where the object happens to provide all the methods
142             that form part of the role's API, according to L<Role::Inspector>.
143              
144             This type constraint is a subtype of C<Object> from L<Types::Standard>.
145              
146             =item C<< ObjectDoesInterface[$role, private => 0] >>
147              
148             This type constraint accepts any object where C<< $object->DOES($role) >>
149             returns true, B<or> where the object happens to provide all the public
150             methods (i.e. those not starting with an underscore) that form part of
151             the role's API, according to L<Role::Inspector>.
152              
153             =item C<< ClassDoesInterface[$role] >>
154              
155             This type constraint accepts any class name where C<< $class->DOES($role) >>
156             returns true, B<or> where the class happens to provide all the methods
157             that form part of the role's API, according to L<Role::Inspector>.
158              
159             This type constraint is a subtype of C<LoadableClass> from
160             L<Types::LoadableClass>.
161              
162             =item C<< ClassDoesInterface[$role, private => 0] >>
163              
164             This type constraint accepts any class name where C<< $class->DOES($role) >>
165             returns true, B<or> where the object class to provide all the public
166             methods (i.e. those not starting with an underscore) that form part of
167             the role's API, according to L<Role::Inspector>.
168              
169             =back
170              
171             =head1 BUGS
172              
173             Please report any bugs to
174             L<http://rt.cpan.org/Dist/Display.html?Queue=Types-Interface>.
175              
176             =head1 SEE ALSO
177              
178             L<Type::Tiny::Manual>,
179             L<Types::LoadableClass>,
180             L<Types::Standard>,
181             L<Role::Inspector>.
182              
183             =head1 AUTHOR
184              
185             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
186              
187             =head1 COPYRIGHT AND LICENCE
188              
189             This software is copyright (c) 2014 by Toby Inkster.
190              
191             This is free software; you can redistribute it and/or modify it under
192             the same terms as the Perl 5 programming language system itself.
193              
194             =head1 DISCLAIMER OF WARRANTIES
195              
196             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
197             WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
198             MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
199