MOOOOOOOOOOOOOOSE
Stevan Little [Sat, 18 Mar 2006 05:42:16 +0000 (05:42 +0000)]
Build.PL
lib/Moose.pm
lib/Moose/Meta/Attribute.pm
lib/Moose/Meta/Class.pm
lib/Moose/Object.pm
lib/Moose/Util/TypeConstraints.pm
t/004_basic.t [new file with mode: 0644]

index d9c09bb..9bc5aed 100644 (file)
--- a/Build.PL
+++ b/Build.PL
@@ -16,6 +16,8 @@ my $build = Module::Build->new(
     build_requires => {
         'Test::More'      => '0.47',
         'Test::Exception' => '0.21',
+        'Locale::US'      => '0',
+        'Regexp::Common'  => '0',
     },
     create_makefile_pl => 'traditional',
     recursive_test_files => 1,
index 01564eb..67434ea 100644 (file)
@@ -1,4 +1,6 @@
 
+use lib '/Users/stevan/Projects/CPAN/Class-MOP/Class-MOP/lib';
+
 package Moose;
 
 use strict;
@@ -30,7 +32,7 @@ sub import {
        return if $pkg eq 'main';
        
        Moose::Util::TypeConstraints->import($pkg);
-       
+
        my $meta;
        if ($pkg->can('meta')) {
                $meta = $pkg->meta();
@@ -96,15 +98,15 @@ sub import {
                my $code = pop @_;
                $meta->add_around_method_modifier($_, $code) for @_;    
        });     
-       
+
        # make sure they inherit from Moose::Object
-       $meta->superclasses('Moose::Object') 
-               unless $meta->superclasses();
+       $meta->superclasses('Moose::Object')
+       unless $meta->superclasses();
 
        # we recommend using these things 
        # so export them for them
-       $meta->alias_method('confess' => \&confess);                    
-       $meta->alias_method('blessed' => \&blessed);                            
+       $meta->alias_method('confess' => \&Carp::confess);                      
+       $meta->alias_method('blessed' => \&Scalar::Util::blessed);                              
 }
 
 1;
@@ -175,26 +177,40 @@ more :)
 
 =over 4
 
-=item Makes Other Object Systems Envious
+=item Make Other Object Systems Envious
 
 =item Makes Object Orientation So Easy
 
-=item Makes Object Orientation Sound Easy
+=item Makes Object Orientation Spiffy- Er  (sorry ingy)
 
-=item Makes Object Orientation Spiffy- Er
+=item Most Other Object Systems Emasculate
 
 =item My Overcraft Overfilled (with) Some Eels
 
 =item Moose Often Ovulate Sorta Early
 
-=item Most Other Object Systems Emasculate
-
 =item Many Overloaded Object Systems Exists 
 
 =item Moose Offers Often Super Extensions
 
 =back
 
+=head1 ACKNOWLEDGEMENTS
+
+=over 4
+
+=item I blame Sam Vilain for giving me my first hit of meta-model crack.
+
+=item I blame Audrey Tang for encouraging that meta-crack habit in #perl6.
+
+=item Without the love and encouragement of Yuval "nothingmuch" Kogman, 
+this module would not be possible (and it wouldn't have a name).
+
+=item The basis of the TypeContraints module was Rob Kinyon's idea 
+originally, I just ran with it.
+
+=back
+
 =head1 BUGS
 
 All complex software has bugs lurking in it, and this module is no 
index 2d59ce1..5c4af2f 100644 (file)
@@ -9,7 +9,7 @@ use Carp         'confess';
 
 use Moose::Util::TypeConstraints ':no_export';
 
-our $VERSION = '0.01';
+our $VERSION = '0.02';
 
 use base 'Class::MOP::Attribute';
 
@@ -43,7 +43,7 @@ sub generate_accessor_method {
                    return sub {
                                if (scalar(@_) == 2) {
                                        (defined $self->type_constraint->($_[1]))
-                                               || confess "Attribute ($attr_name) does not pass the type contraint"
+                                               || confess "Attribute ($attr_name) does not pass the type contraint with '$_[1]'"
                                                        if defined $_[1];
                                $_[0]->{$attr_name} = $_[1];
                                        weaken($_[0]->{$attr_name});
@@ -55,7 +55,7 @@ sub generate_accessor_method {
                    return sub {
                                if (scalar(@_) == 2) {
                                        (defined $self->type_constraint->($_[1]))
-                                               || confess "Attribute ($attr_name) does not pass the type contraint"
+                                               || confess "Attribute ($attr_name) does not pass the type contraint with '$_[1]'"
                                                        if defined $_[1];
                                $_[0]->{$attr_name} = $_[1];
                                }
@@ -88,7 +88,7 @@ sub generate_writer_method {
                if ($self->has_weak_ref) {
                    return sub { 
                                (defined $self->type_constraint->($_[1]))
-                                       || confess "Attribute ($attr_name) does not pass the type contraint"
+                                       || confess "Attribute ($attr_name) does not pass the type contraint with '$_[1]'"
                                                if defined $_[1];
                                $_[0]->{$attr_name} = $_[1];
                                weaken($_[0]->{$attr_name});
@@ -97,7 +97,7 @@ sub generate_writer_method {
                else {
                    return sub { 
                                (defined $self->type_constraint->($_[1]))
-                                       || confess "Attribute ($attr_name) does not pass the type contraint"
+                                       || confess "Attribute ($attr_name) does not pass the type contraint with '$_[1]'"
                                                if defined $_[1];
                                $_[0]->{$attr_name} = $_[1];
                        };                      
index 361c95a..e29786f 100644 (file)
@@ -22,8 +22,8 @@ sub construct_instance {
         # attribute's default value (if it has one)
         $val ||= $attr->default($instance) if $attr->has_default; 
                if (defined $val && $attr->has_type_constraint) {
-                       (defined $attr->type_constraint->($val))
-                               || confess "Attribute (" . $attr->name . ") does not pass the type contraint";                  
+            (defined($attr->type_constraint->($val))) 
+                || confess "Attribute () does not pass the type contraint with";                       
                }
         $instance->{$attr->name} = $val;
     }
index 68db685..cf08065 100644 (file)
@@ -22,14 +22,14 @@ sub new {
 sub BUILDALL {
        my ($self, %params) = @_;
        foreach my $method ($self->meta->find_all_methods_by_name('BUILD')) {
-               $method->{method}->($self, %params);
+               $method->{code}->($self, %params);
        }
 }
 
 sub DEMOLISHALL {
        my $self = shift;
        foreach my $method ($self->meta->find_all_methods_by_name('DEMOLISH')) {
-               $method->{method}->($self);
+               $method->{code}->($self);
        }       
 }
 
index a9a6b52..6c65523 100644 (file)
@@ -7,7 +7,7 @@ use warnings;
 use Sub::Name    'subname';
 use Scalar::Util 'blessed';
 
-our $VERSION = '0.01';
+our $VERSION = '0.02';
 
 sub import {
        shift;
@@ -66,12 +66,12 @@ sub subtype ($$;$) {
        else {
                ($parent, $check) = ($name, $parent);
                $parent = $TYPES{$parent} unless $parent && ref($parent) eq 'CODE';             
-               return subname((caller() . '::__anon_subtype__') => sub { 
+               return subname '__anon_subtype__' => sub { 
                        return $TYPES{$name} unless defined $_[0];                      
                        local $_ = $_[0];
                        return undef unless defined $parent->($_[0]) && $check->($_[0]);
                        $_[0];
-               });             
+               };              
        }
 }
 
diff --git a/t/004_basic.t b/t/004_basic.t
new file mode 100644 (file)
index 0000000..5f6f253
--- /dev/null
@@ -0,0 +1,235 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More tests => 64;
+use Test::Exception;
+
+BEGIN {
+    use_ok('Moose');           
+}
+
+{
+    package Address;
+    use strict;
+    use warnings;
+    use Moose;
+    
+    use Locale::US;
+    use Regexp::Common 'zip';
+    
+    my $STATES = Locale::US->new;
+    
+    subtype USState 
+        => as Str
+        => where {
+            (exists $STATES->{code2state}{uc($_)} || exists $STATES->{state2code}{uc($_)})
+        };
+        
+    subtype USZipCode 
+        => as Value
+        => where {
+            /^$RE{zip}{US}{-extended => 'allow'}$/            
+        };
+    
+    has 'street'   => (is => 'rw', isa => Str());
+    has 'city'     => (is => 'rw', isa => Str());
+    has 'state'    => (is => 'rw', isa => USState());
+    has 'zip_code' => (is => 'rw', isa => USZipCode());   
+    
+    package Company;
+    use strict;
+    use warnings;
+    use Moose;
+    
+    has 'name'      => (is => 'rw', isa => Str());
+    has 'address'   => (is => 'rw', isa => 'Address'); 
+    has 'employees' => (is => 'rw', isa => subtype ArrayRef => where { 
+        ($_->isa('Employee') || return) for @$_; 1 
+    });    
+    
+    sub BUILD {
+        my ($self, %params) = @_;
+        if ($params{employees}) {
+            foreach my $employee (@{$params{employees}}) {
+                $employee->company($self);
+            }
+        }
+    }
+    
+    sub get_employee_count { scalar @{(shift)->employees} }
+    
+    package Person;
+    use strict;
+    use warnings;
+    use Moose;
+    
+    has 'first_name'     => (is => 'rw', isa => Str());
+    has 'last_name'      => (is => 'rw', isa => Str());       
+    has 'middle_initial' => (is => 'rw', isa => Str(), predicate => 'has_middle_initial');  
+    has 'address'        => (is => 'rw', isa => 'Address');
+    
+    sub full_name {
+        my $self = shift;
+        return $self->first_name . 
+              ($self->has_middle_initial ? ' ' . $self->middle_initial . '. ' : ' ') .
+               $self->last_name;
+    }
+      
+    package Employee;
+    use strict;
+    use warnings;
+    use Moose;  
+    
+    extends 'Person';
+    
+    has 'title'   => (is => 'rw', isa => Str());
+    has 'company' => (is => 'rw', isa => 'Company', weak_ref => 1);  
+}
+
+my $ii;
+lives_ok {
+    $ii = Company->new(
+        name    => 'Infinity Interactive',
+        address => Address->new(
+            street   => '565 Plandome Rd., Suite 307',
+            city     => 'Manhasset',
+            state    => 'NY',
+            zip_code => '11030'
+        ),
+        employees => [
+            Employee->new(
+                first_name     => 'Jeremy',
+                last_name      => 'Shao',
+                title          => 'President / Senior Consultant',
+                address        => Address->new(city => 'Manhasset', state => 'NY')
+            ),
+            Employee->new(
+                first_name     => 'Tommy',
+                last_name      => 'Lee',
+                title          => 'Vice President / Senior Developer',
+                address        => Address->new(city => 'New York', state => 'NY')
+            ),        
+            Employee->new(
+                first_name     => 'Stevan',
+                middle_initial => 'C',
+                last_name      => 'Little',
+                title          => 'Senior Developer',            
+                address        => Address->new(city => 'Madison', state => 'CT')
+            ),
+            Employee->new(
+                first_name     => 'Rob',
+                last_name      => 'Kinyon',
+                title          => 'Developer',            
+                address        => Address->new(city => 'Marysville', state => 'OH')
+            ),        
+        ]
+    );
+} '... created the entire company successfully';
+isa_ok($ii, 'Company');
+
+is($ii->name, 'Infinity Interactive', '... got the right name for the company');
+
+isa_ok($ii->address, 'Address');
+is($ii->address->street, '565 Plandome Rd., Suite 307', '... got the right street address');
+is($ii->address->city, 'Manhasset', '... got the right city');
+is($ii->address->state, 'NY', '... got the right state');
+is($ii->address->zip_code, 11030, '... got the zip code');
+
+is($ii->get_employee_count, 4, '... got the right employee count');
+
+# employee #1
+
+isa_ok($ii->employees->[0], 'Employee');
+isa_ok($ii->employees->[0], 'Person');
+
+is($ii->employees->[0]->first_name, 'Jeremy', '... got the right first name');
+is($ii->employees->[0]->last_name, 'Shao', '... got the right last name');
+ok(!$ii->employees->[0]->has_middle_initial, '... no middle initial');
+is($ii->employees->[0]->middle_initial, undef, '... got the right middle initial value');
+is($ii->employees->[0]->full_name, 'Jeremy Shao', '... got the right full name');
+is($ii->employees->[0]->title, 'President / Senior Consultant', '... got the right title');
+is($ii->employees->[0]->company, $ii, '... got the right company');
+
+isa_ok($ii->employees->[0]->address, 'Address');
+is($ii->employees->[0]->address->city, 'Manhasset', '... got the right city');
+is($ii->employees->[0]->address->state, 'NY', '... got the right state');
+
+# employee #2
+
+isa_ok($ii->employees->[1], 'Employee');
+isa_ok($ii->employees->[1], 'Person');
+
+is($ii->employees->[1]->first_name, 'Tommy', '... got the right first name');
+is($ii->employees->[1]->last_name, 'Lee', '... got the right last name');
+ok(!$ii->employees->[1]->has_middle_initial, '... no middle initial');
+is($ii->employees->[1]->middle_initial, undef, '... got the right middle initial value');
+is($ii->employees->[1]->full_name, 'Tommy Lee', '... got the right full name');
+is($ii->employees->[1]->title, 'Vice President / Senior Developer', '... got the right title');
+is($ii->employees->[1]->company, $ii, '... got the right company');
+
+isa_ok($ii->employees->[1]->address, 'Address');
+is($ii->employees->[1]->address->city, 'New York', '... got the right city');
+is($ii->employees->[1]->address->state, 'NY', '... got the right state');
+
+# employee #3
+
+isa_ok($ii->employees->[2], 'Employee');
+isa_ok($ii->employees->[2], 'Person');
+
+is($ii->employees->[2]->first_name, 'Stevan', '... got the right first name');
+is($ii->employees->[2]->last_name, 'Little', '... got the right last name');
+ok($ii->employees->[2]->has_middle_initial, '... got middle initial');
+is($ii->employees->[2]->middle_initial, 'C', '... got the right middle initial value');
+is($ii->employees->[2]->full_name, 'Stevan C. Little', '... got the right full name');
+is($ii->employees->[2]->title, 'Senior Developer', '... got the right title');
+is($ii->employees->[2]->company, $ii, '... got the right company');
+
+isa_ok($ii->employees->[2]->address, 'Address');
+is($ii->employees->[2]->address->city, 'Madison', '... got the right city');
+is($ii->employees->[2]->address->state, 'CT', '... got the right state');
+
+# employee #4
+
+isa_ok($ii->employees->[3], 'Employee');
+isa_ok($ii->employees->[3], 'Person');
+
+is($ii->employees->[3]->first_name, 'Rob', '... got the right first name');
+is($ii->employees->[3]->last_name, 'Kinyon', '... got the right last name');
+ok(!$ii->employees->[3]->has_middle_initial, '... got middle initial');
+is($ii->employees->[3]->middle_initial, undef, '... got the right middle initial value');
+is($ii->employees->[3]->full_name, 'Rob Kinyon', '... got the right full name');
+is($ii->employees->[3]->title, 'Developer', '... got the right title');
+is($ii->employees->[3]->company, $ii, '... got the right company');
+
+isa_ok($ii->employees->[3]->address, 'Address');
+is($ii->employees->[3]->address->city, 'Marysville', '... got the right city');
+is($ii->employees->[3]->address->state, 'OH', '... got the right state');
+
+## check some error conditions for the subtypes
+
+dies_ok {
+    Address->new(state => 'British Columbia'),    
+} '... we die correctly with bad args';
+
+lives_ok {
+    Address->new(state => 'Connecticut'),    
+} '... we live correctly with good args';
+
+dies_ok {
+    Address->new(zip_code => 'AF5J6$'),    
+} '... we die correctly with bad args';
+
+lives_ok {
+    Address->new(zip_code => '06443'),    
+} '... we live correctly with good args';
+
+dies_ok {
+    Company->new(employees => [ Person->new ]),    
+} '... we die correctly with good args';
+
+lives_ok {
+    Company->new(employees => []),    
+} '... we live correctly with good args';
+