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 =~ /\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};
}
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;
}
}
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)
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 {
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;
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;
}
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;
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