X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMoose%2FManual%2FTypes.pod;h=330edb594306a624f51c8ad05aca3c566893c3d6;hb=970a92fa56f1ea409c8d7c5428392479292fd8d4;hp=6fa9753871046b2ffa9d607f4bed51f1999f937a;hpb=636f25f3bcd1033be8cf71f6dd073b95fa3b50f7;p=gitmo%2FMoose.git diff --git a/lib/Moose/Manual/Types.pod b/lib/Moose/Manual/Types.pod index 6fa9753..330edb5 100644 --- a/lib/Moose/Manual/Types.pod +++ b/lib/Moose/Manual/Types.pod @@ -2,7 +2,7 @@ =head1 NAME -Moose::Manual::Types - Moose's Type System +Moose::Manual::Types - Moose's type system =head1 TYPES IN PERL? @@ -11,17 +11,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 @@ -39,27 +38,54 @@ The basic Moose type hierarchy looks like this Undef Defined Value - Num - Int Str - ClassName + Num + Int + ClassName + RoleName Ref - ScalarRef + ScalarRef[`a] ArrayRef[`a] HashRef[`a] CodeRef RegexpRef GlobRef - FileHandle + FileHandle Object - Role 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 @@ -68,7 +94,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. @@ -78,7 +104,7 @@ L. It's important to realize that types are not classes (or packages). Types are just objects (L objects, to be exact) with a name and a constraint. Moose maintains a -global type registry that lets it convert names like "Num" into the +global type registry that lets it convert names like C into the appropriate object. However, class names I type names. When you define a new class @@ -91,7 +117,7 @@ using Moose, it defines an associated type name behind the scenes: Now you can use C<'MyApp::User'> as a type name: has creator => ( - is => 'rw', + is => 'ro', isa => 'MyApp::User', ); @@ -101,7 +127,7 @@ assumes that any unknown type name passed as the C value for an attribute is a class. So this works: has 'birth_date' => ( - is => 'rw', + is => 'ro', isa => 'DateTime', ); @@ -118,18 +144,18 @@ that the name is a class: isa => 'ArrayRef[DateTime]', ); -Moose will assume that "DateTime" is a class name in both of these +Moose will assume that C is a class name in both of these instances. =head1 SUBTYPES -Moose uses subtypes in its built-in hierarchy. C is a child of -C for example. +Moose uses subtypes in its built-in hierarchy. For example, C is +a child of C. A subtype is defined in terms of a parent type and a constraint. Any -constraints defined by the parent(s) will be checked first, and then -the the subtype's . A value must pass I of these checks to be -valid for the subtype. +constraints defined by the parent(s) will be checked first, followed by +constraints defined by the subtype. A value must pass I of these +checks to be valid for the subtype. Typically, a subtype takes the parent's constraint and makes it more specific. @@ -150,21 +176,6 @@ Here's a simple (and useful) subtype example: 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 @@ -177,21 +188,28 @@ you prefix names with some sort of namespace indicator to prevent these sorts of collisions. For example, instead of calling a type "PositiveInt", call it -"MyApp.Type.PositiveInt". +"MyApp::Type::PositiveInt" or "MyApp::Types::PositiveInt". We +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 write easily create parameterized types: -Type names are just strings. We recommend that you I use "::" -as a separator in type names. This can be very confusing, because -class names are I valid type names! Using something else, like a -period, makes it clear that "MyApp::User" is a class and -"MyApp.Type.PositiveInt" is a Moose type defined by your application. + has 'counts' => (is => 'ro', isa => HashRef[PositiveInt]); -The C module lets you create bareword aliases to longer -names and also automatically namespaces all the types you define. +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]'; @@ -200,19 +218,21 @@ coercions. A coercion is a way to convert from one type to another. => 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 parameter 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; has 'sizes' => ( - is => 'rw', + is => 'ro', isa => 'ArrayRefOfInts', coerce => 1, ); @@ -222,7 +242,7 @@ C attribute parameter to a true value: This code example will do the right thing, and the newly created object will have C<[ 42 ]> as its C attribute. -=head2 Deep Coercion +=head2 Deep coercion Deep coercion is the coercion of type parameters for parameterized types. Let's take these types as an example: @@ -236,7 +256,7 @@ types. Let's take these types as an example: => via { hex $_ }; has 'sizes' => ( - is => 'rw', + is => 'ro', isa => 'ArrayRef[Int]', coerce => 1, ); @@ -261,7 +281,7 @@ two parameterized types. 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: @@ -306,7 +326,7 @@ with a simple wrapper class: use Moose; has 'handle' => ( - is => 'ro', + is => 'rw', isa => 'FileHandle', ); @@ -314,7 +334,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: @@ -344,17 +364,17 @@ subtype of C that only allows the specified values: enum 'RGB' => qw( red green blue ); -This creates a type named C +This creates a type named C. =head1 ANONYMOUS TYPES All of the type creation functions return a type object. This type object can be used wherever you would use a type name, as a parent -type, or as the value for an attribute's C parameter: +type, or as the value for an attribute's C option: has 'size' => ( - is => 'rw', - 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 @@ -366,7 +386,7 @@ Moose does not provide any means of validating method parameters. However, there are several MooseX extensions on CPAN which let you do this. -The simplest and least sugary is C. This +The simplest and least sugary is L. This lets you validate a set of named parameters using Moose types: use Moose; @@ -381,14 +401,14 @@ lets you validate a set of named parameters using Moose types: ... } -C also supports coercions. +L also supports coercions. There are several more powerful extensions that support method parameter validation using Moose types, including -C, which gives you a full-blown C +L, which gives you a full-blown C keyword. - method morning (Str $name) { + method morning ( Str $name ) { $self->say("Good morning ${name}!"); } @@ -398,20 +418,9 @@ 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. +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. =head1 AUTHOR