CatalystX::Usul::File::HashMerge - Merge hashes with update flag


CatalystX-Usul documentation Contained in the CatalystX-Usul distribution.

Index


Code Index:

Name

Top

CatalystX::Usul::File::HashMerge - Merge hashes with update flag

Version

Top

0.3.$Revision: 597 $

Synopsis

Top

   use CatalystX::Usul::File::HashMerge;

   $class   = q(CatalystX::Usul::File::HashMerge);
   $updated = $class->merge( $src, $dest_ref, $condition );

Description

Top

Merge the attributes from the source hash ref into destination ref

Subroutines/Methods

Top

merge

   $class = q(CatalystX::Usul::File::HashMerge);
   $bool  = $class->merge( $src, $dest_ref, $condition );

Only merge the attributes from $src to $dest_ref if the $condition coderef evaluates to true. Return true if the destination ref was updated

Diagnostics

Top

None

Configuration and Environment

Top

None

Dependencies

Top

None

Incompatibilities

Top

There are no known incompatibilities in this module

Bugs and Limitations

Top

There are no known bugs in this module. Please report problems to the address below. Patches are welcome

Author

Top

Peter Flanigan, <Support at RoxSoft.co.uk>

License and Copyright

Top


CatalystX-Usul documentation Contained in the CatalystX-Usul distribution.

# @(#)$Id: HashMerge.pm 597 2009-06-20 22:05:52Z pjf $

package CatalystX::Usul::File::HashMerge;

use strict;
use warnings;
use version; our $VERSION = qv( sprintf '0.3.%d', q$Rev: 597 $ =~ /\d+/gmx );

use Carp;

sub merge {
   my ($self, $src, $dest_ref, $condition) = @_; my $updated = 0;

   croak 'No destination reference specified' unless ($dest_ref);

   $src ||= {}; ${ $dest_ref } ||= {}; $condition ||= sub { return 1 };

   for my $attr (__get_src_attributes( $condition, $src )) {
      if (defined $src->{ $attr }) {
         my $res = $self->_merge_attr
            ( $src->{ $attr }, \${ $dest_ref }->{ $attr } );

         $updated ||= $res;
      }
      elsif (exists ${ $dest_ref }->{ $attr }) {
         delete ${ $dest_ref }->{ $attr };
         $updated = 1;
      }
   }

   ${ $dest_ref }->{name} = $src->{name} if ($updated);

   return $updated;
}

# Private methods

sub _merge_attr {
   my ($self, $from, $to_ref) = @_; my $updated = 0; my $to = ${ $to_ref };

   if ($to and ref $to eq q(ARRAY)) {
      $updated = $self->_merge_attr_arrays( $from, $to );
   }
   elsif ($to and ref $to eq q(HASH)) {
      $updated = $self->_merge_attr_hashes( $from, $to );
   }
   elsif ((not $to and defined $from) or ($to and $to ne $from)) {
      $updated = 1; ${ $to_ref } = $from;
   }

   return $updated;
}

sub _merge_attr_arrays {
   my ($self, $from, $to) = @_; my $updated = 0;

   for (0 .. $#{ $to }) {
      if ($from->[ $_ ]) {
         my $res = $self->_merge_attr( $from->[ $_ ], \$to->[ $_ ] );

         $updated ||= $res;
      }
      elsif ($to->[ $_ ]) {
         splice @{ $to }, $_;
         $updated = 1;
         last;
      }
   }

   if (@{ $from } > @{ $to }) {
      push @{ $to }, (splice @{ $from }, $#{ $to } + 1);
      $updated = 1;
   }

   return $updated;
}

sub _merge_attr_hashes {
   my ($self, $from, $to) = @_; my $updated = 0;

   for (keys %{ $to }) {
      if ($from->{ $_ }) {
         my $res = $self->_merge_attr( $from->{ $_ }, \$to->{ $_ } ) ;

         $updated ||= $res;
      }
      elsif ($to->{ $_ }) {
         delete $to->{ $_ };
         $updated = 1;
      }
   }

   if (keys %{ $from } > keys %{ $to }) {
      for (keys %{ $from }) {
         if ($from->{ $_ } and not exists $to->{ $_ }) {
            $to->{ $_ } = $from->{ $_ };
            $updated = 1;
         }
      }
   }

   return $updated;
}

# Private subroutines

sub __get_src_attributes {
   my ($condition, $src) = @_;

   return grep { not m{ \A _ }mx
                 and $_ ne q(name)
                 and $condition->( $_ ) } keys %{ $src };
}

1;

__END__

# Local Variables:
# mode: perl
# tab-width: 3
# End: