Data-Tumbler

 view release on metacpan or  search on metacpan

lib/Data/Tumbler.pm  view on Meta::CPAN

returned by the providers. Typically the path define the current "path"
through the tree of combinations.

The providers are passed the current path, context, and payload.
The payload is cloned at each level of recursion so that any changes made to it
by providers are only visible within the scope of the generated sub-tree.

Note that although the example above shows the path, context and payload as
array references, the tumbler code makes no assumptions about them. They can be
any kinds of values.

See L<Test::WriteVariants> for a practical example use.

=head1 ATTRIBUTES

=head2 consumer

    $tumbler->consumer( sub { my ($path, $context, $payload) = @_; ... } );

Defines the code reference to call at the leafs of the generated tree of combinations.
The default is to throw an exception.

=head2 add_path

    $tumbler->add_path( sub { my ($path, $name) = @_; return [ @$path, $name ] } )

Defines the code reference to call to create a new path value that combines
the existing path and the new name. The default is shown in the example above.


=head2 add_context

    $tumbler->add_context( sub { my ($context, $value) = @_; return [ @$context, $value ] } )

Defines the code reference to call to create a new context value that combines
the existing context and the new value. The default is shown in the example above.

=cut

use Storable qw(dclone);
use Carp qw(confess);

our $VERSION = '0.010';

=head1 METHODS

=head2 new

Contructs new Data::Tumbler, deals with initial values for L</ATTRIBUTES>.

=cut

sub new {
    my ($class, %args) = @_;

    my %defaults = (
        consumer    => sub { confess "No Data::Tumbler consumer defined" },
        add_path    => sub { my ($path,    $name ) = @_; return [ @$path,    $name  ] },
        add_context => sub { my ($context, $value) = @_; return [ @$context, $value ] },
    );
    my $self = bless \%defaults => $class;

    for my $attribute (qw(consumer add_path add_context)) {
        next unless exists $args{$attribute};
        $self->$attribute(delete $args{$attribute});
    }
    confess "Unknown $class arguments: @{[ keys %args ]}"
        if %args;

    return $self;
}


sub consumer {
    my $self = shift;
    $self->{consumer} = shift if @_;
    return $self->{consumer};
}

sub add_path {
    my $self = shift;
    $self->{add_path} = shift if @_;
    return $self->{add_path};
}

sub add_context {
    my $self = shift;
    $self->{add_context} = shift if @_;
    return $self->{add_context};
}

=head2 tumble

Tumbles providers to compute variants.

=cut

sub tumble {
    my ($self, $providers, $path, $context, $payload) = @_;

    if (not @$providers) { # no more providers in this context
        $self->consumer->($path, $context, $payload);
        return;
    }

    # clone the $payload so the provider can alter it for the consumer
    # at and below this point in the tree of variants
    $payload = dclone($payload) if ref $payload;

    my ($current_provider, @remaining_providers) = @$providers;

    # call the current provider to supply the variants for this context
    # returns empty if the consumer shouldn't be called in the current context
    # returns a single (possibly nil/empty/dummy) variant if there are
    # no actual variations needed.
    my %variants = $current_provider->($path, $context, $payload);

    # for each variant in turn, call the next level of provider
    # with the name and value of the variant appended to the
    # path and context.

 view all matches for this distribution
 view release on metacpan -  search on metacpan

( run in 1.698 second using v1.00-cache-2.02-grep-82fe00e-cpan-1925d2aa809 )