.\" -*- mode: troff; coding: utf-8 -*- .\" Automatically generated by Pod::Man 5.01 (Pod::Simple 3.43) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>. .ie n \{\ . ds C` "" . ds C' "" 'br\} .el\{\ . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" ======================================================================== .\" .IX Title "Type::Tiny::Manual::UsingWithClassTiny 3" .TH Type::Tiny::Manual::UsingWithClassTiny 3 2024-03-13 "perl v5.38.2" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH NAME Type::Tiny::Manual::UsingWithClassTiny \- use of Type::Tiny with Class::Tiny .SH MANUAL .IX Header "MANUAL" Class::Tiny is an even-smaller-than-Moo class builder. .PP Let's translate the classic Horse class from Moo to Class::Tiny. .PP Moo: .PP .Vb 4 \& package Horse { \& use Moo; \& use Types::Standard qw( Str Num ArrayRef ); \& use namespace::autoclean; \& \& has name => ( is => \*(Aqro\*(Aq, isa => Str, required => 1 ); \& has gender => ( is => \*(Aqro\*(Aq, isa => Str ); \& has age => ( is => \*(Aqrw\*(Aq, isa => Num ); \& has children => ( \& is => \*(Aqro\*(Aq, \& isa => ArrayRef, \& default => sub { return [] }, \& ); \& } .Ve .PP Class::Tiny: .PP .Vb 8 \& package Horse { \& use Class::Tiny qw( gender age ), { \& name => sub { die "name is required"; }, \& children => sub { return [] }, \& }; \& use Types::Standard qw( Str Num ArrayRef Dict Optional Slurpy Any Object ); \& use Type::Params qw( signature_for ); \& use namespace::autoclean; \& \& # type checks \& signature_for BUILD => ( \& method => Object, \& named => [ \& name => Str, \& gender => Optional[Str], \& age => Optional[Num], \& children => Optional[ArrayRef], \& () => Slurpy[Any], \& ], \& fallback => 1, \& ); \& signature_for [ \*(Aqname\*(Aq, \*(Aqgender\*(Aq, \*(Aqchildren\*(Aq ] => ( \& method => Object, \& positional => [], \& ); \& signature_for age => ( \& method => Object, \& positional => [ Optional[Num] ], \& ); \& } .Ve .PP What's going on here? .PP Well, Class::Tiny, after it has built a new object, will do this: .PP .Vb 1 \& $self\->BUILD($args); .Ve .PP (Technically, it calls \f(CW\*(C`BUILD\*(C'\fR not just for the current class, but for all parent classes too.) We can hook onto this in order to check type constraints for the constructor. .PP We use \f(CW\*(C`signature_for\*(C'\fR from Type::Params to wrap the original \f(CW\*(C`BUILD\*(C'\fR method (which doesn't exist, so \f(CW\*(C`fallback => 1\*(C'\fR will just assume an empty sub) with a type check for its arguments. The type check is just a \&\fBDict\fR that checks the class's required and optional attributes and includes \&\fBSlurpy[Any]\fR at the end to be flexible for subclasses adding new attributes. .PP Then we wrap the \f(CW\*(C`name\*(C'\fR, \f(CW\*(C`gender\*(C'\fR, and \f(CW\*(C`children\*(C'\fR methods with checks to make sure they're only being called as getters, and we wrap \f(CW\*(C`age\*(C'\fR, allowing it to be called as a setter with a \fBNum\fR. .PP There are also a couple of CPAN modules that can help you out. .SS Class::Tiny::ConstrainedAccessor .IX Subsection "Class::Tiny::ConstrainedAccessor" Class::Tiny::ConstrainedAccessor creates a \f(CW\*(C`BUILD\*(C'\fR and accessors that enforce Type::Tiny constraints. Attribute types are passed to Class::Tiny::ConstrainedAccessor; attribute defaults are passed to Class::Tiny. .PP .Vb 10 \& package Horse { \& use Types::Standard qw( Str Num ArrayRef ); \& use Class::Tiny::ConstrainedAccessor { \& name => Str, \& gender => Str, \& age => Num, \& children => ArrayRef, \& }; \& use Class::Tiny qw( gender age ), { \& name => sub { die "name is required"; }, \& children => sub { return [] }, \& }; \& } .Ve .SS Class::Tiny::Antlers .IX Subsection "Class::Tiny::Antlers" Class::Tiny::Antlers provides Moose-like syntax for Class::Tiny, including support for \f(CW\*(C`isa\*(C'\fR. You do not also need to use Class::Tiny itself. .PP .Vb 4 \& package Horse { \& use Class::Tiny::Antlers qw(has); \& use Types::Standard qw( Str Num ArrayRef ); \& use namespace::autoclean; \& \& has name => ( \& is => \*(Aqro\*(Aq, \& isa => Str, \& default => sub { die "name is required" }, \& ); \& has gender => ( is => \*(Aqro\*(Aq, isa => Str ); \& has age => ( is => \*(Aqrw\*(Aq, isa => Num ); \& has children => ( \& is => \*(Aqro\*(Aq, \& isa => ArrayRef, \& default => sub { return [] }, \& ); \& } .Ve .SH "NEXT STEPS" .IX Header "NEXT STEPS" Here's your next step: .IP \(bu 4 Type::Tiny::Manual::UsingWithOther .Sp Using Type::Tiny with Class::InsideOut, Params::Check, and Object::Accessor. .SH AUTHOR .IX Header "AUTHOR" Toby Inkster . .SH "COPYRIGHT AND LICENCE" .IX Header "COPYRIGHT AND LICENCE" This software is copyright (c) 2013\-2014, 2017\-2023 by Toby Inkster. .PP This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. .SH "DISCLAIMER OF WARRANTIES" .IX Header "DISCLAIMER OF WARRANTIES" THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.