package Variable::Magic;
-use 5.007003;
+use 5.008;
use strict;
use warnings;
=head1 VERSION
-Version 0.26
+Version 0.29
=cut
our $VERSION;
BEGIN {
- $VERSION = '0.26';
+ $VERSION = '0.29';
}
=head1 SYNOPSIS
True iff this module could have been built with thread-safety features enabled.
+=head2 C<VMG_OP_INFO_NAME>
+
+Value to pass with C<op_info> to get the current op name in the magic callbacks.
+
+=head2 C<VMG_OP_INFO_OBJECT>
+
+Value to pass with C<op_info> to get a C<B::OP> object representing the current op in the magic callbacks.
+
=head1 FUNCTIONS
=cut
=head2 C<wizard>
- wizard sig => ...,
- data => sub { ... },
- get => sub { my ($ref, $data) = @_; ... },
- set => sub { my ($ref, $data) = @_; ... },
- len => sub { my ($ref, $data, $len) = @_; ... ; return $newlen; },
- clear => sub { my ($ref, $data) = @_; ... },
- free => sub { my ($ref, $data) = @_, ... },
- copy => sub { my ($ref, $data, $key, $elt) = @_; ... },
- local => sub { my ($ref, $data) = @_; ... },
- fetch => sub { my ($ref, $data, $key) = @_; ... },
- store => sub { my ($ref, $data, $key) = @_; ... },
- exists => sub { my ($ref, $data, $key) = @_; ... },
- delete => sub { my ($ref, $data, $key) = @_; ... }
+ wizard sig => ...,
+ data => sub { ... },
+ get => sub { my ($ref, $data [, $op]) = @_; ... },
+ set => sub { my ($ref, $data [, $op]) = @_; ... },
+ len => sub { my ($ref, $data, $len [, $op]) = @_; ... ; return $newlen; },
+ clear => sub { my ($ref, $data [, $op]) = @_; ... },
+ free => sub { my ($ref, $data [, $op]) = @_, ... },
+ copy => sub { my ($ref, $data, $key, $elt [, $op]) = @_; ... },
+ local => sub { my ($ref, $data [, $op]) = @_; ... },
+ fetch => sub { my ($ref, $data, $key [, $op]) = @_; ... },
+ store => sub { my ($ref, $data, $key [, $op]) = @_; ... },
+ exists => sub { my ($ref, $data, $key [, $op]) = @_; ... },
+ delete => sub { my ($ref, $data, $key [, $op]) = @_; ... },
+ copy_key => $bool,
+ op_info => [ 0 | VMG_OP_INFO_NAME | VMG_OP_INFO_OBJECT ]
This function creates a 'wizard', an opaque type that holds the magic information.
It takes a list of keys / values as argument, whose keys can be :
C<get>, C<set>, C<len>, C<clear>, C<free>, C<copy>, C<local>, C<fetch>, C<store>, C<exists> and C<delete>
-Code references to corresponding magic callbacks.
+Code references to the corresponding magic callbacks.
You don't have to specify all of them : the magic associated with undefined entries simply won't be hooked.
In those callbacks, C<$_[0]> is always a reference to the magic object and C<$_[1]> is always the private data (or C<undef> when no private data constructor was supplied).
-In the special case of C<len> magic and when the variable is an array, C<$_[2]> contains its normal length.
-C<$_[2]> is the current key in C<copy>, C<fetch>, C<store>, C<exists> and C<delete> callbacks, although for C<copy> it may just be a copy of the actual key so it's useless to (for example) cast magic on it.
-C<copy> magic also receives the current element (i.e. the value) in C<$_[3]>.
+
+Moreover, when you pass C<< op_info => $num >> to C<wizard>, the last element of C<@_> will be the current op name if C<$num == VMG_OP_INFO_NAME> and a C<B::OP> object representing the current op if C<$num == VMG_OP_INFO_OBJECT>.
+Both have a performance hit, but just getting the name is lighter than getting the op object.
+
+Other arguments are specific to the magic hooked :
+
+=over 8
+
+=item *
+
+C<len>
+
+When the variable is an array or a scalar, C<$_[2]> contains the non-magical length.
+The callback can return the new scalar or array length to use, or C<undef> to default to the normal length.
+
+=item *
+
+C<copy>
+
+C<$_[2]> is a either a copy or an alias of the current key, which means that it is useless to try to change or cast magic on it.
+C<$_[3]> is an alias to the current element (i.e. the value).
+
+=item *
+
+C<fetch>, C<store>, C<exists> and C<delete>
+
+C<$_[2]> is an alias to the current key.
+Nothing prevents you from changing it, but be aware that there lurk dangerous side effects.
+For example, it may righteously be readonly if the key was a bareword.
+You can get a copy instead by passing C<< copy_key => 1 >> to L</wizard>, which allows you to safely assign to C<$_[2]> in order to e.g. redirect the action to another key.
+This however has a little performance drawback because of the copy.
+
+=back
All the callbacks are expected to return an integer, which is passed straight to the perl magic API.
However, only the return value of the C<len> callback currently holds a meaning.
sub wizard {
croak 'Wrong number of arguments for wizard()' if @_ % 2;
my %opts = @_;
- my @cbs = qw/sig data get set len clear free/;
- push @cbs, 'copy' if MGf_COPY;
- push @cbs, 'dup' if MGf_DUP;
- push @cbs, 'local' if MGf_LOCAL;
- push @cbs, qw/fetch store exists delete/ if VMG_UVAR;
- my $ret = eval { _wizard(map $opts{$_}, @cbs) };
+ my @keys = qw/sig data op_info get set len clear free/;
+ push @keys, 'copy' if MGf_COPY;
+ push @keys, 'dup' if MGf_DUP;
+ push @keys, 'local' if MGf_LOCAL;
+ push @keys, qw/fetch store exists delete copy_key/ if VMG_UVAR;
+ my $ret = eval { _wizard(map $opts{$_}, @keys) };
if (my $err = $@) {
$err =~ s/\sat\s+.*?\n//;
croak $err;
our @EXPORT = ();
our %EXPORT_TAGS = (
'funcs' => [ qw/wizard gensig getsig cast getdata dispell/ ],
- 'consts' => [ qw/SIG_MIN SIG_MAX SIG_NBR MGf_COPY MGf_DUP MGf_LOCAL VMG_UVAR/,
- qw/VMG_COMPAT_ARRAY_PUSH_NOLEN VMG_COMPAT_ARRAY_UNSHIFT_NOLEN_VOID VMG_COMPAT_ARRAY_UNDEF_CLEAR/,
- qw/VMG_COMPAT_SCALAR_LENGTH_NOLEN/,
+ 'consts' => [
+ qw/SIG_MIN SIG_MAX SIG_NBR MGf_COPY MGf_DUP MGf_LOCAL VMG_UVAR/,
+ qw/VMG_COMPAT_ARRAY_PUSH_NOLEN VMG_COMPAT_ARRAY_UNSHIFT_NOLEN_VOID VMG_COMPAT_ARRAY_UNDEF_CLEAR VMG_COMPAT_SCALAR_LENGTH_NOLEN/,
qw/VMG_PERL_PATCHLEVEL/,
- qw/VMG_THREADSAFE/ ]
+ qw/VMG_THREADSAFE/,
+ qw/VMG_OP_INFO_NAME VMG_OP_INFO_OBJECT/
+ ]
);
our @EXPORT_OK = map { @$_ } values %EXPORT_TAGS;
$EXPORT_TAGS{'all'} = [ @EXPORT_OK ];
+END { _cleanup() }
+
=head1 CAVEATS
If you store a magic object in the private data slot, the magic won't be accessible by L</getdata> since it's not copied by assignation.
If you define a wizard with a C<free> callback and cast it on itself, this destructor won't be called because the wizard will be destroyed first.
-Using C<get> and C<clear> magics on hashes may cause segfaults.
-
=head1 DEPENDENCIES
-L<perl> 5.7.3.
+L<perl> 5.8.
L<Carp> (standard since perl 5), L<XSLoader> (standard since perl 5.006).
=head1 COPYRIGHT & LICENSE
-Copyright 2007-2008 Vincent Pit, all rights reserved.
+Copyright 2007-2009 Vincent Pit, all rights reserved.
This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.