adding in the type constraint registry
Stevan Little [Mon, 10 Sep 2007 19:59:33 +0000 (19:59 +0000)]
Changes
PLANS
lib/Moose/Meta/TypeConstraint.pm
lib/Moose/Meta/TypeConstraint/Registry.pm [new file with mode: 0644]
lib/Moose/Util/TypeConstraints.pm

diff --git a/Changes b/Changes
index 451dee7..2fba568 100644 (file)
--- a/Changes
+++ b/Changes
@@ -7,8 +7,15 @@ Revision history for Perl extension Moose
       - added all the meta classes to the immutable list and 
         set it to inline the accessors
 
+    * Moose::Util::TypeConstraint
+      - no longer uses package variable to keep track of 
+        the type constraints, now uses the an instance of
+        Moose::Meta::TypeConstraint::Registry to do it
+
     * Moose::Meta::TypeConstraint
       - some minor adjustments to make subclassing easier
+      - added the package_defined_in attribute so that we 
+        can track where the type constraints are created
       
     * Moose::Meta::TypeConstraint::Union
       - this is not a subclass of Moose::Meta::TypeConstraint      
@@ -19,6 +26,9 @@ Revision history for Perl extension Moose
         to help construct nested collection types
         - added tests for this
     
+    * Moose::Meta::TypeConstraint::Registry
+      - added this class to keep track of type constraints
+    
     * Moose::Meta::Attribute
       Moose::Meta::Method::Constructor
       Moose::Meta::Method::Accessor
diff --git a/PLANS b/PLANS
index e009272..23ad296 100644 (file)
--- a/PLANS
+++ b/PLANS
@@ -39,12 +39,53 @@ The type checks can get expensive and some people have suggested that allowing
 the checks to be turned off would be helpful for deploying into performance 
 intensive systems. Perhaps this can actually be done as an option to make_immutable? 
 
+- add support for locally scoped TC
+
+This would borrow from MooseX::TypeLibrary to prefix the TC with the name 
+of the package. It would then be accesible from the outside as the fully 
+scoped name, but the local attributes would use it first. (this would need support 
+in the registry for this).
+
+- look into sugar extensions
+
+Use roles as sugar layer function providers (ala MooseX::AttributeHelpers). This 
+would allow custom metaclasses to provide roles to extend the sugar syntax with.
+
+(NOTE: Talk to phaylon a bit more on this)
+
 - misc. minor bits
 
 * make the errors for TCs use ->message
 * look into localizing the messages too
 * make ANON TCs be lazy, so they can possibly be subsituted for the real thing later
 * make ANON TCs more introspectable
+* add this ...
+
+#
+#   Type Definition
+#
+subtype 'Username',
+   from 'Str',
+  where {     (/[a-z][a-z0-9]+/i or fail('Invalid character(s)'))
+          and (length($_) >= 5   or fail('Too short (less than 5 chars)'))
+        }
+on_fail { MyException->throw(value => $_[0], message => $_[1]) };
+
+# fail() will just return false unless the call is made via
+$tc->check_or_fail($value);
+
+* and then something like this:
+
+subtype Foo => as Bar => where { ... } => scoped => -global;
+subtype Foo => as Bar => where { ... } => scoped => -local; 
+
+# or 
+
+subtype Foo => as Bar => where { ... } => in __PACKAGE__ ; 
+
+# or (not sure if it would be possible)
+
+my $Foo = subtype Bar => where { ... };
 
 
 -----------------------------------------------------------
index 7a7cddf..47cf32d 100644 (file)
@@ -44,6 +44,10 @@ __PACKAGE__->meta->add_attribute('hand_optimized_type_constraint' => (
     predicate => 'has_hand_optimized_type_constraint',    
 ));
 
+__PACKAGE__->meta->add_attribute('package_defined_in' => (
+    accessor => '_package_defined_in'
+));
+
 sub new { 
     my $class = shift;
     my $self  = $class->meta->new_object(@_);
diff --git a/lib/Moose/Meta/TypeConstraint/Registry.pm b/lib/Moose/Meta/TypeConstraint/Registry.pm
new file mode 100644 (file)
index 0000000..c1414d0
--- /dev/null
@@ -0,0 +1,92 @@
+
+package Moose::Meta::TypeConstraint::Registry;
+
+use strict;
+use warnings;
+use metaclass;
+
+use Scalar::Util 'blessed';
+use Carp         'confess';
+
+our $VERSION   = '0.01';
+our $AUTHORITY = 'cpan:STEVAN';
+
+use base 'Class::MOP::Object';
+
+__PACKAGE__->meta->add_attribute('type_constraints' => (
+    reader  => 'type_constraints',
+    default => sub { {} }
+));
+
+sub new { 
+    my $class = shift;
+    my $self  = $class->meta->new_object(@_);
+    return $self;
+}
+
+sub has_type_constraint {
+    my ($self, $type_name) = @_;
+    exists $self->type_constraints->{$type_name} ? 1 : 0
+}
+
+sub get_type_constraint {
+    my ($self, $type_name) = @_;
+    $self->type_constraints->{$type_name}
+}
+
+sub add_type_constraint {
+    my ($self, $type) = @_;
+    $self->type_constraints->{$type->name} = $type;
+}
+
+1;
+
+__END__
+
+
+=pod
+
+=head1 NAME
+
+Moose::Meta::TypeConstraint::Registry
+
+=head1 DESCRIPTION
+
+=head1 METHODS
+
+=over 4
+
+=item B<meta>
+
+=item B<new>
+
+=item B<type_constraints>
+
+=item B<has_type_constraint>
+
+=item B<get_type_constraint>
+
+=item B<add_type_constraint>
+
+=back
+
+=head1 BUGS
+
+All complex software has bugs lurking in it, and this module is no 
+exception. If you find a bug please either email me, or add the bug
+to cpan-RT.
+
+=head1 AUTHOR
+
+Stevan Little E<lt>stevan@iinteractive.comE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright 2006, 2007 by Infinity Interactive, Inc.
+
+L<http://www.iinteractive.com>
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=cut
index ef2d9d8..8dd8170 100644 (file)
@@ -9,7 +9,7 @@ use Scalar::Util 'blessed', 'reftype';
 use B            'svref_2object';
 use Sub::Exporter;
 
-our $VERSION   = '0.13';
+our $VERSION   = '0.14';
 our $AUTHORITY = 'cpan:STEVAN';
 
 # Prototyped subs must be predeclared because we have a circular dependency
@@ -34,6 +34,7 @@ sub enum ($;@);
 
 use Moose::Meta::TypeConstraint;
 use Moose::Meta::TypeCoercion;
+use Moose::Meta::TypeConstraint::Registry;
 
 my @exports = qw/
     type subtype as where message optimize_as
@@ -67,84 +68,90 @@ sub unimport {
     }
 }
 
-{
-    my %TYPES;
-    sub find_type_constraint ($) { 
-        return $TYPES{$_[0]}->[1] 
-            if exists $TYPES{$_[0]};
-        return;
-    }
-    
-    sub _dump_type_constraints {
-        require Data::Dumper;        
-        Data::Dumper::Dumper(\%TYPES);
-    }
-    
-    sub _create_type_constraint ($$$;$$) { 
-        my $name   = shift;
-        my $parent = shift;
-        my $check  = shift || sub { 1 };
-        
-        my ($message, $optimized);
-        for (@_) {
-            $message   = $_->{message}   if exists $_->{message};
-            $optimized = $_->{optimized} if exists $_->{optimized};            
-        }
+my $REGISTRY = Moose::Meta::TypeConstraint::Registry->new;
 
-        my $pkg_defined_in = scalar(caller(0));
-        
-        ($TYPES{$name}->[0] eq $pkg_defined_in)
-            || confess ("The type constraint '$name' has already been created in " 
-                       . $TYPES{$name}->[0] . " and cannot be created again in "
-                       . $pkg_defined_in)
-                 if defined $name && exists $TYPES{$name};   
-                              
-        $parent = find_type_constraint($parent) if defined $parent;
-        my $constraint = Moose::Meta::TypeConstraint->new(
-            name       => $name || '__ANON__',
-            parent     => $parent,            
-            constraint => $check,       
-            message    => $message,    
-            optimized  => $optimized,
-        );
-        $TYPES{$name} = [ $pkg_defined_in, $constraint ] if defined $name;
-        return $constraint;
-    }
+sub _get_type_constraint_registry { $REGISTRY }
+sub _dump_type_constraints        { $REGISTRY->dump }
 
-    sub _install_type_coercions ($$) { 
-        my ($type_name, $coercion_map) = @_;
-        my $type = find_type_constraint($type_name);
-        (!$type->has_coercion)
-            || confess "The type coercion for '$type_name' has already been registered";        
-        my $type_coercion = Moose::Meta::TypeCoercion->new(
-            type_coercion_map => $coercion_map,
-            type_constraint   => $type
-        );            
-        $type->coercion($type_coercion);
-    }
-    
-    sub create_type_constraint_union (@) {
-        my (@type_constraint_names) = @_;
-        return Moose::Meta::TypeConstraint->union(
-            map { 
-                find_type_constraint($_) 
-            } @type_constraint_names
-        );
-    }
+sub _create_type_constraint ($$$;$$) { 
+    my $name   = shift;
+    my $parent = shift;
+    my $check  = shift || sub { 1 };
     
-    sub export_type_constraints_as_functions {
-        my $pkg = caller();
-           no strict 'refs';
-       foreach my $constraint (keys %TYPES) {
-               *{"${pkg}::${constraint}"} = find_type_constraint($constraint)->_compiled_type_constraint;
-       }        
+    my ($message, $optimized);
+    for (@_) {
+        $message   = $_->{message}   if exists $_->{message};
+        $optimized = $_->{optimized} if exists $_->{optimized};            
     }
+
+    my $pkg_defined_in = scalar(caller(0));
     
-    *Moose::Util::TypeConstraints::export_type_contstraints_as_functions = \&export_type_constraints_as_functions;
+    if (defined $name) {
+        my $type = $REGISTRY->get_type_constraint($name);
     
-    sub list_all_type_constraints { keys %TYPES }   
+        ($type->_package_defined_in eq $pkg_defined_in)
+            || confess ("The type constraint '$name' has already been created in " 
+                       . $type->_package_defined_in . " and cannot be created again in "
+                       . $pkg_defined_in)
+                 if defined $type;   
+    }                    
+                          
+    $parent = $REGISTRY->get_type_constraint($parent) if defined $parent;
+    my $constraint = Moose::Meta::TypeConstraint->new(
+        name               => $name || '__ANON__',
+        parent             => $parent,            
+        constraint         => $check,       
+        message            => $message,    
+        optimized          => $optimized,
+        package_defined_in => $pkg_defined_in,
+    );
+
+    $REGISTRY->add_type_constraint($constraint)
+        if defined $name;
+
+    return $constraint;
+}
+
+sub _install_type_coercions ($$) { 
+    my ($type_name, $coercion_map) = @_;
+    my $type = $REGISTRY->get_type_constraint($type_name);
+    (!$type->has_coercion)
+        || confess "The type coercion for '$type_name' has already been registered";        
+    my $type_coercion = Moose::Meta::TypeCoercion->new(
+        type_coercion_map => $coercion_map,
+        type_constraint   => $type
+    );            
+    $type->coercion($type_coercion);
+}
+
+sub create_type_constraint_union (@) {
+    my (@type_constraint_names) = @_;
+    return Moose::Meta::TypeConstraint->union(
+        map { 
+            $REGISTRY->get_type_constraint($_) 
+        } @type_constraint_names
+    );
 }
 
+sub export_type_constraints_as_functions {
+    my $pkg = caller();
+    no strict 'refs';
+       foreach my $constraint (keys %{$REGISTRY->type_constraints}) {
+               *{"${pkg}::${constraint}"} = $REGISTRY->get_type_constraint($constraint)
+                                                     ->_compiled_type_constraint;
+       }        
+}
+
+*Moose::Util::TypeConstraints::export_type_contstraints_as_functions = \&export_type_constraints_as_functions;
+
+sub list_all_type_constraints { keys %{$REGISTRY->type_constraints} }   
+
+## --------------------------------------------------------
+## exported functions ...
+## --------------------------------------------------------
+
+sub find_type_constraint ($) { $REGISTRY->get_type_constraint(@_) }
+
 # type constructors
 
 sub type ($$;$$) {