The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

CXC::Data::Visitor - Invoke a callback on every element at every level of a data structure.

VERSION

version 0.03

SYNOPSIS

  use CXC::Data::Visitor 'visit', 'RESULT_CONTINUE';

  my $hoh = { fruit => { berry => 'purple' }, };

  visit(
      $hoh,
      sub {
          my ( $key, $vref ) = @_;
          $$vref = 'blue' if $key eq 'berry';
          return RESULT_CONTINUE;
      } );

  say $hoh->{fruit}{berry}    # 'blue'

DESCRIPTION

CXC::Data::Visitor provides a means of performing a depth first traversal of a data structure. There are similar modules on CPAN ("SEE ALSO"); this module provides a few extras:

  • The traversal may be aborted.

  • A container (hash or array) may be revisited if the callback changes it.

  • User selectable behavior upon detection of a traversal cycle.

  • The complete path from the structure route to an element (both the ancestor containers and the keys and indexes required to traverse the path) is available.

SUBROUTINES

visit

   ( $completed, $context, $metadata ) = visit( $struct, $callback, %opts );

Perform a depth-first traversal of $struct, invoking $callback on containers (hashes and arrays) and terminal elements in $struct.

  • Blessed hashes or arrays are treated as terminal elements and are not further traversed.

  • Hashes are traversed in sorted key order.

  • Cycles are detected upon traversing a container a second time in a depth first search.

  • Containers that can be reached multiple times without cycling, e.g.

      %hash = ( a => { b => 1 }, );
      $hash{c} = $hash{a};

    are visited once per parent, e.g.

      {a}, {a}{b}, {a}{b}[0]
      {c}, {c}{b}, {c}{b}[0]
  • $callback is first invoked on a container and then its elements. Given

      { a => { b => [ 0 ], c => 2 } }

    the callback order is

      {a}, {a}{b}, {a}{b}[0], {a}{c}

"visit" returns the following:

$completed => Boolean

true if all elements were visited, false if $callback requested a premature return.

$context => hash

a hash made available to $callback to stash data

$metadata => hash

collected metadata. See "$metadata" below.

$callback will be called as:

  $handle_return = $callback->( $kydx, $vref, $context, $metadata );

and should return one of the following (see "EXPORTS" to import the constants):

RESULT_CONTINUE

The process of visiting elements should continue.

RESULT_RETURN

"visit" should return immediately to the caller.

RESULT_REVISIT_CONTAINER

Further processing of the elements in the current container should stop and the container should be revisited. This allows "$callback" to modify the container and have it reprocessed.

To avoid inadvertent infinite loops, a finite number of revisits is allowed during a traversal of a container (see "revisit_limit"). Containers with multiple parents are traversed once per parent; The limit is reset for each traversal.

"$callback" is passed

$kydx

the key or index into $container of the element being visited.

$vref

a reference to the value of the element being visited. Use $$vref to get the actual value.

$context

A hash which can be used by the caller to stash data.

$metadata

A hash of state information kept by CXC::Data::Visitor, but which may be of interest to the callback:

container

a reference to the hash or array which contains the element being visited.

path

An array which contains the path (keys and indices) used to arrive at the current element from $struct.

ancestors

An array contains the ancestor containers of the current element.

%opts may contain the following entries:

context => hashref

A reference to a hash passed to "$callback", for the caller's use. It defaults to a freshly created hash.

cycle => CYCLE_TRUNCATE | CYCLE_DIE | CYCLE_CONTINUE | <$coderef>

How to handle cycles in the data structure.

See "EXPORTS" to import the constant values.

CYCLE_DIE

Throw an exception (the default).

CYCLE_CONTINUE

Pretend we haven't seen it before. Will cause stack exhaustion if $callback does handle this.

CYCLE_TRUNCATE

Truncate before entering the cycle a second time.

$coderef

Examine the situation and request a particular resolution. $coderef is called as

  $coderef->( $container, $context, $metadata );

where $container is the hash or array which has already been traversed. See below for "$context" and "$metadata".

$coderef should return one of CYCLE_DIE, CYCLE_CONTINUE, or CYCLE_TRUNCATE, indicating what should be done.

visit => VISIT_CONTAINER | VISIT_LEAF | VISIT_ALL

The parts of the structure that will trigger a callback. See "EXPORTS" to import the constants.

VISIT_CONTAINER

Invoke "$callback" on containers. For example, the elements in the following structure

  $struct = { a => { b => 1, c => [ 2, 3 ] } }

passed to "$callback" are:

  a => {...}  # $struct->{a}
  c => [...]  # $struct->{c}
VISIT_LEAF

Invoke "$callback" on terminal (leaf) elements. For example, the elements in the following structure

  $struct = { a => { b => 1, c => [ 2, 3 ] } }

passed to "$callback" are:

  b => 1  # $struct->{a}{b}
  0 => 2  # $struct->{a}{c}[0]
  1 => 3  # $struct->{a}{c}[1]
VISIT_ALL

Invoke "$callback" on all elements. This is the default.

revisit_limit

If "$callback" returns RESULT_REVISIT_CONTAINER, then the parent container of the element is re-scanned for its elements and revisited. To avoid an inadvertent infinite loop, an exception is thrown if the parent container is revisited more than this number of times. It defaults to 10;

EXPORTS

This module uses Exporter::Tiny, which provides enhanced import utilities.

The following symbols may be exported:

  visit
  VISIT_CONTAINER VISIT_LEAF VISIT_ALL
  CYCLE_DIE CYCLE_CONTINUE CYCLE_TRUNCATE
  RESULT_RETURN RESULT_CONTINUE RESULT_REVISIT_CONTAINER

The available tags and their respective imported symbols are:

all

Import all symbols.

results
 RESULT_RETURN RESULT_CONTINUE RESULT_REVISIT_CONTAINER
cycles
 CYCLE_DIE CYCLE_CONTINUE CYCLE_TRUNCATE
visits
 VISIT_CONTAINER VISIT_LEAF VISIT_ALL
constants

Import tags results, cycles, visits.

SUPPORT

Bugs

Please report any bugs or feature requests to bug-cxc-data-visitor@rt.cpan.org or through the web interface at: https://rt.cpan.org/Public/Dist/Display.html?Name=CXC-Data-Visitor

Source

Source is available at

  https://gitlab.com/djerius/cxc-data-visitor

and may be cloned from

  https://gitlab.com/djerius/cxc-data-visitor.git

SEE ALSO

Please see those modules/websites for more information related to this module.

AUTHOR

Diab Jerius <djerius@cpan.org>

COPYRIGHT AND LICENSE

This software is Copyright (c) 2024 by Smithsonian Astrophysical Observatory.

This is free software, licensed under:

  The GNU General Public License, Version 3, June 2007