Params-PatternMatch

 view release on metacpan or  search on metacpan

lib/Params/PatternMatch.pm  view on Meta::CPAN

package Params::PatternMatch;

# ABSTRACT: Pattern match-based argument binding for Perl.

use strict;
use warnings;
use B;
use Carp;
use Data::Compare;
use Exporter::Lite;
use Scalar::Util qw/blessed/;
use TryCatch;

our $COMPARATOR = Data::Compare->new;

our @EXPORT_OK = qw/as case match otherwise rest then/;

our $VERSION = '0.01';

our @args;

sub as(&) { @_ }

sub case {
  my $action = pop;
  Carp::croak('Not a CodeRef.') if ref $action ne 'CODE';

  my ($i, $j) = (0, 0);
  for (; $i < @args and $j < @_; ++$i, ++$j) {
    if (is_slurp_arg($_[$j])) {
      $_[$j]->set(@args[$i .. $#args]);
      $i = $#args;
      next;
    }
    if (is_lvalue($_[$j])) {
      $_[$j] = $args[$i];
      next;
    }
    next if $COMPARATOR->Cmp($args[$i], $_[$j]) != 0;

    return;  # Pattern didn't match.
  }
  return unless $i == @args and $j == @_ or is_slurp_arg($_[$j]);

  die Params::PatternMatch::Values->new($action->(@args));
}

sub is_lvalue($) { +(B::svref_2object(\$_[0])->FLAGS & B::SVf_READONLY) == 0 }

sub is_slurp_arg($) {
  blessed $_[0] and $_[0]->isa('Params::PatternMatch::SlurpArg');
}

sub match {
  my $patterns = pop;
  Carp::croak('Not a CodeRef.') if ref $patterns ne 'CODE';

  local *args = \@_;
  try {
    $patterns->();
  } catch (Params::PatternMatch::Values $retval) {
    return $retval->values;
  } catch ($error) {
    die $error;
  };
}

sub otherwise(&) {
  Carp::croak('Not a CodeRef.') if ref $_[0] ne 'CODE';
  die Params::PatternMatch::Values->new($_[0]->(@args));
}

sub rest(\@) { Params::PatternMatch::SlurpArg->new($_[0]) }

sub then(&) { @_ }

package Params::PatternMatch::SlurpArg;

sub new { bless $_[1] => $_[0] }

sub set { @{ $_[0] } = @_[1 .. $#_ ] }



( run in 1.445 second using v1.01-cache-2.11-cpan-5511b514fd6 )