]> git.vpit.fr Git - perl/modules/Variable-Magic.git/blobdiff - lib/Variable/Magic.pm
A clearer introduction to magic
[perl/modules/Variable-Magic.git] / lib / Variable / Magic.pm
index 5f268a44b951fd6f5c2d280c536e4a9fe9438971..50ada382a335532c33bbffb9562d3f1eb117eae7 100644 (file)
@@ -1,6 +1,6 @@
 package Variable::Magic;
 
-use 5.007003;
+use 5.008;
 
 use strict;
 use warnings;
@@ -13,13 +13,13 @@ Variable::Magic - Associate user-defined magic to variables from Perl.
 
 =head1 VERSION
 
-Version 0.27
+Version 0.30
 
 =cut
 
 our $VERSION;
 BEGIN {
- $VERSION = '0.27';
+ $VERSION = '0.30';
 }
 
 =head1 SYNOPSIS
@@ -36,28 +36,49 @@ BEGIN {
 =head1 DESCRIPTION
 
 Magic is Perl way of enhancing objects.
-This mechanism let the user add extra data to any variable and hook syntaxical operations (such as access, assignation or destruction) that can be applied to it.
-With this module, you can add your own magic to any variable without the pain of the C API.
+This mechanism lets the user add extra data to any variable and hook syntaxical operations (such as access, assignation or destruction) that can be applied to it.
+With this module, you can add your own magic to any variable without having to write a single line of XS.
 
-Magic differs from tieing and overloading in several ways :
+You'll realize that these magic variables look a lot like tied variables.
+It's not surprising, as tied variables are implemented as a special kind of magic, just like any 'irregular' Perl variable : scalars like C<$!>, C<$(> or C<$^W>, the C<%ENV> and C<%SIG> hashes, the C<@ISA> array,  C<vec()> and C<substr()> lvalues, L<thread::shared> variables...
+They all share the same underlying C API, and this module gives you direct access to it.
+
+Still, the magic made available by this module differs from tieing and overloading in several ways :
 
 =over 4
 
 =item *
 
-Magic isn't copied on assignation (as for blessed references) : you attach it to variables, not values.
+It isn't copied on assignation.
+
+You attach it to variables, not values (as for blessed references).
 
 =item *
 
-It doesn't replace the original semantics : magic callbacks trigger before the original action take place, and can't prevent it to happen.
+It doesn't replace the original semantics.
+
+Magic callbacks trigger before the original action take place, and can't prevent it to happen.
+This makes catching individual events easier than with C<tie>, where you have to provide fallbacks methods for all actions by usually inheriting from the correct C<Tie::Std*> class and overriding individual methods in your own class.
 
 =item *
 
-It's mostly invisible at the Perl level : magical and non-magical variables cannot be distinguished with C<ref>, C<reftype> or another trick.
+It's type-agnostic.
+
+The same magic can be applied on scalars, arrays, hashes, subs or globs.
+But the same hook (see below for a list) may trigger differently depending on the the type of the variable.
 
 =item *
 
-It's notably faster, since perl's way of handling magic is lighter by nature, and there's no need for any method resolution.
+It's mostly invisible at the Perl level.
+
+Magical and non-magical variables cannot be distinguished with C<ref>, C<tied> or another trick.
+
+=item *
+
+It's notably faster.
+
+Mainly because perl's way of handling magic is lighter by nature, and because there's no need for any method resolution.
+Also, since you don't have to reimplement all the variable semantics, you only pay for what you actually use.
 
 =back
 
@@ -267,6 +288,14 @@ The perl patchlevel this module was built with, or C<0> for non-debugging perls.
 
 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
@@ -278,19 +307,21 @@ BEGIN {
 
 =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 :
@@ -317,12 +348,42 @@ C<$_[0]> is a reference to the magic object and C<@_[1 .. @_-1]> are all extra a
 
 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.
@@ -339,7 +400,7 @@ 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 @keys  = qw/sig data get set len clear free/;
+ 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;
@@ -383,6 +444,15 @@ If the variable isn't a hash, any C<uvar> callback of the wizard is safely ignor
     my $x;
     die 'error' unless cast $x, $wiz;
 
+The C<var> argument can be an array or hash value.
+Magic for those behaves like for any other scalar, except that it is dispelled when the entry is deleted from the container.
+For example, if you want to call C<POSIX::tzset> each time the C<'TZ'> environment variable is changed in C<%ENV>, you can use :
+
+    use POSIX;
+    cast $ENV{TZ}, wizard set => sub { POSIX::tzset(); () };
+
+If you want to overcome the possible deletion of the C<'TZ'> entry, you have no choice but to rely on C<store> uvar magic.
+
 =head2 C<getdata>
 
     getdata [$@%&*]var, [$wiz|$sig]
@@ -419,11 +489,13 @@ use base qw/Exporter/;
 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 ];
@@ -435,11 +507,9 @@ The only way to address this would be to return a reference.
 
 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 simultaneously 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).