X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMooseX%2FTypes%2FTypeDecorator.pm;h=fdfaf4dd1984ed1d299f13047251f30ee83bc4c6;hb=12a9b8fe4f08bc0a7785831c34a27bb45f5bb8fb;hp=f39bd551466c07a13242138d841862993e0d1829;hpb=bb5b7b28b3e2fa8a6120e445ff58a0e377cf0806;p=gitmo%2FMooseX-Types.git diff --git a/lib/MooseX/Types/TypeDecorator.pm b/lib/MooseX/Types/TypeDecorator.pm index f39bd55..fdfaf4d 100644 --- a/lib/MooseX/Types/TypeDecorator.pm +++ b/lib/MooseX/Types/TypeDecorator.pm @@ -1,21 +1,49 @@ package MooseX::Types::TypeDecorator; +our $VERSION = "0.20"; use strict; use warnings; + use Carp::Clan qw( ^MooseX::Types ); -use Moose::Util::TypeConstraints; +use Moose::Util::TypeConstraints (); use Moose::Meta::TypeConstraint::Union; +use Scalar::Util qw(blessed); use overload( '""' => sub { - shift->type_constraint->name; + my $self = shift @_; + if(blessed $self) { + return $self->__type_constraint->name; + } else { + return "$self"; + } }, '|' => sub { - my @tc = grep {ref $_} @_; + + ## It's kind of ugly that we need to know about Union Types, but this + ## is needed for syntax compatibility. Maybe someday we'll all just do + ## Or[Str,Str,Int] + + my @args = @_[0,1]; ## arg 3 is special, see the overload docs. + my @tc = grep {blessed $_} map { + blessed $_ ? $_ : + Moose::Util::TypeConstraints::find_or_parse_type_constraint($_) + || __PACKAGE__->_throw_error( "$_ is not a type constraint") + } @args; + + ( scalar @tc == scalar @args) + || __PACKAGE__->_throw_error( + "one of your type constraints is bad. Passed: ". join(', ', @args) ." Got: ". join(', ', @tc)); + + ( scalar @tc >= 2 ) + || __PACKAGE__->_throw_error("You must pass in at least 2 type names to make a union"); + my $union = Moose::Meta::TypeConstraint::Union->new(type_constraints=>\@tc); return Moose::Util::TypeConstraints::register_type_constraint($union); }, + fallback => 1, + ); =head1 NAME @@ -38,31 +66,42 @@ Old school instantiation =cut sub new { - my ($class, %args) = @_; - if( - $args{type_constraint} && ref($args{type_constraint}) && - ($args{type_constraint}->isa('Moose::Meta::TypeConstraint') || - $args{type_constraint}->isa('MooseX::Types::UndefinedType')) - ) { - return bless \%args, $class; + my $class = shift @_; + if(my $arg = shift @_) { + if(blessed $arg && $arg->isa('Moose::Meta::TypeConstraint')) { + return bless {'__type_constraint'=>$arg}, $class; + } elsif( + blessed $arg && + $arg->isa('MooseX::Types::UndefinedType') + ) { + ## stub in case we'll need to handle these types differently + return bless {'__type_constraint'=>$arg}, $class; + } elsif(blessed $arg) { + __PACKAGE__->_throw_error("Argument must be ->isa('Moose::Meta::TypeConstraint') or ->isa('MooseX::Types::UndefinedType'), not ". blessed $arg); + } else { + __PACKAGE__->_throw_error("Argument cannot be '$arg'"); + } } else { - croak "The argument 'type_constraint' is not valid."; + __PACKAGE__->_throw_error("This method [new] requires a single argument."); } - } -=head type_constraint ($type_constraint) +=head2 __type_constraint ($type_constraint) Set/Get the type_constraint. =cut -sub type_constraint { - my $self = shift @_; - if(defined(my $tc = shift @_)) { - $self->{type_constraint} = $tc; +sub __type_constraint { + my $self = shift @_; + if(blessed $self) { + if(defined(my $tc = shift @_)) { + $self->{__type_constraint} = $tc; + } + return $self->{__type_constraint}; + } else { + __PACKAGE__->_throw_error('cannot call __type_constraint as a class method'); } - return $self->{type_constraint}; } =head2 isa @@ -72,15 +111,19 @@ handle $self->isa since AUTOLOAD can't. =cut sub isa { - my ($self, $target) = @_; + my ($self, $target) = @_; if(defined $target) { - my $isa = $self->type_constraint->isa($target); - return $isa; + if(blessed $self) { + return $self->__type_constraint->isa($target); + } else { + return; + } } else { return; } } + =head2 can handle $self->can since AUTOLOAD can't. @@ -90,13 +133,42 @@ handle $self->can since AUTOLOAD can't. sub can { my ($self, $target) = @_; if(defined $target) { - my $can = $self->type_constraint->can($target); - return $can; + if(blessed $self) { + return $self->__type_constraint->can($target); + } else { + return; + } } else { return; } } +=head2 meta + +have meta examine the underlying type constraints + +=cut + +sub meta { + my $self = shift @_; + if(blessed $self) { + return $self->__type_constraint->meta; + } +} + +=head2 _throw_error + +properly delegate error messages + +=cut + +sub _throw_error { + shift; + require Moose; + unshift @_, 'Moose'; + goto &Moose::throw_error; +} + =head2 DESTROY We might need it later @@ -114,13 +186,28 @@ Delegate to the decorator targe =cut sub AUTOLOAD { + + my ($self, @args) = @_; my ($method) = (our $AUTOLOAD =~ /([^:]+)$/); - return shift->type_constraint->$method(@_); + + ## We delegate with this method in an attempt to support a value of + ## __type_constraint which is also AUTOLOADing, in particular the class + ## MooseX::Types::UndefinedType which AUTOLOADs during autovivication. + + my $return; + + eval { + $return = $self->__type_constraint->$method(@args); + }; if($@) { + __PACKAGE__->_throw_error($@); + } else { + return $return; + } } -=head1 AUTHOR AND COPYRIGHT +=head1 AUTHOR -John Napiorkowski (jnapiorkowski) +See L. =head1 LICENSE