| Attribute-Overload-Match documentation | Contained in the Attribute-Overload-Match distribution. |
Attribute::Overload::Match - argument-dependent handlers for overloaded operators
The module is a wrapper for overload, that provides a simple syntax for calling different operator handlers for different passed arguments. The idea is a curious ( but probably not a very practical ) mix of Attribute::Overload and Sub::PatMat .
use Attribute::Overload::Match;
Suppose we declare a class that overloads operations on integers:
sub new($) { my $x = $_[0]; bless \$x, __PACKAGE__ }
sub val($) { ${$_[0]} }
sub eq : op(==) { val(shift) == shift }
sub subtract : op(-) { new val(shift) - shift }
sub mul : op(*) { new val(shift) * shift }
sub add : op(+) { new val(shift) + shift }
sub qq : op("") { val(shift) }
sub le : op(<) { val(shift) < shift }
...
then we can change meaning of some operators with a touch of functional style:
no warnings 'redefine';
sub fac : op(!,1) { new 1 }
sub fac : op(!) { !($_[0] - 1) * $_[0] }
or
sub fib : op(~,<2) { new 1 }
sub fib : op(~) { ~( $_[0] - 1) + ~($_[0] - 2) }
(if you don't like no warnings 'redefine', just use different sub names for fac etc)
thus
my $x = !new(10); print "$x\n"; 3628800
and
my $x = ~new(10); print "$x\n"; 89
The only syntax available here is syntax that is passed to op attributes,
which is in general sub mysub : op(OPERATOR,CODE[,CODE[,CODE ...]]), where
OPERATOR belongs to strings defined in overload ( such as +, [],
"" etc), and CODE strings are perl code, matching a parameter. However,
for the sake of readability, CODE can be also one of the following
signatures:
Parameter is never checked
Pataremeter must be defined and be equal (==) to the value if the string
Parameter must be defined and be equal (eq) to the value if the string
The string defined as a class name. Parameter must be defined and be an instance of the class (or its descendant).
//Parameter must be defined.
<,>,lt,gt,eq,==,ne,!= followed by an expressionParameter must be defined and return true when compared with the expression using given comparison operator
Anything else is passed directly to eval and is treated in a boolean context
thereafter.
Thanks to Anton Berezin for ideas on Sub::PatMat .
Thanks to H. Merijn Brandt for //.
Attribute::Overload, Sub::PatMat, overload.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
Dmitry Karasik <dmitry@karasik.eu.org>
| Attribute-Overload-Match documentation | Contained in the Attribute-Overload-Match distribution. |
# $Id: Match.pm,v 1.1.1.1 2007/02/28 11:49:47 dk Exp $ package Attribute::Overload::Match; use strict; use warnings; use Attribute::Handlers; our ( %ops, $VERSION); $VERSION = '0.01'; sub handle { my ( $pkg, $op) = ( shift, shift ); NEXTARG: for my $arg ( @{$ops{$pkg}{$op}}) { my $sym = $$arg[0]; next if $#$arg > @_; for ( my $x = 1; $x < @$arg; $x++) { next NEXTARG unless $arg-> [$x]->( $_[$x - 1]); } goto $sym; } die "Nothing matches $op in $pkg"; } sub parse { my @r; for my $v ( @_) { $v =~ s/^\s*//; $v =~ s/\s*$//; if ( $v eq '') { push @r, sub { 1 }; } elsif ( $v =~ /^\d/) { push @r, sub { defined $_[0] and $_[0] == $v }; } elsif ( $v =~ /^'(.*)'$/ ) { $v = $1; push @r, sub { defined $_[0] and $_[0] eq $v }; } elsif ( $v =~ /^[A-Z]/) { push @r, sub { defined $_[0] and ref($_[0]) and $_[0]->isa($v) }; } elsif ( $v eq '//') { push @r, sub { defined $_[0] }; } elsif ( $v =~ /^(<|>|lt|gt|eq|==)\s*(.*)$/) { $v = eval "sub { defined \$_[0] and \$_[0] $v ;}"; die $@ if $@; push @r, $v; } elsif ( $v =~ /^(ne|!=)\s*(.*)$/) { $v = eval "sub { not defined \$_[0] or \$_[0] $v ;}"; die $@ if $@; push @r, $v; } else { $v = eval "sub { $v }"; die $@ if $@; push @r, $v; } } @r; } sub UNIVERSAL::op : ATTR(CODE,RAWDATA) { my ($pkg, $sub, $data) = @_[0,2,4]; require overload; my ($op, @arg) = split( ',', $data); overload::OVERLOAD( $pkg, $op, sub { handle( $pkg, $op, @_ ) } ) unless exists $ops{$pkg}{$op}; push @{$ops{$pkg}{$op}}, [ $sub, parse @arg ]; } 1;