X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FPackage%2FStash%2FPP.pm;h=121a57e8188ab5e5b26a03b94d79c130eb027e3b;hb=c049a789b0ccb2734ee8c8f1b8a6bb80b575c19b;hp=b3e3a7dac1eacb5f7f373eaa1a18e1eb05cc5f45;hpb=ed131e4112640c781865aad216cb3c424e5d2ab9;p=gitmo%2FPackage-Stash.git diff --git a/lib/Package/Stash/PP.pm b/lib/Package/Stash/PP.pm index b3e3a7d..121a57e 100644 --- a/lib/Package/Stash/PP.pm +++ b/lib/Package/Stash/PP.pm @@ -31,27 +31,31 @@ sub new { my $class = shift; my ($package) = @_; - if (!defined($package) || (ref($package) && ref($package) ne 'HASH')) { + if (!defined($package) || (ref($package) && reftype($package) ne 'HASH')) { confess "Package::Stash->new must be passed the name of the " . "package to access"; } - elsif (ref($package) eq 'HASH') { - confess "The pure perl implementation of Package::Stash doesn't " - . "currently support anonymous stashes. You should install " - . "Package::Stash::XS"; + elsif (ref($package) && reftype($package) eq 'HASH') { + return bless { + 'namespace' => $package, + }, $class; } - elsif ($package !~ /[0-9A-Z_a-z]+(?:::[0-9A-Z_a-z]+)*/) { + elsif ($package =~ /\A[0-9A-Z_a-z]+(?:::[0-9A-Z_a-z]+)*\z/) { + return bless { + 'package' => $package, + }, $class; + } + else { confess "$package is not a module name"; } - return bless { - 'package' => $package, - }, $class; } sub name { confess "Can't call name as a class method" unless blessed($_[0]); + confess "Can't get the name of an anonymous package" + unless defined($_[0]->{package}); return $_[0]->{package}; } @@ -89,17 +93,31 @@ sub namespace { sub _deconstruct_variable_name { my ($self, $variable) = @_; - (defined $variable && length $variable) - || confess "You must pass a variable name"; - - my $sigil = substr($variable, 0, 1, ''); - - if (exists $SIGIL_MAP{$sigil}) { - return ($variable, $sigil, $SIGIL_MAP{$sigil}); + my @ret; + if (ref($variable) eq 'HASH') { + @ret = @{$variable}{qw[name sigil type]}; } else { - return ("${sigil}${variable}", '', $SIGIL_MAP{''}); + (defined $variable && length $variable) + || confess "You must pass a variable name"; + + my $sigil = substr($variable, 0, 1, ''); + + if (exists $SIGIL_MAP{$sigil}) { + @ret = ($variable, $sigil, $SIGIL_MAP{$sigil}); + } + else { + @ret = ("${sigil}${variable}", '', $SIGIL_MAP{''}); + } } + + # XXX in pure perl, this will access things in inner packages, + # in xs, this will segfault - probably look more into this at + # some point + ($ret[0] !~ /::/) + || confess "Variable names may not contain ::"; + + return @ret; } } @@ -119,11 +137,7 @@ sub _valid_for_type { sub add_symbol { my ($self, $variable, $initial_value, %opts) = @_; - my ($name, $sigil, $type) = ref $variable eq 'HASH' - ? @{$variable}{qw[name sigil type]} - : $self->_deconstruct_variable_name($variable); - - my $pkg = $self->name; + my ($name, $sigil, $type) = $self->_deconstruct_variable_name($variable); if (@_ > 2) { $self->_valid_for_type($initial_value, $type) @@ -140,13 +154,14 @@ sub add_symbol { my $last_line_num = $opts{last_line_num} || ($first_line_num ||= 0); # http://perldoc.perl.org/perldebguts.html#Debugger-Internals - $DB::sub{$pkg . '::' . $name} = "$filename:$first_line_num-$last_line_num"; + $DB::sub{$self->name . '::' . $name} = "$filename:$first_line_num-$last_line_num"; } } - no strict 'refs'; - no warnings 'redefine', 'misc', 'prototype'; - *{$pkg . '::' . $name} = ref $initial_value ? $initial_value : \$initial_value; + my $namespace = $self->namespace; + $namespace->{$name} ||= *{ Symbol::gensym() }; + *{ $namespace->{$name} } = ref $initial_value + ? $initial_value : \$initial_value; } sub remove_glob { @@ -157,9 +172,7 @@ sub remove_glob { sub has_symbol { my ($self, $variable) = @_; - my ($name, $sigil, $type) = ref $variable eq 'HASH' - ? @{$variable}{qw[name sigil type]} - : $self->_deconstruct_variable_name($variable); + my ($name, $sigil, $type) = $self->_deconstruct_variable_name($variable); my $namespace = $self->namespace; @@ -189,9 +202,7 @@ sub has_symbol { sub get_symbol { my ($self, $variable, %opts) = @_; - my ($name, $sigil, $type) = ref $variable eq 'HASH' - ? @{$variable}{qw[name sigil type]} - : $self->_deconstruct_variable_name($variable); + my ($name, $sigil, $type) = $self->_deconstruct_variable_name($variable); my $namespace = $self->namespace; @@ -236,8 +247,17 @@ sub get_symbol { } else { if ($type eq 'CODE') { - no strict 'refs'; - return \&{ $self->name . '::' . $name }; + # XXX we should really be able to support arbitrary anonymous + # stashes here... (not just via Package::Anon) + if (blessed($namespace) && $namespace->isa('Package::Anon')) { + # ->can will call gv_init for us + $namespace->bless(\(my $foo))->can($name); + return *{ $namespace->{$name} }{CODE}; + } + else { + no strict 'refs'; + return \&{ $self->name . '::' . $name }; + } } else { return undef; @@ -253,9 +273,7 @@ sub get_or_add_symbol { sub remove_symbol { my ($self, $variable) = @_; - my ($name, $sigil, $type) = ref $variable eq 'HASH' - ? @{$variable}{qw[name sigil type]} - : $self->_deconstruct_variable_name($variable); + my ($name, $sigil, $type) = $self->_deconstruct_variable_name($variable); # FIXME: # no doubt this is grossly inefficient and