1Type::Tiny::Manual::UsiUnsgeWritChoOntthreirb(u3t)ed PerTlypDeo:c:uTmiennyt:a:tMiaonnual::UsingWithOther(3)
2
3
4

NAME

6       Type::Tiny::Manual::UsingWithOther - using Type::Tiny with
7       Class::InsideOut, Params::Check, and Object::Accessor.
8

MANUAL

10       The antlers crew aren't the only object-oriented programming toolkits
11       in Perl town. Although Type::Tiny might have been built with Moose,
12       Mouse, and Moo in mind, it can be used with other toolkits.
13
14       These toolkits are... well... hmm... okay... they exist.
15
16       If you are starting a new project, there's very little reason not to
17       use Class::Tiny, Moo, or Moose. So you're probably okay to skip this
18       part of the fine manual and go straight to
19       Type::Tiny::Manual::UsingWithTestMore.
20
21   Class::InsideOut
22       You want Class::InsideOut 1.13 or above, which has support for blessed
23       and overloaded objects (including Type::Tiny type constraints) for the
24       "get_hook" and "set_hook" options.
25
26         package Person {
27           use Class::InsideOut qw( public );
28           use Types::Standard qw( Str Int );
29           use Types::Common::Numeric qw( PositiveInt );
30           use Type::Params qw( signature );
31
32           # Type checks are really easy.
33           # Just supply the type as a set hook.
34           public name => my %_name, {
35             set_hook => Str,
36           };
37
38           # Define a type that silently coerces negative values
39           # to positive. It's silly, but it works as an example!
40           my $Years = PositiveInt->plus_coercions(Int, q{ abs($_) });
41
42           # Coercions are more annoying, but possible.
43           public age => my %_age, {
44             set_hook => sub { $_ = $Years->assert_coerce($_) },
45           };
46
47           # Parameter checking for methods is as expected.
48           sub get_older {
49             state $check = signature( method => 1, positional => [ $Years ] );
50             my ( $self, $years ) = $check->( @_ );
51             $self->_set_age( $self->age + $years );
52           }
53         }
54
55   Params::Check and Object::Accessor
56       The Params::Check allow() function, the "allow" option for the
57       Params::Check check() function, and the input validation mechanism for
58       Object::Accessor all work in the same way, which is basically a limited
59       pure-Perl implementation of the smart match operator. While this
60       doesn't directly support Type::Tiny constraints, it does support
61       coderefs.  You can use Type::Tiny's "compiled_check" method to obtain a
62       suitable coderef.
63
64       Param::Check example:
65
66         my $tmpl = {
67           name => { allow => Str->compiled_check },
68           age  => { allow => Int->compiled_check },
69         };
70         check($tmpl, { name => "Bob", age => 32 })
71           or die Params::Check::last_error();
72
73       Object::Accessor example:
74
75         my $obj = Object::Accessor->new;
76         $obj->mk_accessors(
77           { name => Str->compiled_check },
78           { age  => Int->compiled_check },
79         );
80
81       Caveat: Object::Accessor doesn't die when a value fails to meet its
82       type constraint; instead it outputs a warning to STDERR. This behaviour
83       can be changed by setting "$Object::Accessor::FATAL = 1".
84
85   Class::Struct
86       This is proof-of-concept of how Type::Tiny can be used to constrain
87       attributes for Class::Struct. It's probably not a good idea to use this
88       in production as it slows down "UNIVERSAL::isa" globally.
89
90         use Types::Standard -types;
91         use Class::Struct;
92
93         {
94           my %MAP;
95           my $orig_isa = \&UNIVERSAL::isa;
96           *UNIVERSAL::isa = sub {
97             return $MAP{$1}->check($_[0])
98               if $_[1] =~ /^CLASSSTRUCT::TYPETINY::(.+)$/ && exists $MAP{$1};
99             goto $orig;
100           };
101           my $orig_dn = \&Type::Tiny::display_name;
102           *Type::Tiny::display_name = sub {
103             if (caller(1) eq 'Class::Struct') {
104               $MAP{$_[0]{uniq}} = $_[0];
105               return "CLASSSTRUCT::TYPETINY::".$_[0]{uniq};
106             }
107             goto $orig_dn;
108           };
109         }
110
111         struct Person => [ name => Str, age => Int ];
112
113         my $bob = Person->new(
114           name => "Bob",
115           age  => 21,
116         );
117
118         $bob->name("Robert");   # okay
119         $bob->name([]);         # dies
120
121   Class::Plain
122       There is not currently a high level of integration, but here's a quick
123       example of type checking attributes in the constructor.
124
125       If any of your accessors are ":rw" then you would also need to add type
126       checks to those.
127
128         use Class::Plain;
129
130         class Point {
131           use Types::Common -types, -sigs;
132
133           field x :reader;
134           field y :reader;
135
136           signature_for new => (
137             method => !!1,
138             bless  => !!0,
139             named  => [
140               x => Int,
141               y => Int,
142             ],
143           );
144
145           method as_arrayref () {
146             return [ $self->x, $self->y ];
147           }
148         }
149
150       The following signature may also be of interest:
151
152         signature_for new => (
153           method   => !!1,
154           multiple => [
155             {
156               named => [
157                 x => Int,
158                 y => Int,
159               ],
160               bless => !!0,
161             },
162             {
163               positional => [ Int, Int ],
164               goto_next  => sub {
165                 my ( $class, $x, $y ) = @_;
166                 return ( $class, { x => $x, y => $y } ),
167               },
168             },
169           ],
170         );
171
172       This would allow your class to be instantiated using any of the
173       following:
174
175         my $point11 = Point->new( { x => 1, y => 1 } );
176         my $point22 = Point->new(   x => 2, y => 2   );
177         my $point33 = Point->new( 3, 3 );
178

NEXT STEPS

180       Here's your next step:
181
182       •   Type::Tiny::Manual::UsingWithTestMore
183
184           Type::Tiny for test suites.
185

AUTHOR

187       Toby Inkster <tobyink@cpan.org>.
188
190       This software is copyright (c) 2013-2014, 2017-2023 by Toby Inkster.
191
192       This is free software; you can redistribute it and/or modify it under
193       the same terms as the Perl 5 programming language system itself.
194

DISCLAIMER OF WARRANTIES

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
200
201
202perl v5.36.0                      2023-04-T2y4pe::Tiny::Manual::UsingWithOther(3)
Impressum