X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMoose%2FManual%2FTypes.pod;h=1b54e6534cbc50c0519aea253e8b08e6632e017e;hb=b8d7a95f57f36d24ad4d15ffd6f4ca195f4d5eaf;hp=7b623d17e68344f3cb80535180f0b8d00ff63191;hpb=dab940632264ba728cdd882436a2c972f001fecf;p=gitmo%2FMoose.git diff --git a/lib/Moose/Manual/Types.pod b/lib/Moose/Manual/Types.pod index 7b623d1..1b54e65 100644 --- a/lib/Moose/Manual/Types.pod +++ b/lib/Moose/Manual/Types.pod @@ -1,8 +1,10 @@ -=pod +package Moose::Manual::Types; + +# ABSTRACT: Moose's type system -=head1 NAME +__END__ -Moose::Manual::Types - Moose's type system +=pod =head1 TYPES IN PERL? @@ -11,17 +13,16 @@ these types to validate method parameters with the help of a MooseX module. Moose's type system is based on a combination of Perl 5's own -I types and some Perl 6 concepts. You can easily create your +I types and some Perl 6 concepts. You can create your own subtypes with custom constraints, making it easy to express any sort of validation. Types have names, and you can re-use them by name, making it easy to share types throughout a large application. -Let us be clear that is not a "real" type system. Moose does not -magically make Perl start associating types with variables. This is -just an advanced parameter checking system which allows you to -associate a name with a constraint. +However, this is not a "real" type system. Moose does not magically make Perl +start associating types with variables. This is just an advanced parameter +checking system which allows you to associate a name with a constraint. That said, it's still pretty damn useful, and we think it's one of the things that makes Moose both fun and powerful. Taking advantage of the @@ -33,34 +34,60 @@ data, and it also contributes greatly to code maintainability. The basic Moose type hierarchy looks like this Any - Item - Bool - Maybe[`a] - Undef - Defined - Value - Num - Int - Str - ClassName - RoleName - Ref - ScalarRef - ArrayRef[`a] - HashRef[`a] - CodeRef - RegexpRef - GlobRef - FileHandle - Object - Role + Item + Bool + Maybe[`a] + Undef + Defined + Value + Str + Num + Int + ClassName + RoleName + Ref + ScalarRef[`a] + ArrayRef[`a] + HashRef[`a] + CodeRef + RegexpRef + GlobRef + FileHandle + Object In practice, the only difference between C and C is conceptual. C is used as the top-level type in the hierarchy. -The rest of these types correspond to existing Perl concepts. For -example, a C is anything that Perl thinks looks like a number, an -C is a blessed reference, etc. +The rest of these types correspond to existing Perl concepts. +In particular: + +=over 4 + +=item + +C accepts C<1> for true, and undef, 0, or the empty string as false. + +=item + +C accepts either C<`a> or C. + +=item + +C accepts anything that perl thinks looks like a number (see L). + +=item + +C and C accept strings that are either the name of a class or the name of a role. The class/role must already be loaded when the constraint is checked. + +=item + +C accepts either an L object or a builtin perl filehandle (see L). + +=item + +C accepts any blessed reference. + +=back The types followed by "[`a]" can be parameterized. So instead of just plain C we can say that we want C instead. We @@ -69,7 +96,7 @@ can even do something like C. The C type deserves a special mention. Used by itself, it doesn't really mean anything (and is equivalent to C). When it is parameterized, it means that the value is either C or the -parameterized type. So C means an integer or C +parameterized type. So C means an integer or C. For more details on the type hierarchy, see L. @@ -139,33 +166,20 @@ A subtype can also define its own constraint failure message. This lets you do things like have an error "The value you provided (20), was not a valid rating, which must be a number from 1-10." This is much friendlier than the default error, which just says that the value -failed a validation check for the type. +failed a validation check for the type. The default error can, however, +be made more friendly by installing L (version 0.14 or +higher), which Moose will use if possible to display the invalid value. Here's a simple (and useful) subtype example: - subtype 'PositiveInt' - => as 'Int' - => where { $_ > 0 } - => message { "The number you provided, $_, was not a positive number" } + subtype 'PositiveInt', + as 'Int', + where { $_ > 0 }, + message { "The number you provided, $_, was not a positive number" }; Note that the sugar functions for working with types are all exported by L. -=head2 Creating a new type (that isn't a subtype) - -You can also create new top-level types: - - type 'FourCharacters' => where { defined $_ && length $_ == 4 }; - -In practice, this example is more or less the same as subtyping -C, except you have to check definedness yourself. - -It's hard to find a case where you wouldn't want to subtype a very -broad type like C, C or C. - -Defining a new top-level type is conceptually the same as subtyping -C. - =head1 TYPE NAMES Type names are global throughout the current Perl @@ -183,26 +197,41 @@ recommend that you centralize all of these definitions in a single package, C, which can be loaded by other classes in your application. +However, before you do this, you should look at the L +module. This module makes it easy to create a "type library" module, which can +export your types as perl constants. + + has 'counter' => (is => 'rw', isa => PositiveInt); + +This lets you use a short name rather than needing to fully qualify the name +everywhere. It also allows you to easily create parameterized types: + + has 'counts' => (is => 'ro', isa => HashRef[PositiveInt]); + +This module will check your names at compile time, and is generally more +robust than the string type parsing for complex cases. + =head1 COERCION -One of the most powerful features of Moose's type system is its -coercions. A coercion is a way to convert from one type to another. +A coercion lets you tell Moose to automatically convert one type to another. - subtype 'ArrayRefOfInts' - => as 'ArrayRef[Int]'; + subtype 'ArrayRefOfInts', + as 'ArrayRef[Int]'; - coerce 'ArrayRefOfInts' - => from 'Int' - => via { [ $_ ] }; + coerce 'ArrayRefOfInts', + from 'Int', + via { [ $_ ] }; -You'll note that we had to create a subtype rather than coercing -C directly. This is just a quirk of how Moose -works. +You'll note that we created a subtype rather than coercing C +directly. It's a bad idea to add coercions to the raw built in +types. -Coercions, like type names, are global. This is I reason why -it is good to namespace your types. Moose will I try to coerce -a value unless you explicitly ask for it. This is done by setting the -C attribute option to a true value: +Coercions are global, just like type names, so a coercion applied to a built +in type is seen by all modules using Moose types. This is I reason +why it is good to namespace your types. + +Moose will I try to coerce a value unless you explicitly ask for +it. This is done by setting the C attribute option to a true value: package Foo; @@ -222,13 +251,13 @@ object will have C<[ 42 ]> as its C attribute. Deep coercion is the coercion of type parameters for parameterized types. Let's take these types as an example: - subtype 'HexNum' - => as 'Str' - => where { /[a-f0-9]/i }; + subtype 'HexNum', + as 'Str', + where { /[a-f0-9]/i }; - coerce 'Int' - => from 'HexNum' - => via { hex $_ }; + coerce 'Int', + from 'HexNum', + via { hex $_ }; has 'sizes' => ( is => 'ro', @@ -242,27 +271,27 @@ attribute, Moose will not do any coercion. However, you can define a set of subtypes to enable coercion between two parameterized types. - subtype 'ArrayRefOfHexNums' - => as 'ArrayRef[HexNum]'; + subtype 'ArrayRefOfHexNums', + as 'ArrayRef[HexNum]'; - subtype 'ArrayRefOfInts' - => as 'ArrayRef[Int]'; + subtype 'ArrayRefOfInts', + as 'ArrayRef[Int]'; - coerce 'ArrayRefOfInts' - => from 'ArrayRefOfHexNums' - => via { [ map { hex } @{$_} ] }; + coerce 'ArrayRefOfInts', + from 'ArrayRefOfHexNums', + via { [ map { hex } @{$_} ] }; Foo->new( sizes => [ 'a1', 'ff', '22' ] ); Now Moose will coerce the hex numbers to integers. -However, Moose does not attempt to chain coercions, so it will not +Moose does not attempt to chain coercions, so it will not coerce a single hex number. To do that, we need to define a separate coercion: - coerce 'ArrayRefOfInts' - => from 'HexNum' - => via { [ hex $_ ] }; + coerce 'ArrayRefOfInts', + from 'HexNum', + via { [ hex $_ ] }; Yes, this can all get verbose, but coercion is tricky magic, and we think it's best to make it explicit. @@ -289,9 +318,7 @@ coercion might be a better answer. For our example above, we might want to be more specific, and insist that output be an object with a C method: - subtype 'CanPrint' - => as 'Object' - => where { $_->can('print') }; + duck_type 'CanPrint', [qw(print)]; We can coerce file handles to an object that satisfies this condition with a simple wrapper class: @@ -309,7 +336,7 @@ with a simple wrapper class: my $self = shift; my $fh = $self->handle(); - print $fh @_; + print {$fh} @_; } Now we can define a coercion from C to our wrapper class: @@ -331,13 +358,13 @@ make your class internals simpler. The L module exports a number of helper functions for creating specific kinds of types. These include -C, C, and C. See the docs for -details. +C, C, C, and C. See the +docs for details. One helper worth noting is C, which allows you to create a subtype of C that only allows the specified values: - enum 'RGB' => qw( red green blue ); + enum 'RGB', [qw( red green blue )]; This creates a type named C. @@ -348,8 +375,8 @@ object can be used wherever you would use a type name, as a parent type, or as the value for an attribute's C option: has 'size' => ( - is => 'ro', - isa => subtype 'Int' => where { $_ > 0 }, + is => 'ro', + isa => subtype( 'Int' => where { $_ > 0 } ), ); This is handy when you want to create a one-off type and don't want to @@ -383,7 +410,7 @@ parameter validation using Moose types, including L, which gives you a full-blown C keyword. - method morning (Str $name) { + method morning ( Str $name ) { $self->say("Good morning ${name}!"); } @@ -393,32 +420,8 @@ Because Moose types are defined at runtime, you may run into load order problems. In particular, you may want to use a class's type constraint before that type has been defined. -We have several recommendations for ameliorating this problem. First, -define I of your custom types in one module, -C. Second, load this module in all of your other -modules. - -If you are still having load order problems, you can make use of the -C function exported by -L: - - class_type('MyApp::User') - unless find_type_constraint('MyApp::User') || ; - -This sort of "find or create" logic is simple to write, and will let -you work around load order issues. - -=head1 AUTHOR - -Dave Rolsky Eautarch@urth.orgE - -=head1 COPYRIGHT AND LICENSE - -Copyright 2009 by Infinity Interactive, Inc. - -L - -This library is free software; you can redistribute it and/or modify -it under the same terms as Perl itself. +In order to ameliorate this problem, we recommend defining I of your +custom types in one module, C, and then loading this module in +all of your other modules. =cut