1Type::Tiny::Manual::UsiUnsgeWritChoOntthreirb(u3t)ed PerTlypDeo:c:uTmiennyt:a:tMiaonnual::UsingWithOther(3)
2
3
4
6 Type::Tiny::Manual::UsingWithOther - using Type::Tiny with
7 Class::InsideOut, Params::Check, and Object::Accessor.
8
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
180 Here's your next step:
181
182 • Type::Tiny::Manual::UsingWithTestMore
183
184 Type::Tiny for test suites.
185
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
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)