Coder Social home page Coder Social logo

struct-diff.pm's Introduction

NAME

Struct::Diff - Recursive diff for nested perl structures

Travis CI Coverage Status CPAN version

VERSION

Version 0.98

SYNOPSIS

use Struct::Diff qw(diff list_diff split_diff patch valid_diff);

$x = {one => [1,{two => 2}]};
$y = {one => [1,{two => 9}],three => 3};

$diff = diff($x, $y, noO => 1, noU => 1); # omit unchanged items and old values
# $diff == {D => {one => {D => [{D => {two => {N => 9}},I => 1}]},three => {A => 3}}}

@list_diff = list_diff($diff); # list (path and ref pairs) all diff entries
# @list_diff == ({K => ['one']},[1],{K => ['two']}],\{N => 9},[{K => ['three']}],\{A => 3})

$splitted = split_diff($diff);
# $splitted->{a} # does not exist
# $splitted->{b} == {one => [{two => 9}],three => 3}

patch($x, $diff); # $x now equal to $y by structure and data

@errors = valid_diff($diff);

EXPORT

Nothing is exported by default.

DIFF FORMAT

Diff is simply a HASH whose keys shows status for each item in passed structures. Every status type (except D) may be omitted during the diff calculation. Disabling some or other types produce different diffs: diff with only unchanged items is also possible (when all other types disabled).

  • A

    Stands for 'added' (exist only in second structure), it's value - added item.

  • D

    Means 'different' and contains subdiff. The only status type which can't be disabled.

  • I

    Index for array item, used only when prior item was omitted.

  • N

    Is a new value for changed item.

  • O

    Alike N, O is a changed item's old value.

  • R

    Similar for A, but for removed items.

  • U

    Represent unchanged items.

Diff format: metadata alternates with data and, as a result, diff may represent any structure of any data types. Simple types specified as is, arrays and hashes contain subdiffs for their items with native for such types addressing: indexes for arrays and keys for hashes.

Sample:

old:  {one => [5,7]}
new:  {one => [5],two => 2}
opts: {noU => 1} # omit unchanged items

diff:
{D => {one => {D => [{I => 1,R => 7}]},two => {A => 2}}}
||    | |     ||    |||    | |    |     |     ||    |
||    | |     ||    |||    | |    |     |     ||    +- with value 2
||    | |     ||    |||    | |    |     |     |+- key 'two' was added (A)
||    | |     ||    |||    | |    |     |     +- subdiff for it
||    | |     ||    |||    | |    |     +- another key from top-level hash
||    | |     ||    |||    | |    +- what it was (item's value: 7)
||    | |     ||    |||    | +- what happened to item (R - removed)
||    | |     ||    |||    +- array item's actual index
||    | |     ||    ||+- prior item was omitted
||    | |     ||    |+- subdiff for array item
||    | |     ||    +- it's value - ARRAY
||    | |     |+- it is deeply changed
||    | |     +- subdiff for key 'one'
||    | +- it has key 'one'
||    +- top-level thing is a HASH
|+- changes somewhere deeply inside
+- diff is always a HASH

SUBROUTINES

diff

Returns recursive diff for two passed things.

$diff  = diff($x, $y, %opts);
$patch = diff($x, $y, noU => 1, noO => 1, trimR => 1); # smallest diff

Beware changing diff: it's parts are references to substructures of passed arguments.

Options

  • freezer <sub>

    Serializer callback (redefines default serializer). "freeze" in Storable is used by default, see "CONFIGURATION VARIABLES" for details.

  • noX <true|false>

    Where X is a status (A, N, O, R, U); such status will be omitted.

  • trimR <true|false>

    Drop removed item's data.

list_diff

List all pairs (path-to-subdiff, ref-to-subdiff) for provided diff. See "ADDRESSING SCHEME" in Struct::Path for path format specification.

@list = list_diff($diff);

Options

  • depth <int>

    Don't dive deeper than defined number of levels; undef used by default (unlimited).

  • sort <sub|true|false>

    Defines how to handle hash subdiffs. Keys will be picked randomly (default keys behavior), sorted by provided subroutine (if value is a coderef) or lexically sorted if set to some other true value.

split_diff

Divide diff to pseudo original structures.

$structs = split_diff(diff($x, $y));
# $structs->{a}: items from $x
# $structs->{b}: items from $y

patch

Apply diff.

patch($target, $diff);

valid_diff

Validate diff structure. In scalar context returns 1 for valid diff, undef otherwise. In list context returns list of pairs (path, type) for each error. See "ADDRESSING SCHEME" in Struct::Path for path format specification.

@errors_list = valid_diff($diff); # list context

or

$is_valid = valid_diff($diff); # scalar context

CONFIGURATION VARIABLES

  • $Struct::Diff::FREEZER

    Contains reference to default serialization function (diff() rely on it to determine data equivalency). "freeze" in Storable with enabled $Storable::canonical and $Storable::Deparse opts used by default.

    Data::Dumper is suitable for structures with regular expressions:

      use Data::Dumper;
    
      $Struct::Diff::FREEZER = sub {
          local $Data::Dumper::Deparse    = 1;
          local $Data::Dumper::Sortkeys   = 1;
          local $Data::Dumper::Terse      = 1;
    
          return Dumper @_;
      }
    

    But comparing to Storable it has two another issues: speed and unability to distinguish numbers from their string representations.

LIMITATIONS

Only arrays and hashes traversed. All other types compared by reference addresses and serialized content.

"freeze" in Storable (serializer used by default) will fail serializing compiled regexps, so, consider to use other serializer if data contains regular expressions. See "CONFIGURATION VARIABLES" for details.

Struct::Diff will fail on structures with loops in references; has_circular_ref from Data::Structure::Util can help to detect such structures.

AUTHOR

Michael Samoglyadov, <mixas at cpan.org>

BUGS

Please report any bugs or feature requests to bug-struct-diff at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Struct-Diff. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

You can find documentation for this module with the perldoc command.

perldoc Struct::Diff

You can also look for information at:

SEE ALSO

Algorithm::Diff, Data::Deep, Data::Diff, Data::Difference, JSON::Patch, JSON::MergePatch, Struct::Diff::MergePatch

Data::Structure::Util, Struct::Path, Struct::Path::PerlStyle

LICENSE AND COPYRIGHT

Copyright 2015-2019 Michael Samoglyadov.

This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.

See http://dev.perl.org/licenses/ for more information.

struct-diff.pm's People

Contributors

manwar avatar mr-mixas avatar

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

struct-diff.pm's Issues

diff incorrect for identical scalars

A diff for a hashref containing scalars which values are identical but their default freezer (Storable) return value is different are reported as different:

For example:

my $diff = diff({ port => "1434" }, { port => "1434" }, noU => 1);

print Dumper($diff);

outputs:

{
  D => {
    port => {
      N => "1434",
      O => "1434",
    }
  }
}

I'm still trying to get a failing test case but haven't succeeded so far.

Adding these lines after https://github.com/mr-mixas/Struct-Diff.pm/blob/master/lib/Struct/Diff.pm#L233

print "CHECKING $k\n";
print "\tx: '" . $x->{$k} . "' " . $opts{freezer}($x->{$k}) . "\n";
print "\ty: '" . $y->{$k} . "' " . $opts{freezer}($y->{$k}) . "\n";

for example outputs this:

CHECKING port
	x: '1434' 
                 12345678
1434
	y: '1434' 
                 123451434

Line https://github.com/mr-mixas/Struct-Diff.pm/blob/master/lib/Struct/Diff.pm#L252 causes the failure as it doesn't compare scalars ($type undefined).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.