Greetings!
I have a simple Perl script that uses PPI to locate and update the heredocs (which is mainly SQL) in Perl scripts/modules. For each heredoc in the script/module it clipboards the content of the heredoc and allows you to change it. For most respect it is well-behaved except when it comes to the heredoc terminators - which double (in the sense that what should be EOF becomes EOFEOF).
When the fed the script and replacing "Something" with "else"
my($query);
$query =<<"ENDOFSQL";
Something
ENDOFSQL
$query = <<"ENDOFSQL";
Something
ENDOFSQL
I'll get
my($query);
$query =<<"ENDOFSQL";
/* # Just A Test
Something
*/
else
ENDOFSQLENDOFSQL
$query = <<"ENDOFSQL";
/* # Just A Test
Something
*/
else
ENDOFSQLENDOFSQL
Note the doubling up of the terminators.
Here is FindAndUpdateHeredoc script
#!/usr/bin/perl
use 5.12.0;
use Params::Validate qw(:all);
use PPI;
use PPI::Dumper;
use PPI::Find;
use Win32::Clipboard;
use strict;
use warnings;
# Clear the screen
system 'cls';
FindAndReplaceHereDocs($ARGV[0],"$ARGV[0].upd")
if (-f $ARGV[0]);
exit;
sub _Comment {
return "# Just A Test";
};
sub FindAndReplaceHereDocs {
@_=Params::Validate::validate_pos(@_
,{ type=>SCALAR, callbacks=>{ "File not found"=> sub {
+ -f shift() } }}
,{ type=>SCALAR }
,{ type=>SCALAR, optional=>1, default=>_Comment() });
### @_
my ($ExistingCodeFilename_S,$UpdatedCodeFilename_S,$Comment_S)
+=@_;
my $Document_o=PPI::Document->new($ExistingCodeFilename_S);
#PPI::Dumper->new($Document_o,whitespace=>0,locations=>1)->pri
+nt;
# Stripping out comments
#$Document_o->prune('PPI::Token::Comment');
# Sub to find HereDocs
local *HereDocs = sub {
$_[1]->isa('PPI::Token::HereDoc')
};
# Buffer for HereDocs required by the updated document
my @NewHereDoc_a;
# We'll need a clipboard ...
my $Clipboard_o=Win32::Clipboard->new();
# Find the HereDocs in the existing code
my $ExistingCodeHereDoc_ar=$Document_o->find(\&HereDocs) || []
+;
for my $HereDoc_o (@$ExistingCodeHereDoc_ar) {
#PPI::Dumper->new($HereDoc_o,whitespace=>0,locations=>1)->
+print;
$Clipboard_o->Empty();
$Clipboard_o->Set(join('',$HereDoc_o->heredoc()));
print join('',$HereDoc_o->heredoc())."\n";
{
local $|=1;
print STDOUT "Update the clipboard then 'Enter':";
<STDIN>;
};
# See if the clipboard has been changed
if ((my $NewText_s=$Clipboard_o->GetText()) ne join('',$He
+reDoc_o->heredoc())) {
print "Replaced with:\n$NewText_s\n\n";
chomp($NewText_s);
push @NewHereDoc_a,PPI::Document->new(\(
$HereDoc_o->content()
."\n"
."/* $Comment_S\n" # Comment
.join('',$HereDoc_o->heredoc()) # ... origina
+l commented out
."*/\n" #
.$NewText_s # ... replace
+ment
."\n"
#.$HereDoc_o->terminator() # Prevents sp
+urious terminator
));
my $HereDoc_ar=$NewHereDoc_a[-1]->find(\&HereDocs) ||
+[];
#PPI::Dumper->new($HereDoc_ar->[0],whitespace=>1,locat
+ions=>1)->print;
#print join('',$HereDoc_ar->[0]->heredoc())."\n";
if ($HereDoc_o->insert_before($HereDoc_ar->[0])) {
$HereDoc_o->delete();
} else {
warn "insert_before failed!";
};
};
};
#PPI::Dumper->new($Document_o,whitespace=>0,locations=>1)->pri
+nt;
$Document_o->save($UpdatedCodeFilename_S)
};
No doubt I'm doing something wrong --- but what?
Update The code as it currently stands behaves correctly and will find HereDocs and copy them to the clipboard so they can be pasted to an editor, edited then reclip to amend the HereDoc.