Variable::Magic - Associate user-defined magic to variables from Perl.
VERSION
- Version 0.33
+ Version 0.39
SYNOPSIS
use Variable::Magic qw/wizard cast VMG_OP_INFO_NAME/;
* "get"
- This magic is invoked when the variable is evaluated (does not
- include array/hash subscripts and slices).
+ This magic is invoked when the variable is evaluated. It is never
+ called for arrays and hashes.
* "set"
- This one is triggered each time the value of the variable changes
- (includes array/hash subscripts and slices).
+ This one is triggered each time the value of the variable changes.
+ It is called for array subscripts and slices, but never for hashes.
* "len"
FUNCTIONS
"wizard"
- wizard sig => ...,
- data => sub { ... },
+ wizard data => sub { ... },
get => sub { my ($ref, $data [, $op]) = @_; ... },
set => sub { my ($ref, $data [, $op]) = @_; ... },
len => sub { my ($ref, $data, $len [, $op]) = @_; ... ; return $newlen; },
information. It takes a list of keys / values as argument, whose keys
can be :
- * "sig"
-
- The numerical signature. If not specified or undefined, a random
- signature is generated. If the signature matches an already defined
- magic, then the existant magic object is returned.
-
* "data"
- A code reference to a private data constructor. It is called each
- time this magic is cast on a variable, and the scalar returned is
- used as private data storage for it. $_[0] is a reference to the
- magic object and @_[1 .. @_-1] are all extra arguments that were
- passed to "cast".
+ A code (or string) reference to a private data constructor. It is
+ called each time this magic is cast on a variable, and the scalar
+ returned is used as private data storage for it. $_[0] is a
+ reference to the magic object and @_[1 .. @_-1] are all extra
+ arguments that were passed to "cast".
* "get", "set", "len", "clear", "free", "copy", "local", "fetch",
"store", "exists" and "delete"
- 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, $_[0] is always a
- reference to the magic object and $_[1] is always the private data
- (or "undef" when no private data constructor was supplied).
+ Code (or string) 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, $_[0]
+ is always a reference to the magic object and $_[1] is always the
+ private data (or "undef" when no private data constructor was
+ supplied).
Moreover, when you pass "op_info => $num" to "wizard", the last
element of @_ will be the current op name if "$num ==
$_[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
+ side effects. For example, it may rightfully be readonly if
the key was a bareword. You can get a copy instead by
passing "copy_key => 1" to "wizard", which allows you to
safely assign to $_[2] in order to e.g. redirect the action
straight to the perl magic API. However, only the return value of
the "len" callback currently holds a meaning.
- # A simple scalar tracer
- my $wiz = wizard get => sub { print STDERR "got ${$_[0]}\n" },
- set => sub { print STDERR "set to ${$_[0]}\n" },
- free => sub { print STDERR "${$_[0]} was deleted\n" }
+ Each callback can be specified as a code or a string reference, in which
+ case the function denoted by the string will be used as the callback.
Note that "free" callbacks are *never* called during global destruction,
as there's no way to ensure that the wizard and the "free" callback
weren't destroyed before the variable.
- "gensig"
- With this tool, you can manually generate random magic signature between
- SIG_MIN and SIG_MAX inclusive. That's the way "wizard" creates them when
- no signature is supplied.
-
- # Generate a signature
- my $sig = gensig;
-
- "getsig"
- getsig $wiz
+ Here's a simple usage example :
- This accessor returns the magic signature of this wizard.
-
- # Get $wiz signature
- my $sig = getsig $wiz;
+ # A simple scalar tracer
+ my $wiz = wizard get => sub { print STDERR "got ${$_[0]}\n" },
+ set => sub { print STDERR "set to ${$_[0]}\n" },
+ free => sub { print STDERR "${$_[0]} was deleted\n" }
"cast"
- cast [$@%&*]var, [$wiz|$sig], ...
+ cast [$@%&*]var, $wiz, ...
This function associates $wiz magic to the variable supplied, without
- overwriting any other kind of magic. You can also supply the numeric
- signature $sig instead of $wiz. It returns true on success or when $wiz
- magic is already present, and croaks on error or when no magic
- corresponds to the given signature (in case a $sig was supplied). All
- extra arguments specified after $wiz are passed to the private data
- constructor in @_[1 .. @_-1]. If the variable isn't a hash, any "uvar"
- callback of the wizard is safely ignored.
+ overwriting any other kind of magic. It returns true on success or when
+ $wiz magic is already present, and croaks on error. All extra arguments
+ specified after $wiz are passed to the private data constructor in @_[1
+ .. @_-1]. If the variable isn't a hash, any "uvar" callback of the
+ wizard is safely ignored.
# Casts $wiz onto $x, and pass '1' to the data constructor.
my $x;
If you want to overcome the possible deletion of the 'TZ' entry, you
have no choice but to rely on "store" uvar magic.
- "cast" can be called from any magical callback, and in particular from
- "data". This allows you to recursively cast magic on datastructures :
-
- my $wiz;
- $wiz = wizard
- data => sub {
- my ($var, $depth) = @_;
- $depth ||= 0;
- my $r = ref $var;
- if ($r eq 'ARRAY') {
- &cast((ref() ? $_ : \$_), $wiz, $depth + 1) for @$var;
- } elsif ($r eq 'HASH') {
- &cast((ref() ? $_ : \$_), $wiz, $depth + 1) for values %$var;
- }
- return $depth;
- },
- free => sub {
- my ($var, $depth) = @_;
- my $r = ref $var;
- print "free $r at depth $depth\n";
- ();
- };
-
- {
- my %h = (
- a => [ 1, 2 ],
- b => { c => 3 }
- );
- cast %h, $wiz;
- }
-
- When %h goes out of scope, this will print something among the lines of
- :
-
- free HASH at depth 0
- free HASH at depth 1
- free SCALAR at depth 2
- free ARRAY at depth 1
- free SCALAR at depth 3
- free SCALAR at depth 3
-
- Of course, this example does nothing with the values that are added
- after the "cast".
-
"getdata"
- getdata [$@%&*]var, [$wiz|$sig]
+ getdata [$@%&*]var, $wiz
- This accessor fetches the private data associated with the magic $wiz
- (or the signature $sig) in the variable. It croaks when $wiz or $sig do
- not represent a current valid magic object attached to the variable, and
- returns "undef" when the wizard has no data constructor or when the data
- is actually "undef".
+ This accessor fetches the private data associated with the magic $wiz in
+ the variable. It croaks when $wiz do not represent a valid magic object,
+ and returns an empty list if no such magic is attached to the variable
+ or when the wizard has no data constructor.
# Get the attached data, or undef if the wizard does not attach any.
my $data = getdata $x, $wiz;
"dispell"
- dispell [$@%&*]variable, [$wiz|$sig]
+ dispell [$@%&*]variable, $wiz
The exact opposite of "cast" : it dissociates $wiz magic from the
- variable. You can also pass the magic signature $sig as the second
- argument. This function returns true on success, 0 when no magic
- represented by $wiz or $sig could be found in the variable, and croaks
- if the supplied wizard or signature is invalid.
+ variable. This function returns true on success, 0 when no magic
+ represented by $wiz could be found in the variable, and croaks if the
+ supplied wizard is invalid.
# Dispell now.
die 'no such magic in $x' unless dispell $x, $wiz;
CONSTANTS
- "SIG_MIN"
- The minimum integer used as a signature for user-defined magic.
-
- "SIG_MAX"
- The maximum integer used as a signature for user-defined magic.
-
- "SIG_NBR"
- SIG_NBR = SIG_MAX - SIG_MIN + 1
-
"MGf_COPY"
Evaluates to true iff the 'copy' magic is available.
"VMG_COMPAT_ARRAY_PUSH_NOLEN"
True for perls that don't call 'len' magic when you push an element in a
- magical array.
+ magical array. Starting from perl 5.11.0, this only refers to pushes in
+ non-void context and hence is false.
+
+ "VMG_COMPAT_ARRAY_PUSH_NOLEN_VOID"
+ True for perls that don't call 'len' magic when you push in void context
+ an element in a magical array.
"VMG_COMPAT_ARRAY_UNSHIFT_NOLEN_VOID"
True for perls that don't call 'len' magic when you unshift in void
True iff this module could have been built with thread-safety features
enabled.
+ "VMG_FORKSAFE"
+ True iff this module could have been built with fork-safety features
+ enabled. This will always be true except on Windows where it's false for
+ perl 5.10.0 and below .
+
"VMG_OP_INFO_NAME"
Value to pass with "op_info" to get the current op name in the magic
callbacks.
Value to pass with "op_info" to get a "B::OP" object representing the
current op in the magic callbacks.
+COOKBOOK
+ Associate an object to any perl variable
+ This can be useful for passing user data through limited APIs.
+
+ {
+ package Magical::UserData;
+
+ use Variable::Magic qw/wizard cast getdata/;
+
+ my $wiz = wizard data => sub { \$_[1] };
+
+ sub ud (\[$@%*&]) : lvalue {
+ my ($var) = @_;
+ my $data = &getdata($var, $wiz);
+ unless (defined $data) {
+ &cast($var, $wiz);
+ $data = &getdata($var, $wiz);
+ die "Couldn't cast UserData magic onto the variable" unless defined $data;
+ }
+ $$data;
+ }
+ }
+
+ {
+ BEGIN { *ud = \&Magical::UserData::ud }
+
+ my $cb;
+ $cb = sub { print 'Hello, ', ud(&$cb), "!\n" };
+
+ ud(&$cb) = 'world';
+ $cb->(); # Hello, world!
+ }
+
+ Recursively cast magic on datastructures
+ "cast" can be called from any magical callback, and in particular from
+ "data". This allows you to recursively cast magic on datastructures :
+
+ my $wiz;
+ $wiz = wizard data => sub {
+ my ($var, $depth) = @_;
+ $depth ||= 0;
+ my $r = ref $var;
+ if ($r eq 'ARRAY') {
+ &cast((ref() ? $_ : \$_), $wiz, $depth + 1) for @$var;
+ } elsif ($r eq 'HASH') {
+ &cast((ref() ? $_ : \$_), $wiz, $depth + 1) for values %$var;
+ }
+ return $depth;
+ },
+ free => sub {
+ my ($var, $depth) = @_;
+ my $r = ref $var;
+ print "free $r at depth $depth\n";
+ ();
+ };
+
+ {
+ my %h = (
+ a => [ 1, 2 ],
+ b => { c => 3 }
+ );
+ cast %h, $wiz;
+ }
+
+ When %h goes out of scope, this will print something among the lines of
+ :
+
+ free HASH at depth 0
+ free HASH at depth 1
+ free SCALAR at depth 2
+ free ARRAY at depth 1
+ free SCALAR at depth 3
+ free SCALAR at depth 3
+
+ Of course, this example does nothing with the values that are added
+ after the "cast".
+
PERL MAGIC HISTORY
The places where magic is invoked have changed a bit through perl
history. Here's a little list of the most recent ones.
an element into a magical array in void context. The "push" part was
already covered by *p25854*.
+ *g9cdcb38b* : 'len' magic is called again when pushing into a
+ magical array in non-void context.
+
EXPORT
- The functions "wizard", "gensig", "getsig", "cast", "getdata" and
- "dispell" are only exported on request. All of them are exported by the
- tags ':funcs' and ':all'.
+ The functions "wizard", "cast", "getdata" and "dispell" are only
+ exported on request. All of them are exported by the tags ':funcs' and
+ ':all'.
All the constants are also only exported on request, either individually
or by the tags ':consts' and ':all'.