Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

RFC: perl sub diff between two files

by bliako (Chaplain)
on Mar 26, 2018 at 12:24 UTC ( #1211734=perlmeditation: print w/replies, xml ) Need Help??

Fellow Monks,

Recently, I was in need to compare two versions of the same perl module containing many subs. I was interested to see the difference between the contents of subs with the same name. This happened because I forked the same code in two different machines and made changes in the modules in both machines.

For this purpose I wrote the following basic script which I place here for public use but also for comments from the monastic community.

The simple script makes use of two excellent modules, namely PPI and Text::WordDiff. PPI parses perl code and is capable of extracting subs and their contents. Text::WordDiff outlines (and color-codes) the differences between two blocks of text (the contents of identically-named subs in two files).

Unix's diff is a fine tool in general, but code has a few idiosyngracies which make diffing sometimes impractical. For example when same-content subs have different order in their respective files.

That said, I wanted a quick tool to check my two versions of the perl module, find enhancements in either file I made and produce a final version.

Here is the script:

#!/usr/bin/env perl use strict; use warnings; use PPI; use Text::WordDiff; if( scalar(@ARGV) != 2 ){ print usage($0) . "\n"; exit(0); } my ($infile1, $infile2) = @ARGV; my $doc = PPI::Document->new($infile1); if( ! defined($doc) ){ print STDERR "$0 : call to ".'PPI::Document->ne +w()'." has failed for input file '$infile2'.\n"; exit(1); } my (%subs1, %subs2, $asub); for $asub ( @{ $doc->find('PPI::Statement::Sub') || [] } ) { # loop over all subs in file unless ( $asub->forward ) { # store sub's contents in hash keyed on sub's name $subs1{ $asub->name } = $asub->content; } } $doc = PPI::Document->new($infile2); if( ! defined($doc) ){ print STDERR "$0 : call to ".'PPI::Document->ne +w()'." has failed for input file '$infile2'.\n"; exit(1); } for $asub ( @{ $doc->find('PPI::Statement::Sub') || [] } ) { # loop over all subs in file unless ( $asub->forward ) { # store sub's contents in hash keyed on sub's name $subs2{ $asub->name } = $asub->content; } } my ($k, $v1, $v2, $res, $anitem); my @dont_exist = (); my %allkeys = map { $_ => 1 } (keys %subs1, keys %subs2); foreach $k (sort keys %allkeys){ if( ! defined($v1=$subs1{$k}) ){ push(@dont_exist, "$k : Does not exist in '$infile1'\n"); next } elsif( ! defined($v2=$subs2{$k}) ){ push(@dont_exist, "$k : Does not exist in '$infile2'\n"); next } # sub (same name) exists in both files, diff sub's contents in fil +es: $res = Text::WordDiff::word_diff( \$v1, \$v2, ); # print diff results print "----- begin '$k' -----\n" . $res . "\n----- end '$k' ------\n" ; } # and also print the subs which exist in one file but not the other fi +le print join("", @dont_exist); exit(0); sub usage { return "Usage : ".$_[0]." file1 file2\nColor output guide:\n\tRED +: file1\n\tGREEN: file2\n" }

bliako

Replies are listed 'Best First'.
Re: RFC: perl sub diff between two files
by stevieb (Abbot) on Mar 26, 2018 at 15:07 UTC

    Good work!

    I do not have time today to review and play with what you've done here, but the diff aspect sounds like something that would be very beneficial to my Devel::Examine::Subs, so I will give it a good test and see if that Text::WordDiff functionality fits well into my project.

Re: RFC: perl sub diff between two files
by LanX (Bishop) on Mar 26, 2018 at 15:47 UTC
Re: RFC: perl sub diff between two files
by Anonymous Monk on Mar 26, 2018 at 20:45 UTC
Re: RFC: perl sub diff between two files
by Anonymous Monk on Mar 29, 2018 at 01:15 UTC
    If you "forked" them then this implies that both versions are under version-control, e.g. git or svn. Both of which can compare and reconcile differences – especially if you did each set of changes (as you should have) on separate branches. You should have no need of Perl-tomfoolery here.
      >  e.g. git or svn. Both of which can compare and reconcile differences

      You sound like sundial ...

      Neither GIT nor SVN can "compare or reconcile" using Perl semantics, they work only by line* comparison.

      Otherwise please show me how to do this with a subroutine which moved from start to end of a file after refactoring.

      Cheers Rolf
      (addicted to the Perl Programming Language and ☆☆☆☆ :)
      Wikisyntax for the Monastery

      *) more precisely "chunks of equal lines"

        exactly one of my main motivations. although i did not use GIT nor SVN for other reasons, including laziness.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://1211734]
Approved by marto
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (8)
As of 2018-09-25 13:28 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Eventually, "covfefe" will come to mean:













    Results (199 votes). Check out past polls.

    Notices?
    • (Sep 10, 2018 at 22:53 UTC) Welcome new users!