From: Dave Rolsky Date: Wed, 11 Feb 2009 19:31:37 +0000 (+0000) Subject: Don't define a coercion directly to a class like URI. Make a subtype X-Git-Tag: 0.69~22 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=3a4bb3ecba2480afb1d069aba9bb5e7da0bcb1a2;p=gitmo%2FMoose.git Don't define a coercion directly to a class like URI. Make a subtype and coerce that instead. --- diff --git a/lib/Moose/Cookbook/Basics/Recipe5.pod b/lib/Moose/Cookbook/Basics/Recipe5.pod index 2f0208d..a16f60d 100644 --- a/lib/Moose/Cookbook/Basics/Recipe5.pod +++ b/lib/Moose/Cookbook/Basics/Recipe5.pod @@ -15,17 +15,17 @@ Moose::Cookbook::Basics::Recipe5 - More subtypes, coercion in a B class use Params::Coerce (); use URI (); - class_type('HTTP::Headers'); + subtype 'My.HTTP::Headers' => as class_type('HTTP::Headers'); - coerce 'HTTP::Headers' + coerce 'My.HTTP::Headers' => from 'ArrayRef' => via { HTTP::Headers->new( @{$_} ) } => from 'HashRef' => via { HTTP::Headers->new( %{$_} ) }; - class_type('URI'); + subtype 'My.URI' => as class_type('HTTP::Headers'); - coerce 'URI' + coerce 'My.URI' => from 'Object' => via { $_->isa('URI') ? $_ @@ -37,13 +37,13 @@ Moose::Cookbook::Basics::Recipe5 - More subtypes, coercion in a B class => as 'Str' => where { /^HTTP\/[0-9]\.[0-9]$/ }; - has 'base' => ( is => 'rw', isa => 'URI', coerce => 1 ); - has 'uri' => ( is => 'rw', isa => 'URI', coerce => 1 ); + has 'base' => ( is => 'rw', isa => 'My.URI', coerce => 1 ); + has 'uri' => ( is => 'rw', isa => 'My.URI', coerce => 1 ); has 'method' => ( is => 'rw', isa => 'Str' ); has 'protocol' => ( is => 'rw', isa => 'Protocol' ); has 'headers' => ( is => 'rw', - isa => 'HTTP::Headers', + isa => 'My.HTTP::Headers', coerce => 1, default => sub { HTTP::Headers->new } ); @@ -61,10 +61,16 @@ set the C attribute parameter to a true value. First, we create the subtype to which we will coerce the other types: - class_type('HTTP::Headers'); + subtype 'My.HTTP::Headers' => as class_type('HTTP::Headers'); + +We are creating a subtype rather than using C as a type +directly. The reason we do this is coercions are global, and a +coercion defined for C in our C class would +then be defined for I Moose-using classes in the current Perl +interpreter. It's a L to +avoid this sort of namespace pollution. -The C sugar function is simply a shortcut for something -like this: +The C sugar function is simply a shortcut for this: subtype 'HTTP::Headers' => as 'Object' @@ -92,7 +98,7 @@ to accept those data structure instead of an B instance, and just do the right thing. This is exactly what coercion is for: - coerce 'HTTP::Headers' + coerce 'My.HTTP::Headers' => from 'ArrayRef' => via { HTTP::Headers->new( @{$_} ) } => from 'HashRef' @@ -108,7 +114,7 @@ we want a particular attribute to be coerced: has 'headers' => ( is => 'rw', - isa => 'Header', + isa => 'My.HTTP::Headers', coerce => 1, default => sub { HTTP::Headers->new } ); @@ -131,11 +137,11 @@ help implement coercions. In this case we use L. Once again, we need to declare a class type for our non-Moose L class: - class_type('URI'); + subtype 'My.URI' => as class_type('HTTP::Headers'); Then we define the coercion: - coerce 'URI' + coerce 'My.URI' => from 'Object' => via { $_->isa('URI') ? $_ @@ -158,8 +164,8 @@ string is assumed to be an C URI. Finally, we need to make sure our attributes enable coercion. - has 'base' => ( is => 'rw', isa => 'URI', coerce => 1 ); - has 'uri' => ( is => 'rw', isa => 'URI', coerce => 1 ); + has 'base' => ( is => 'rw', isa => 'My.URI', coerce => 1 ); + has 'uri' => ( is => 'rw', isa => 'My.URI', coerce => 1 ); Re-using the coercion lets us enforce a consistent API across multiple attributes. diff --git a/t/000_recipes/basics/005_coercion.t b/t/000_recipes/basics/005_coercion.t index d45cf69..224c084 100644 --- a/t/000_recipes/basics/005_coercion.t +++ b/t/000_recipes/basics/005_coercion.t @@ -22,17 +22,17 @@ use Test::Exception; use Params::Coerce (); use URI (); - class_type('HTTP::Headers'); + subtype 'My.HTTP::Headers' => as class_type('HTTP::Headers'); - coerce 'HTTP::Headers' + coerce 'My.HTTP::Headers' => from 'ArrayRef' => via { HTTP::Headers->new( @{$_} ) } => from 'HashRef' => via { HTTP::Headers->new( %{$_} ) }; - class_type('URI'); + subtype 'My.URI' => as class_type('HTTP::Headers'); - coerce 'URI' + coerce 'My.URI' => from 'Object' => via { $_->isa('URI') ? $_ @@ -44,13 +44,13 @@ use Test::Exception; => as 'Str' => where { /^HTTP\/[0-9]\.[0-9]$/ }; - has 'base' => ( is => 'rw', isa => 'URI', coerce => 1 ); - has 'uri' => ( is => 'rw', isa => 'URI', coerce => 1 ); + has 'base' => ( is => 'rw', isa => 'My.URI', coerce => 1 ); + has 'uri' => ( is => 'rw', isa => 'My.URI', coerce => 1 ); has 'method' => ( is => 'rw', isa => 'Str' ); has 'protocol' => ( is => 'rw', isa => 'Protocol' ); has 'headers' => ( is => 'rw', - isa => 'HTTP::Headers', + isa => 'My.HTTP::Headers', coerce => 1, default => sub { HTTP::Headers->new } );