X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMouse%2FTypeRegistry.pm;h=a10e7a4c04b842bd6408bb801af1b287a15e351e;hb=8aeec00e16ce77ccab0e5222106b2b83979edb5f;hp=70f00acab1072641c37ca3617eb97d35081e3562;hpb=5439cf977dec83dafef4ee1cc990e7850d308cd0;p=gitmo%2FMouse.git diff --git a/lib/Mouse/TypeRegistry.pm b/lib/Mouse/TypeRegistry.pm index 70f00ac..a10e7a4 100644 --- a/lib/Mouse/TypeRegistry.pm +++ b/lib/Mouse/TypeRegistry.pm @@ -1,13 +1,13 @@ -#!/usr/bin/env perl package Mouse::TypeRegistry; use strict; use warnings; use Carp (); -use Mouse::Util qw/blessed looks_like_number openhandle/; +use Scalar::Util qw/blessed looks_like_number openhandle/; -my $SUBTYPE = +{}; -my $COERCE = +{}; +my %SUBTYPE; +my %COERCE; +my %COERCE_KEYS; #find_type_constraint register_type_constraint sub import { @@ -43,34 +43,82 @@ sub _via (&) { $_[0] } +my $optimized_constraints; +my $optimized_constraints_base; +{ + no warnings 'uninitialized'; + %SUBTYPE = ( + Any => sub { 1 }, + Item => sub { 1 }, + Bool => sub { + !defined($_) || $_ eq "" || "$_" eq '1' || "$_" eq '0' + }, + Undef => sub { !defined($_) }, + Defined => sub { defined($_) }, + Value => sub { defined($_) && !ref($_) }, + Num => sub { !ref($_) && looks_like_number($_) }, + Int => sub { defined($_) && !ref($_) && /^-?[0-9]+$/ }, + Str => sub { defined($_) && !ref($_) }, + ClassName => sub { Mouse::is_class_loaded($_) }, + Ref => sub { ref($_) }, + + ScalarRef => sub { ref($_) eq 'SCALAR' }, + ArrayRef => sub { ref($_) eq 'ARRAY' }, + HashRef => sub { ref($_) eq 'HASH' }, + CodeRef => sub { ref($_) eq 'CODE' }, + RegexpRef => sub { ref($_) eq 'Regexp' }, + GlobRef => sub { ref($_) eq 'GLOB' }, + + FileHandle => sub { + ref($_) eq 'GLOB' + && openhandle($_) + or + blessed($_) + && $_->isa("IO::Handle") + }, + + Object => sub { blessed($_) && blessed($_) ne 'Regexp' }, + ); + + sub optimized_constraints { \%SUBTYPE } + my @SUBTYPE_KEYS = keys %SUBTYPE; + sub list_all_builtin_type_constraints { @SUBTYPE_KEYS } +} + sub _subtype { my $pkg = caller(0); my($name, %conf) = @_; - if (my $type = $SUBTYPE->{$name}) { + if (my $type = $SUBTYPE{$name}) { Carp::croak "The type constraint '$name' has already been created, cannot be created again in $pkg"; }; - my $as = $conf{as}; - my $stuff = $conf{where} || optimized_constraints()->{$as}; - - $SUBTYPE->{$name} = $stuff; + my $stuff = $conf{where} || do { $SUBTYPE{delete $conf{as} || 'Any' } }; + my $as = $conf{as} || ''; + if ($as = $SUBTYPE{$as}) { + $SUBTYPE{$name} = sub { $as->($_) && $stuff->($_) }; + } else { + $SUBTYPE{$name} = $stuff; + } } sub _coerce { my($name, %conf) = @_; Carp::croak "Cannot find type '$name', perhaps you forgot to load it." - unless optimized_constraints()->{$name}; + unless $SUBTYPE{$name}; - my $subtypes = optimized_constraints(); - $COERCE->{$name} ||= {}; + unless ($COERCE{$name}) { + $COERCE{$name} = {}; + $COERCE_KEYS{$name} = []; + } while (my($type, $code) = each %conf) { Carp::croak "A coercion action already exists for '$type'" - if $COERCE->{$name}->{$type}; + if $COERCE{$name}->{$type}; Carp::croak "Could not find the type constraint ($type) to coerce from" - unless $subtypes->{$type}; + unless $SUBTYPE{$type}; - $COERCE->{$name}->{$type} = $code; + push @{ $COERCE_KEYS{$name} }, $type; + $COERCE{$name}->{$type} = $code; } } @@ -78,10 +126,9 @@ sub _class_type { my $pkg = caller(0); my($name, $conf) = @_; my $class = $conf->{class}; + Mouse::load_class($class); _subtype( - $name => where => sub { - defined $_ && ref($_) eq $class; - } + $name => where => sub { $_->isa($class) } ); } @@ -97,61 +144,22 @@ sub _role_type { } sub typecast_constraints { - my($class, $pkg, $type, $value) = @_; - return $value unless $COERCE->{$type}; - - my $optimized_constraints = optimized_constraints(); - for my $coerce_type (keys %{ $COERCE->{$type} }) { - local $_ = $value; - if ($optimized_constraints->{$coerce_type}->()) { - local $_ = $value; - return $COERCE->{$type}->{$coerce_type}->(); + my($class, $pkg, $type_constraint, $types, $value) = @_; + + local $_; + for my $type (ref($types) eq 'ARRAY' ? @{ $types } : ( $types )) { + next unless $COERCE{$type}; + for my $coerce_type (@{ $COERCE_KEYS{$type}}) { + $_ = $value; + next unless $SUBTYPE{$coerce_type}->(); + $_ = $value; + $_ = $COERCE{$type}->{$coerce_type}->(); + return $_ if $type_constraint->(); } } - return $value; } -{ - no warnings 'uninitialized'; - my $optimized_constraints = { - Any => sub { 1 }, - Item => sub { 1 }, - Bool => sub { - !defined($_) || $_ eq "" || "$_" eq '1' || "$_" eq '0' - }, - Undef => sub { !defined($_) }, - Defined => sub { defined($_) }, - Value => sub { defined($_) && !ref($_) }, - Num => sub { !ref($_) && looks_like_number($_) }, - Int => sub { defined($_) && !ref($_) && /^-?[0-9]+$/ }, - Str => sub { defined($_) && !ref($_) }, - ClassName => sub { Mouse::is_class_loaded($_) }, - Ref => sub { ref($_) }, - - ScalarRef => sub { ref($_) eq 'SCALAR' }, - ArrayRef => sub { ref($_) eq 'ARRAY' }, - HashRef => sub { ref($_) eq 'HASH' }, - CodeRef => sub { ref($_) eq 'CODE' }, - RegexpRef => sub { ref($_) eq 'Regexp' }, - GlobRef => sub { ref($_) eq 'GLOB' }, - - FileHandle => sub { - ref($_) eq 'GLOB' - && openhandle($_) - or - blessed($_) - && $_->isa("IO::Handle") - }, - - Object => sub { blessed($_) && blessed($_) ne 'Regexp' }, - }; - sub list_all_builtin_type_constraints { keys %{ $optimized_constraints } } - sub optimized_constraints { - return { %{ $SUBTYPE }, %{ $optimized_constraints } }; - } -} - 1; __END__