NAME
Data::Walk::Graft - A way to say what should be added
SYNOPSIS
#!perl
use Data::Walk::Extracted;
use Data::Walk::Graft;
use Data::Walk::Print;
use MooseX::ShortCut::BuildInstance qw( build_instance );
my $gardener = build_instance(
package => 'Jordan::Porter',
superclasses =>['Data::Walk::Extracted'],
roles =>[qw( Data::Walk::Graft Data::Walk::Clone Data::Walk::Print )],
sorted_nodes =>{
HASH => 1,
},# For demonstration consistency
#Until Data::Walk::Extracted and ::Graft support these types
#(watch Data-Walk-Extracted on github)
skipped_nodes =>{
OBJECT => 1,
CODEREF => 1,
},
graft_memory => 1,
);
my $tree_ref = {
Helping =>{
KeyTwo => 'A New Value',
KeyThree => 'Another Value',
OtherKey => 'Something',
},
MyArray =>[
'ValueOne',
'ValueTwo',
'ValueThree',
],
};
$gardener->graft_data(
scion_ref =>{
Helping =>{
OtherKey => 'Otherthing',
},
MyArray =>[
'IGNORE',
{
What => 'Chicken_Butt!',
},
'IGNORE',
'IGNORE',
'ValueFive',
],
},
tree_ref => $tree_ref,
);
$gardener->print_data( $tree_ref );
print "Now a list of -" . $gardener->number_of_scions . "- grafted positions\n";
$gardener->print_data( $gardener->get_grafted_positions );
#####################################################################################
# Output of SYNOPSIS
# 01 {
# 02 Helping => {
# 03 KeyThree => 'Another Value',
# 04 KeyTwo => 'A New Value',
# 05 OtherKey => 'Otherthing',
# 06 },
# 07 MyArray => [
# 08 'ValueOne',
# 09 {
# 10 What => 'Chicken_Butt!',
# 11 },
# 12 'ValueThree',
# 13 undef,
# 14 'ValueFive',
# 15 ],
# 16 },
# 17 Now a list of -3- grafted positions
# 18 [
# 19 {
# 20 Helping => {
# 21 OtherKey => 'Otherthing',
# 22 },
# 23 },
# 24 {
# 25 MyArray => [
# 26 undef,
# 27 {
# 28 What => 'Chicken_Butt!',
# 29 },
# 30 ],
# 31 },
# 32 {
# 33 MyArray => [
# 34 undef,
# 35 undef,
# 36 undef,
# 37 undef,
# 38 'ValueFive',
# 39 ],
# 40 },
# 41 ],
#####################################################################################
DESCRIPTION
This Moose::Role contains methods for adding a new branch ( or three ) to an existing data ref. The method used to do this is graft_data using Data::Walk::Extracted. Grafting is accomplished by sending a $scion_ref that has additions that need to be made to a $tree_ref. Anything in the scion ref that does not exist in the tree ref is grafted to the tree ref. Anytime the scion_ref is different from the tree_ref the scion_ref branch will replace the tree_ref branch!
USE
This is a Moose::Role specifically designed to be used with Data::Walk::Extracted . It can be combined traditionaly to the ~::Extracted class using Moose or at run time. see Moose::Util and MooseX::ShortCut::BuildInstance for more information.
Deep cloning the graft
In general grafted data refs are subject to external modification by changing the data in that ref from another location of the code. This module assumes that you don't want to do that! As a consequence it checks to see if a 'deep_clone' method has been provided to the class that consumes this role. If so it calls that method on the data ref to be grafted. One possiblity is to add the Role Data::Walk::Clone to your object so that a deep_clone method is automatically available (all compatability testing complete). If you choose to add your own deep_clone method it will be called like this;
my $clone_value = ( $self->can( 'deep_clone' ) ) ?
$self->deep_clone( $scion_ref ) : $scion_ref ;
Where $self is the active object instance.
Grafting unsupported node types
If you want to add data from another ref to a current ref and the add ref contains nodes that are not supported then you need to skip those nodes in the cloning process.
Attributes
Data passed to ->new when creating an instance. For modification of these attributes see Methods. The ->new function will either accept fat comma lists or a complete hash ref that has the possible attributes as the top keys. Additionally some attributes that have all the following methods; get_$attribute, set_$attribute, has_$attribute, and clear_$attribute, can be passed to graft_data and will be adjusted for just the run of that method call. These are called 'one shot' attributes. The class and each role (where applicable) in this package have a list of supported one shot attributes .
graft_memory
Definition: When running a 'graft_data' operation any branch of the $scion_ref that does not terminate past the end of the tree ref or differ from the tree_ref will not be used. This attribute turns on tracking of the actual grafts made and stores them for review after the method is complete. This is a way to know if a graft was actually implemented. The potentially awkward wording of the associated methods is done to make this an eligible 'one shot' attribute.
Default undefined = don't remember the grafts
Range 1 = remember the grafts | 0 = don't remember
(see also)
Data::Walk::Extracted Attributes
Methods
graft_data( %args|$arg_ref )
Definition: This is a method to add defined elements to targeted parts of a data reference.
Accepts: a hash ref with the keys 'scion_ref' and 'tree_ref'. The scion ref can contain more than one place that will be grafted to the tree data.
tree_ref This is the primary data ref that will be manipulated and returned changed. If an empty 'tree_ref' is passed then the 'scion_ref' is returned in it's entirety.
scion_ref This is a data ref that will be used to graft to the 'tree_ref'. For the scion ref to work it must contain the parts of the tree ref below the new scions as well as the scion itself. During data walking when a difference is found graft_data will attempt to clone the remaining untraveled portion of the 'scion_ref' and then graft the result to the 'tree_ref' at that point. Any portion of the tree ref that differs from the scion ref at that point will be replaced. If graft_memory is on then a full recording of the graft with a map to the data root will be saved in the object. The word 'IGNORE' can be used in either an array position or the value for a key in a hash ref. This tells the program to ignore differences (in depth) past that point. For example if you wish to change the third element of an array node then placing 'IGNORE' in the first two positions will cause 'graft_data' to skip the analysis of the first two branches. This saves replicating deep references in the scion_ref while also avoiding a defacto 'prune' operation. If an array position in the scion_ref is set to 'IGNORE' in the 'scion_ref' but a graft is made below the node with IGNORE then the grafted tree will contain 'IGNORE' in that element of the array (not undef). Any positions that exist in the tree_ref that do not exist in the scion_ref will be ignored. If an empty 'scion_ref' is sent then the code will cluck and then return the 'tree_ref'.
[attribute name] - attribute names are accepted with temporary attribute settings. These settings are temporarily set for a single "graft_data" call and then the original attribute values are restored. For this to work the the attribute must meet the necessary criteria.
Example
$grafted_tree_ref = $self->graft_data(
tree_ref => $tree_data,
scion_ref => $addition_data,
graft_memory => 0,
);
Returns: The $tree_ref with any changes (possibly deep cloned)
has_graft_memory
Definition: This will indicate if the attribute graft_memory is active
Accepts: nothing
Returns: 1 or 0
set_graft_memory( $Bool )
Definition: This will set the graft_memory attribute
Accepts: 1 or 0
Returns: nothing
get_graft_memory
Definition: This will return the current value for the graft_memory attribute.
Accepts: nothing
Returns: 1 or 0
clear_graft_memory
Definition: This will clear the graft_memory attribute.
Accepts: nothing
Returns: nothing
number_of_scions
Definition: This will return the number of scion points grafted in the most recent graft action if the graft_memory attribute is on.
Accepts: nothing
Returns: a positive integer
has_grafted_positions
Definition: This will indicate if any grafted positions were saved.
Accepts: nothing
Returns: 1 or 0
get_grafted_positions
Definition: This will return any saved grafted positions.
Accepts: nothing
Returns: an ARRAY ref of grafted positions. This will include one full data branch to the root for each position actually grafted.
Caveat utilitor
Supported Node types
- ARRAY
- HASH
- SCALAR
- Other node support
-
Support for Objects is partially implemented and as a consequence graft_data won't immediatly die when asked to graft an object. It will still die but on a dispatch table call that indicates where there is missing object support not at the top of the node.
Supported one shot attributes
- graft_memory
GLOBAL VARIABLES
$ENV{Smart_Comments}
The module uses Smart::Comments if the '-ENV' option is set. The 'use' is encapsulated in an if block triggered by an environmental variable to comfort non-believers. Setting the variable $ENV{Smart_Comments} in a BEGIN block will load and turn on smart comment reporting. There are three levels of 'Smartness' available in this module '###', '####', and '#####'.
SUPPORT
TODO
1. Add Log::Shiras debugging in exchange for Smart::Comments
2. Support grafting through class instance nodes (can - should you even do this?)
3. Support grafting through CodeRef nodes (can - should you even do this?)
4. Support grafting through REF nodes
5. A possible depth check to ensure the scion is deeper than the tree_ref
Implemented with an attribute that turns the feature on and off. The goal would be to eliminate unintentional swapping of small branches for large branches. This feature has some overhead downside and may not be usefull so I'm not sure if it makes sence yet.
AUTHOR
COPYRIGHT
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
The full text of the license can be found in the LICENSE file included with this module.
This software is copyrighted (c) 2012, 2016 by Jed Lund.
Dependencies
Data::Walk::Extracted::Dispatch
Carp - cluck
SEE ALSO
Log::Shiras::Unhide - Can use to unhide '###InternalExtracteDGrafT' tags
Log::Shiras::TapWarn - to manage the output of exposed '###InternalExtracteDGrafT' lines
Data::Dumper - used in the '###InternalExtracteDGrafT' lines