t/95-portability-files.t
t/99-kwalitee.t
t/lib/Variable/Magic/TestDieRequired.pm
+t/lib/Variable/Magic/TestValue.pm
t/lib/Variable/Magic/TestWatcher.pm
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.
+Magic callbacks usually trigger before the original action take place, and can't prevent it to happen.
+This also 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 *
use strict;
use warnings;
-use Test::More tests => 2 * 4 + 2 + 1;
+use Test::More tests => (2 * 4 + 2) + (2 * 2) + 1;
use Variable::Magic qw/cast/;
use lib 't/lib';
use Variable::Magic::TestWatcher;
+use Variable::Magic::TestValue;
my $wiz = init_watcher 'get', 'get';
$b = watch { "X${a}Y" } { get => 1 }, 'interpolate';
is $b, "X${n}Y", 'get: interpolate correctly';
+
+{
+ my $val = 0;
+
+ init_value $val, 'get', 'get';
+
+ value { my $x = $val } \0;
+}
use strict;
use warnings;
-use Test::More tests => 2 * 5 + 3 + 1;
+use Test::More tests => (2 * 5 + 3) + (2 * 2 + 1);
use Variable::Magic qw/cast/;
use lib 't/lib';
use Variable::Magic::TestWatcher;
+use Variable::Magic::TestValue;
my $wiz = init_watcher 'set', 'set';
watch { --$a } { set => 1 }, 'decrement';
is $a, $n, 'set: decrement correctly';
+
+{
+ my $val = 0;
+
+ init_value $val, 'set', 'set';
+
+ value { $val = 1 } \1;
+}
use strict;
use warnings;
-use Test::More tests => 33;
+use Test::More tests => 33 + (2 * 2 + 1);
-use Variable::Magic qw/wizard cast VMG_COMPAT_SCALAR_LENGTH_NOLEN/;
+use Variable::Magic qw/wizard cast dispell VMG_COMPAT_SCALAR_LENGTH_NOLEN/;
+
+use lib 't/lib';
+use Variable::Magic::TestValue;
my $c = 0;
is $d, 5, 'len: get utf8 scalar length have correct default length';
is $b, $d, 'len: get utf8 scalar length correctly';
}
+
+{
+ my @val = (4 .. 6);
+
+ my $wv = init_value @val, 'len', 'len';
+
+ value { $val[-1] = 8 } [ 4, 5, 6 ];
+
+ dispell @val, $wv;
+ is_deeply \@val, [ 4, 5, 8 ], 'len: after value';
+}
use strict;
use warnings;
-use Test::More tests => 2 * 5 + 2 + 1;
+use Test::More tests => (2 * 5 + 2) + (2 * 2 + 1) + 1;
-use Variable::Magic qw/cast/;
+use Variable::Magic qw/cast dispell/;
use lib 't/lib';
use Variable::Magic::TestWatcher;
+use Variable::Magic::TestValue;
my $wiz = init_watcher 'clear', 'clear';
watch { %h = () } { clear => 1 }, 'clear hash';
is_deeply \%h, { }, 'clear: clear hash correctly';
+
+{
+ my @val = (4 .. 6);
+
+ my $wv = init_value @val, 'clear', 'clear';
+
+ value { @val = () } [ 4 .. 6 ];
+
+ dispell @val, $wv;
+ is_deeply \@val, [ ], 'clear: value after';
+}
use Test::More;
-use Variable::Magic qw/cast MGf_COPY/;
+use Variable::Magic qw/cast dispell MGf_COPY/;
if (MGf_COPY) {
- plan tests => 2 + (2 * 5 + 3) + (2 * 9 + 6) + 1;
+ plan tests => 2 + ((2 * 5 + 3) + (2 * 2 + 1)) + (2 * 9 + 6) + 1;
} else {
plan skip_all => 'No copy magic for this perl';
}
use lib 't/lib';
use Variable::Magic::TestWatcher;
+use Variable::Magic::TestValue;
my $wiz = init_watcher 'copy', 'copy';
SKIP: {
eval "use Tie::Array";
- skip 'Tie::Array required to test copy magic on arrays', 2 * 5 + 3 if $@;
+ skip 'Tie::Array required to test copy magic on arrays'
+ => (2 * 5 + 3) + (2 * 2 + 1) if $@;
diag "Using Tie::Array $Tie::Array::VERSION" if defined $Tie::Array::VERSION;
tie my @a, 'Tie::StdArray';
ok $s, 'copy: tied array exists correctly';
watch { undef @a } { }, 'tied array undef';
+
+ {
+ tie my @val, 'Tie::StdArray';
+ @val = (4 .. 6);
+
+ my $wv = init_value @val, 'copy', 'copy';
+
+ value { $val[3] = 8 } [ 4 .. 6 ];
+
+ dispell @val, $wv;
+ is_deeply \@val, [ 4 .. 6, 8 ], 'copy: value after';
+ }
}
SKIP: {
use Variable::Magic qw/wizard cast dispell VMG_UVAR/;
if (VMG_UVAR) {
- plan tests => 2 * 15 + 12 + 14 + 1;
+ plan tests => 2 * 15 + 12 + 14 + (4 * 2 * 2 + 1 + 1) + 1;
} else {
plan skip_all => 'No nice uvar magic for this perl';
}
use lib 't/lib';
use Variable::Magic::TestWatcher;
+use Variable::Magic::TestValue;
my $wiz = init_watcher [ qw/fetch store exists delete/ ], 'uvar';
is_deeply \%h3, { a => 3, b => 5, c => 5 + $i },
"uvar: change readonly key in store correcty ($i)";
}
+
+{
+ my %val = (apple => 1);
+
+ init_value %val, 'fetch', 'uvar';
+
+ value { my $x = $val{apple} } { apple => 1 }, 'value store';
+}
+
+{
+ my %val = (apple => 1);
+
+ my $wv = init_value %val, 'store', 'uvar';
+
+ value { $val{apple} = 2 } { apple => 1 }, 'value store';
+
+ dispell %val, $wv;
+ is_deeply \%val, { apple => 2 }, 'uvar: value after store';
+}
+
+{
+ my %val = (apple => 1);
+
+ init_value %val, 'exists', 'uvar';
+
+ value { my $x = exists $val{apple} } { apple => 1 }, 'value exists';
+}
+
+{
+ my %val = (apple => 1, banana => 2);
+
+ my $wv = init_value %val, 'delete', 'uvar';
+
+ value { delete $val{apple} } { apple => 1, banana => 2 }, 'value delete';
+
+ dispell %val, $wv;
+ is_deeply \%val, { banana => 2 }, 'uvar: value after delete';
+}
--- /dev/null
+package Variable::Magic::TestValue;
+
+use strict;
+use warnings;
+
+use Test::More;
+
+use Variable::Magic qw/wizard cast/;
+
+use base qw/Exporter/;
+
+our @EXPORT = qw/init_value value/;
+
+our ($exp, $prefix, $desc);
+
+sub value_cb {
+ my $data = $_[1];
+ return if $data->{guard};
+ local $data->{guard} = 1;
+ local $Test::Builder::Level = ($Test::Builder::Level || 0) + 3;
+ is_deeply $_[0], $exp, $desc;
+ ()
+}
+
+sub init_value (\[$@%&*]$;$) {
+ my $type = $_[1];
+ $prefix = (defined) ? "$_: " : '' for $_[2];
+ my $wiz = eval "wizard data => sub { +{ guard => 0 } }, $type => \\&value_cb";
+ is $@, '', $prefix . 'wizard() doesn\'t croak';
+ eval { &cast($_[0], $wiz, $prefix) };
+ is $@, '', $prefix . 'cast() doesn\'t croak';
+ return $wiz;
+}
+
+sub value (&$;$) {
+ my ($code, $_exp, $_desc) = @_;
+ my $want = wantarray;
+ $_desc = 'value' unless defined $desc;
+ $_desc = $prefix . $_desc;
+ my @ret;
+ {
+ local $Test::Builder::Level = ($Test::Builder::Level || 0) + 1;
+ local $exp = $_exp;
+ local $desc = $_desc;
+ if (defined $want and not $want) { # scalar context
+ $ret[0] = eval { $code->() };
+ } else {
+ @ret = eval { $code->() };
+ }
+ is $@, '', $desc . ' doesn\'t croak';
+ }
+ return $want ? @ret : $ret[0];
+}
+
+1;