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