X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=gitmo%2FMouse.git;a=blobdiff_plain;f=lib%2FMouse%2FPurePerl.pm;h=f51b4c2540ff3ddfc4a56ae81767b51dc995e510;hp=32616b09bc2788d4ec4e17cabbb877876ec92fb0;hb=f7e41edaceee0d549a2d664378cfcf85dcf9454b;hpb=619338ac4245c7c523d67645d6cd51cb982d4841 diff --git a/lib/Mouse/PurePerl.pm b/lib/Mouse/PurePerl.pm index 32616b0..f51b4c2 100644 --- a/lib/Mouse/PurePerl.pm +++ b/lib/Mouse/PurePerl.pm @@ -1,5 +1,7 @@ package Mouse::PurePerl; +require Mouse::Util; + package Mouse::Util; @@ -166,7 +168,7 @@ package sub name { $_[0]->{package} } sub _method_map { $_[0]->{methods} } -sub _attribute_map{ $_[0]->{attribute_map} } +sub _attribute_map{ $_[0]->{attributes} } sub namespace{ my $name = $_[0]->{package}; @@ -201,6 +203,12 @@ sub add_method { package Mouse::Meta::Class; +sub method_metaclass { $_[0]->{method_metaclass} || 'Mouse::Meta::Method' } +sub attribute_metaclass { $_[0]->{attribute_metaclass} || 'Mouse::Meta::Attribute' } + +sub constructor_class { $_[0]->{constructor_class} || 'Mouse::Meta::Method::Constructor' } +sub destructor_class { $_[0]->{destructor_class} || 'Mouse::Meta::Method::Destructor' } + sub is_anon_class{ return exists $_[0]->{anon_serial_id}; } @@ -209,9 +217,82 @@ sub roles { $_[0]->{roles} } sub linearized_isa { @{ get_linear_isa($_[0]->{package}) } } +sub get_all_attributes { + my($self) = @_; + my %attrs = map { %{ $self->initialize($_)->{attributes} } } reverse $self->linearized_isa; + return values %attrs; +} + +sub new_object { + my $self = shift; + my %args = (@_ == 1 ? %{$_[0]} : @_); + + my $object = bless {}, $self->name; + + $self->_initialize_object($object, \%args); + return $object; +} + +sub _initialize_object{ + my($self, $object, $args, $ignore_triggers) = @_; + + my @triggers_queue; + + foreach my $attribute ($self->get_all_attributes) { + my $init_arg = $attribute->init_arg; + my $slot = $attribute->name; + + if (defined($init_arg) && exists($args->{$init_arg})) { + $object->{$slot} = $attribute->_coerce_and_verify($args->{$init_arg}, $object); + + weaken($object->{$slot}) + if ref($object->{$slot}) && $attribute->is_weak_ref; + + if ($attribute->has_trigger) { + push @triggers_queue, [ $attribute->trigger, $object->{$slot} ]; + } + } + else { # no init arg + if ($attribute->has_default || $attribute->has_builder) { + if (!$attribute->is_lazy) { + my $default = $attribute->default; + my $builder = $attribute->builder; + my $value = $builder ? $object->$builder() + : ref($default) eq 'CODE' ? $object->$default() + : $default; + + $object->{$slot} = $attribute->_coerce_and_verify($value, $object); + + weaken($object->{$slot}) + if ref($object->{$slot}) && $attribute->is_weak_ref; + } + } + elsif($attribute->is_required) { + $self->throw_error("Attribute (".$attribute->name.") is required"); + } + } + } + + if(!$ignore_triggers){ + foreach my $trigger_and_value(@triggers_queue){ + my($trigger, $value) = @{$trigger_and_value}; + $trigger->($object, $value); + } + } + + if($self->is_anon_class){ + $object->{__METACLASS__} = $self; + } + + return; +} + + package Mouse::Meta::Role; +sub method_metaclass{ $_[0]->{method_metaclass} || 'Mouse::Meta::Role::Method' } + sub is_anon_role{ return exists $_[0]->{anon_serial_id}; } @@ -221,7 +302,9 @@ sub get_roles { $_[0]->{roles} } package Mouse::Meta::Attribute; -use Mouse::Meta::Method::Accessor; +require Mouse::Meta::Method::Accessor; + +sub accessor_metaclass{ $_[0]->{accessor_metaclass} || 'Mouse::Meta::Method::Accessor' } # readers @@ -267,8 +350,6 @@ sub has_builder { exists $_[0]->{builder} } sub has_documentation { exists $_[0]->{documentation} } -sub accessor_metaclass(){ 'Mouse::Meta::Method::Accessor' } - package Mouse::Meta::TypeConstraint; @@ -282,6 +363,126 @@ sub _compiled_type_coercion { $_[0]->{_compiled_type_coercion} } sub has_coercion{ exists $_[0]->{_compiled_type_coercion} } + +sub compile_type_constraint{ + my($self) = @_; + + # add parents first + my @checks; + for(my $parent = $self->{parent}; defined $parent; $parent = $parent->{parent}){ + if($parent->{hand_optimized_type_constraint}){ + unshift @checks, $parent->{hand_optimized_type_constraint}; + last; # a hand optimized constraint must include all the parents + } + elsif($parent->{constraint}){ + unshift @checks, $parent->{constraint}; + } + } + + # then add child + if($self->{constraint}){ + push @checks, $self->{constraint}; + } + + if($self->{type_constraints}){ # Union + my @types = map{ $_->{compiled_type_constraint} } @{ $self->{type_constraints} }; + push @checks, sub{ + foreach my $c(@types){ + return 1 if $c->($_[0]); + } + return 0; + }; + } + + if(@checks == 0){ + $self->{compiled_type_constraint} = \&Mouse::Util::TypeConstraints::Any; + } + else{ + $self->{compiled_type_constraint} = sub{ + my(@args) = @_; + local $_ = $args[0]; + foreach my $c(@checks){ + return undef if !$c->(@args); + } + return 1; + }; + } + return; +} + +package + Mouse::Object; + + +sub BUILDARGS { + my $class = shift; + + if (scalar @_ == 1) { + (ref($_[0]) eq 'HASH') + || $class->meta->throw_error("Single parameters to new() must be a HASH ref"); + + return {%{$_[0]}}; + } + else { + return {@_}; + } +} + +sub new { + my $class = shift; + + $class->meta->throw_error('Cannot call new() on an instance') if ref $class; + + my $args = $class->BUILDARGS(@_); + + my $meta = Mouse::Meta::Class->initialize($class); + my $self = $meta->new_object($args); + + # BUILDALL + if( $self->can('BUILD') ) { + for my $class (reverse $meta->linearized_isa) { + my $build = Mouse::Util::get_code_ref($class, 'BUILD') + || next; + + $self->$build($args); + } + } + + return $self; +} + +sub DESTROY { + my $self = shift; + + return unless $self->can('DEMOLISH'); # short circuit + + local $?; + + my $e = do{ + local $@; + eval{ + + # DEMOLISHALL + + # We cannot count on being able to retrieve a previously made + # metaclass, _or_ being able to make a new one during global + # destruction. However, we should still be able to use mro at + # that time (at least tests suggest so ;) + + foreach my $class (@{ Mouse::Util::get_linear_isa(ref $self) }) { + my $demolish = Mouse::Util::get_code_ref($class, 'DEMOLISH') + || next; + + $self->$demolish(); + } + }; + $@; + }; + + no warnings 'misc'; + die $e if $e; # rethrow +} + 1; __END__ @@ -291,7 +492,7 @@ Mouse::PurePerl - A Mouse guts in pure Perl =head1 VERSION -This document describes Mouse version 0.40_03 +This document describes Mouse version 0.40_08 =head1 SEE ALSO