Audit-DBI
view release on metacpan or search on metacpan
lib/Audit/DBI/Utils.pm view on Meta::CPAN
=head2 diff_structures()
Return the differences between the two data structures passed as parameter.
By default, if leaf nodes are compared with '==' if they are both numeric, and
with 'eq' otherwise.
An optional I<comparison_function> parameter can be used to specify a different
comparison function.
my $differences = Audit::DBI::Utils::diff_structures(
$data_structure_1,
$data_structure_2,
);
# Alternative built-in comparison function.
# Leaf nodes are compared using 'eq'.
my $diff = Audit::DBI::Utils::diff_structures(
$data_structure_1,
$data_structure_2,
comparison_function => 'eq',
);
# Alternative custom comparison function.
my $diff = Audit::DBI::Utils::diff_structures(
$data_structure_1,
$data_structure_2,
comparison_function => sub
{
my ( $variable_1, $variable2 ) = @_;
# [...]
return $is_equal;
}
);
=cut
sub diff_structures
{
my ( @args ) = @_;
return _diff_structures(
{},
@args
);
}
sub _diff_structures_comparison_eq
{
my ( $variable_1, $variable_2 ) = @_;
return $variable_1 eq $variable_2;
}
sub _diff_structures_comparison_default
{
my ( $variable_1, $variable_2 ) = @_;
# For numbers, return numerical comparison.
return $variable_1 == $variable_2
if Scalar::Util::looks_like_number( $variable_1 ) && Scalar::Util::looks_like_number( $variable_2 );
# Otherwise, use exact string match.
return $variable_1 eq $variable_2;
}
sub _diff_structures
{
my ( $cache, $structure1, $structure2, %args ) = @_;
my $comparison_function = $args{'comparison_function'};
# make sure the provided equality function is really a coderef
if ( !Data::Validate::Type::is_coderef( $comparison_function ) )
{
if ( defined( $comparison_function ) && ( $comparison_function eq 'eq' ) )
{
$comparison_function = \&_diff_structures_comparison_eq;
}
else
{
$comparison_function = \&_diff_structures_comparison_default;
}
}
# If one of the structure is undef, return
if ( !defined( $structure1 ) || !defined( $structure2 ) )
{
if ( !defined( $structure1 ) && !defined( $structure2 ) )
{
return undef;
}
else
{
return
{
old => $structure1,
new => $structure2
};
}
}
# Cache memory addresses to make sure we don't get into an infinite loop.
# The idea comes from Test::Deep's code.
return undef
if exists( $cache->{ "$structure1" }->{ "$structure2" } );
$cache->{ "$structure1" }->{ "$structure2" } = undef;
# Hashes (including hashes blessed as objects)
if ( Data::Validate::Type::is_hashref( $structure1 ) && Data::Validate::Type::is_hashref( $structure2 ) )
{
my %union_keys = map { $_ => undef } ( keys %$structure1, keys %$structure2 );
my %tmp = ();
foreach ( keys %union_keys )
{
my $diff = _diff_structures(
$cache,
$structure1->{$_},
$structure2->{$_},
%args,
);
( run in 1.530 second using v1.01-cache-2.11-cpan-5a3173703d6 )