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')
? $_
=> 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 }
);
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<HTTP::Headers> as a type
+directly. The reason we do this is coercions are global, and a
+coercion defined for C<HTTP::Headers> in our C<Request> class would
+then be defined for I<all> Moose-using classes in the current Perl
+interpreter. It's a L<best practice|Moose::Manual::BestPractices> to
+avoid this sort of namespace pollution.
-The C<class_type> sugar function is simply a shortcut for something
-like this:
+The C<class_type> sugar function is simply a shortcut for this:
subtype 'HTTP::Headers'
=> as 'Object'
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'
has 'headers' => (
is => 'rw',
- isa => 'Header',
+ isa => 'My.HTTP::Headers',
coerce => 1,
default => sub { HTTP::Headers->new }
);
Once again, we need to declare a class type for our non-Moose L<URI>
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')
? $_
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.
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')
? $_
=> 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 }
);