X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FMouse%2FMeta%2FModule.pm;h=12b0453b3bf39ec6d8ff911ab4e847b0571a1d83;hb=6cfa1e5e70616fb102915489c02d8347ffa912fb;hp=01d42c10ee943980bead033f81fd51b0317c2b94;hpb=3a63a2e7ef8fbac5f61eab04baecbf5d19374b83;p=gitmo%2FMouse.git diff --git a/lib/Mouse/Meta/Module.pm b/lib/Mouse/Meta/Module.pm index 01d42c1..12b0453 100755 --- a/lib/Mouse/Meta/Module.pm +++ b/lib/Mouse/Meta/Module.pm @@ -2,13 +2,75 @@ package Mouse::Meta::Module; use strict; use warnings; -use Scalar::Util qw/blessed weaken/; -use Mouse::Util qw/version authority identifier get_code_info/; -use Carp 'confess'; +use Mouse::Util qw/get_code_info not_supported load_class/; +use Scalar::Util qw/blessed/; + + +{ + my %METACLASS_CACHE; + + # because Mouse doesn't introspect existing classes, we're forced to + # only pay attention to other Mouse classes + sub _metaclass_cache { + my($class, $name) = @_; + return $METACLASS_CACHE{$name}; + } + + sub initialize { + my($class, $package_name, @args) = @_; + + ($package_name && !ref($package_name)) + || $class->throw_error("You must pass a package name and it cannot be blessed"); + + return $METACLASS_CACHE{$package_name} + ||= $class->_new(package => $package_name, @args); + } + + sub Mouse::class_of{ + my($class_or_instance) = @_; + return undef unless defined $class_or_instance; + return $METACLASS_CACHE{ blessed($class_or_instance) || $class_or_instance }; + } + + # Means of accessing all the metaclasses that have + # been initialized thus far + sub get_all_metaclasses { %METACLASS_CACHE } + sub get_all_metaclass_instances { values %METACLASS_CACHE } + sub get_all_metaclass_names { keys %METACLASS_CACHE } + sub get_metaclass_by_name { $METACLASS_CACHE{$_[0]} } + sub store_metaclass_by_name { $METACLASS_CACHE{$_[0]} = $_[1] } + sub weaken_metaclass { weaken($METACLASS_CACHE{$_[0]}) } + sub does_metaclass_exist { defined $METACLASS_CACHE{$_[0]} } + sub remove_metaclass_by_name { delete $METACLASS_CACHE{$_[0]} } + +} + +sub meta{ Mouse::Meta::Class->initialize(ref $_[0] || $_[0]) } + +sub _new{ Carp::croak("Mouse::Meta::Module is an abstract class") } sub name { $_[0]->{package} } sub _method_map{ $_[0]->{methods} } +sub version { no strict 'refs'; ${shift->name.'::VERSION'} } +sub authority { no strict 'refs'; ${shift->name.'::AUTHORITY'} } +sub identifier { + my $self = shift; + return join '-' => ( + $self->name, + ($self->version || ()), + ($self->authority || ()), + ); +} + +# add_attribute is an abstract method + +sub get_attribute_map { $_[0]->{attributes} } +sub has_attribute { exists $_[0]->{attributes}->{$_[1]} } +sub get_attribute { $_[0]->{attributes}->{$_[1]} } +sub get_attribute_list{ keys %{$_[0]->{attributes}} } +sub remove_attribute { delete $_[0]->{attributes}->{$_[1]} } + sub namespace{ my $name = $_[0]->{package}; no strict 'refs'; @@ -19,10 +81,10 @@ sub add_method { my($self, $name, $code) = @_; if(!defined $name){ - confess "You must pass a defined name"; + $self->throw_error("You must pass a defined name"); } if(ref($code) ne 'CODE'){ - confess "You must pass a CODE reference"; + not_supported 'add_method for a method object'; } $self->_method_map->{$name}++; # Moose stores meta object here. @@ -51,7 +113,23 @@ sub has_method { return $code && $self->_code_is_mine($code); } +sub get_method{ + my($self, $method_name) = @_; + + if($self->has_method($method_name)){ + my $method_metaclass = $self->method_metaclass; + load_class($method_metaclass); + + my $package = $self->name; + return $method_metaclass->new( + body => $package->can($method_name), + name => $method_name, + package => $package, + ); + } + return undef; +} sub get_method_list { my($self) = @_; @@ -59,14 +137,19 @@ sub get_method_list { return grep { $self->has_method($_) } keys %{ $self->namespace }; } -sub get_attribute_map { $_[0]->{attributes} } -sub has_attribute { exists $_[0]->{attributes}->{$_[1]} } -sub get_attribute { $_[0]->{attributes}->{$_[1]} } -sub get_attribute_list { - my $self = shift; - keys %{$self->get_attribute_map}; -} +sub throw_error{ + my($class, $message, %args) = @_; + local $Carp::CarpLevel = $Carp::CarpLevel + 1 + ($args{depth} || 0); + local $Carp::MaxArgNums = 20; # default is 8, usually we use named args which gets messier though + + if(exists $args{longmess} && !$args{longmess}){ # intentionaly longmess => 0 + Carp::croak($message); + } + else{ + Carp::confess($message); + } +} 1;