X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FClass%2FMOP%2FPackage.pm;h=2911d2e5f4bb9fdaee16130ab837756b0403e8e5;hb=c46b802b9f10829ddce24dbf3fb81d5319f8be8f;hp=275c1652c92dc2e8c0aa9aa6fc12b935f4cbd272;hpb=2243a22b2f3dd10fe1d860722e83526fa3c998b3;p=gitmo%2FClass-MOP.git diff --git a/lib/Class/MOP/Package.pm b/lib/Class/MOP/Package.pm index 275c165..2911d2e 100644 --- a/lib/Class/MOP/Package.pm +++ b/lib/Class/MOP/Package.pm @@ -5,8 +5,9 @@ use strict; use warnings; use Scalar::Util 'blessed'; +use Carp 'confess'; -our $VERSION = '0.01'; +our $VERSION = '0.02'; # introspection @@ -15,6 +16,145 @@ sub meta { Class::MOP::Class->initialize(blessed($_[0]) || $_[0]); } +# creation ... + +sub initialize { + my $class = shift; + my $package_name = shift; + # we hand-construct the class + # until we can bootstrap it + no strict 'refs'; + return bless { + '$:package' => $package_name, + '%:namespace' => \%{$package_name . '::'}, + } => $class; +} + +# Attributes + +# NOTE: +# all these attribute readers will be bootstrapped +# away in the Class::MOP bootstrap section + +sub name { $_[0]->{'$:package'} } +sub namespace { $_[0]->{'%:namespace'} } + +# utility methods + +{ + my %SIGIL_MAP = ( + '$' => 'SCALAR', + '@' => 'ARRAY', + '%' => 'HASH', + '&' => 'CODE', + ); + + sub _deconstruct_variable_name { + my ($self, $variable) = @_; + + (defined $variable) + || confess "You must pass a variable name"; + + my ($sigil, $name) = ($variable =~ /^(.)(.*)$/); + + (defined $sigil) + || confess "The variable name must include a sigil"; + + (exists $SIGIL_MAP{$sigil}) + || confess "I do not recognize that sigil '$sigil'"; + + return ($name, $sigil, $SIGIL_MAP{$sigil}); + } +} + +# Class attributes + +# ... these functions have to touch the symbol table itself,.. yuk + +sub add_package_symbol { + my ($self, $variable, $initial_value) = @_; + + my ($name, $sigil, $type) = $self->_deconstruct_variable_name($variable); + + no strict 'refs'; + no warnings 'redefine', 'misc'; + *{$self->name . '::' . $name} = ref $initial_value ? $initial_value : \$initial_value; +} + +sub remove_package_glob { + my ($self, $name) = @_; + no strict 'refs'; + delete ${$self->name . '::'}{$name}; +} + +# ... these functions deal with stuff on the namespace level + +sub has_package_symbol { + my ($self, $variable) = @_; + + my ($name, $sigil, $type) = $self->_deconstruct_variable_name($variable); + + return 0 unless exists $self->namespace->{$name}; + defined *{$self->namespace->{$name}}{$type} ? 1 : 0; +} + +sub get_package_symbol { + my ($self, $variable) = @_; + + my ($name, $sigil, $type) = $self->_deconstruct_variable_name($variable); + + $self->add_package_symbol($variable) + unless exists $self->namespace->{$name}; + return *{$self->namespace->{$name}}{$type}; +} + +sub remove_package_symbol { + my ($self, $variable) = @_; + + my ($name, $sigil, $type) = $self->_deconstruct_variable_name($variable); + + # FIXME: + # no doubt this is grossly inefficient and + # could be done much easier and faster in XS + + my ($scalar, $array, $hash, $code); + if ($type eq 'SCALAR') { + $array = $self->get_package_symbol('@' . $name) if $self->has_package_symbol('@' . $name); + $hash = $self->get_package_symbol('%' . $name) if $self->has_package_symbol('%' . $name); + $code = $self->get_package_symbol('&' . $name) if $self->has_package_symbol('&' . $name); + } + elsif ($type eq 'ARRAY') { + $scalar = $self->get_package_symbol('$' . $name) if $self->has_package_symbol('$' . $name); + $hash = $self->get_package_symbol('%' . $name) if $self->has_package_symbol('%' . $name); + $code = $self->get_package_symbol('&' . $name) if $self->has_package_symbol('&' . $name); + } + elsif ($type eq 'HASH') { + $scalar = $self->get_package_symbol('$' . $name) if $self->has_package_symbol('$' . $name); + $array = $self->get_package_symbol('@' . $name) if $self->has_package_symbol('@' . $name); + $code = $self->get_package_symbol('&' . $name) if $self->has_package_symbol('&' . $name); + } + elsif ($type eq 'CODE') { + $scalar = $self->get_package_symbol('$' . $name) if $self->has_package_symbol('$' . $name); + $array = $self->get_package_symbol('@' . $name) if $self->has_package_symbol('@' . $name); + $hash = $self->get_package_symbol('%' . $name) if $self->has_package_symbol('%' . $name); + } + else { + confess "This should never ever ever happen"; + } + + $self->remove_package_glob($name); + + $self->add_package_symbol(('$' . $name) => $scalar) if defined $scalar; + $self->add_package_symbol(('@' . $name) => $array) if defined $array; + $self->add_package_symbol(('%' . $name) => $hash) if defined $hash; + $self->add_package_symbol(('&' . $name) => $code) if defined $code; +} + +sub list_all_package_symbols { + my ($self) = @_; + return keys %{$self->namespace}; +} + 1; __END__ @@ -35,12 +175,32 @@ Class::MOP::Package - Package Meta Object =item B +=item B + +=item B + +=item B + +=item B + +=item B + +=item B + +=item B + +=item B + +=item B + =back -=head1 AUTHOR +=head1 AUTHORS Stevan Little Estevan@iinteractive.comE +Yuval Kogman Enothingmuch@woobling.comE + =head1 COPYRIGHT AND LICENSE Copyright 2006 by Infinity Interactive, Inc.