Data::Walk::Extracted

An extracted dataref walker

SYNOPSIS

This is a contrived example! For more functional (complex) examples see the roles in this package.

	package Data::Walk::MyRole;
	use Moose::Role;
	requires '_process_the_data';
	use MooseX::Types::Moose qw(
			Str
			ArrayRef
			HashRef
		);

	my $mangle_keys = {
		Hello_ref => 'primary_ref',
		World_ref => 'secondary_ref',
	};

	#########1 Public Method      3#########4#########5#########6#########7#########8

	sub mangle_data{
		my ( $self, $passed_ref ) = @_;
		@$passed_ref{ 'before_method', 'after_method' } = 
			( '_mangle_data_before_method', '_mangle_data_after_method' );
		### Start recursive parsing
		$passed_ref = $self->_process_the_data( $passed_ref, $mangle_keys );
		### End recursive parsing with: $passed_ref
		return $passed_ref->{Hello_ref};
	}

	#########1 Private Methods    3#########4#########5#########6#########7#########8

	### If you are at the string level merge the two references
	sub _mangle_data_before_method{
		my ( $self, $passed_ref ) = @_;
		if( 
			is_Str( $passed_ref->{primary_ref} ) and 
			is_Str( $passed_ref->{secondary_ref} )		){
			$passed_ref->{primary_ref} .= " " . $passed_ref->{secondary_ref};
		}
		return $passed_ref;
	}

	### Strip the reference layers on the way out
	sub _mangle_data_after_method{
		my ( $self, $passed_ref ) = @_;
		if( is_ArrayRef( $passed_ref->{primary_ref} ) ){
			$passed_ref->{primary_ref} = $passed_ref->{primary_ref}->[0];
		}elsif( is_HashRef( $passed_ref->{primary_ref} ) ){
			$passed_ref->{primary_ref} = $passed_ref->{primary_ref}->{level};
		}
		return $passed_ref;
	}

	package main;
	use Modern::Perl;
	use MooseX::ShortCut::BuildInstance qw(
			build_instance
		);
	my 	$AT_ST = build_instance( 
			package			=> 'Greeting',
			superclasses	=> [ 'Data::Walk::Extracted' ],
			roles			=> [ 'Data::Walk::MyRole' ],
		);
	print $AT_ST->mangle_data( {
			Hello_ref	=> { level =>[ { level =>[ 'Hello' ] } ] },
			World_ref	=> { level =>[ { level =>[ 'World' ] } ] },
		} ) . "\n";
	
	
    
	#################################################################################
	#     Output of SYNOPSIS
	# 01:Hello World
	#################################################################################

DESCRIPTION

This module takes a data reference (or two) and recursivly travels through it(them). Where the two references diverge the walker follows the primary data reference. At the beginning and end of each node the code will attempt to call a method using data from the current location of the node.

Caveat utilitor

This is not an extention of Data::Walk

This module uses the 'defined or' ( //= ) and so requires perl 5.010 or higher.

This is a Moose based data handling class. Many coders will tell you Moose and data manipulation don't belong together. They are most certainly right in speed intensive circumstances.

Recursive parsing is not a good fit for all data since very deep data structures will burn a fair amount of perl memory! Meaning that as the module recursively parses through the levels perl leaves behind snapshots of the previous level that allow perl to keep track of it's location.

The core class has no external effect. All output comes from addtions to the class.

Both data references are effectivly deep cloned during this process. There is an attribute to control this behavior.

What is the unique value of this package?

With the recursive part of data walking extracted, the various functionalities desired when walking the data can be modularized without copying this code. This also allows diverse and targeted data parsing without dragging along a Kitchen sink API.

Acknowledgement of MJD

This is one possible implementation of the concept of extracted data walking from Higher-Order-Perl Chapter 1 by Mark Jason Dominus. The book is well worth the money! With that said I diverged from MJD purity in two ways. This is object oriented code not functional code. Second, like the MJD equivalent, the code does nothing on its own. Unlike the MJD equivalent it looks for methods provided in a role or class extention at the appropriate places for action. The MJD equivalent expects to use a passed CodeRef at the action points. There is clearly some overhead associated with both of these differences. I made those choices consciously and if that upsets you do not hassle MJD!

Extending Data::Walk::Extracted

All action taken during the data walking must be initiated by implementation of action methods that do not exist in this Class. They can be added with a Moose::Role, by extending the class, or joined to the class later. See MooseX::ShortCut::BuildInstance. or Moose::Util for more class building information.

See Data::Walk::Extracted for more documentation.

Install from Source

(for example git)

1. Download a compressed file with the code
2. Extract the code from the compressed file
3. cd into the extracted directory

(For Windows find what version of make was used to compile your perl)

perl  -V:make

Then (modifying make based on the previous step)

perl Makefile.PL
make
make test
make install
make clean