Aldebaran has asked for the wisdom of the Perl Monks concerning the following question:
Hello Good Netizens
I started a meditation with Renaming all files in a directory that got more response than I anticipated, and now that I've thought about the questions that were raised, I would like to visit the same problem space in SopW. In meditations, we might focus on what unites us; over here we might squabble about implementation, vendors, "best ways", and more importantly, deal with questions, and I shall pose a few.
I've watched this twice now: Ricardo Signes 2020 perl conference, and I would like to see if I can pull off the same things he's doing. I think I've set up the playing field appropriately:
First we have this from caller:
## this function is to be debugged using the perl debugger my $return2 = make_initial_captions; say "return2 is $return2";
And then I've stubbed out a function that has access to the primary data structure:
sub make_initial_captions { use 5.016; use warnings; use POSIX; use Path::Tiny; use Encode; use open OUT => ':encoding(UTF-8)', ':std'; use Data::Dumper; my $rvars = shift; my %vars = %$rvars; print Dumper $rvars; my $image_path = $vars{"to_images"}; my $caption_path = $vars{"eng_captions"}; return "nothing yet"; }
In these minimal changes to what was working, I've managed to make it *not work* as I present, so it will be a good candidate for debugging. Here's what my terminal says as I invoke caller:
$ ./1.debug.11.pl Subroutine debug1::getcwd redefined at /usr/share/perl/5.30/Exporter.p +m line 66. at template_stuff/debug1.pm line 397. title is 1.debug.1 path1 is /home/hogan/6.scripts/1.debug.1 abs is /home/hogan/6.scripts/1.debug.1/1.debug.11.pl Can't use an undefined value as a HASH reference at template_stuff/deb +ug1.pm line 35. $ pwd /home/hogan/6.scripts/1.debug.1 $ ls 1.debug.11.pl 1.debug.11.pl.bak template_stuff $
Caller and library are about 500 lines together, so I'll show them once between readmore tags:
$ cat 1.debug.11.pl #!/usr/bin/perl -w use 5.011; use lib "template_stuff"; use debug1; use Path::Tiny; use utf8; use Encode; use open OUT => ':encoding(UTF-8)', ':std'; # initializations that must precede main data structure my $ts = "template_stuff"; my $images = "aimages"; my $captions = "captions"; my $ruscaptions = "ruscaptions"; ## turning things to Path::Tiny # decode paths my $abs = path(__FILE__)->absolute; my $path1 = Path::Tiny->cwd; my $title = $path1->basename; $abs = decode( 'UTF-8', $abs ); $path1 = decode( 'UTF-8', $path1 ); $title = decode( 'UTF-8', $title ); say "title is $title"; say "path1 is $path1"; say "abs is $abs"; my $path2 = path( $path1, $ts ); # page params my %vars = ( title => $title, headline => undef, ts => 'template_system', place => 'Between Portland and Boise', base_url => 'http://www.merrillpjensen.com', css_file => "${title}1.css", header => path( $path2, "hc_input2.txt" ), footer => path( $path2, "footer_center3.txt" ), body => path( $path2, "rebus7.tmpl" ), code_tmpl => path( $path2, "code2.tmpl" ), oitop => path( $path2, "oitop.txt" ), oibottom => path( $path2, "oibottom.txt" ), to_images => path( $path2, $images ), eng_captions => path( $path2, $captions ), rus_captions => path( $path2, $ruscaptions ), translations => path( $path2, 'translations' ), bottom => path( $path2, "bottom1.txt" ), css_path => $path2, css_remote => 'css', print_module => 0, print_script => "1", script_file => $abs, module_tmpl => path( $path2, "code3.tmpl" ), apache_rt => '/var/www/html', html_dir => 'perlmonks', image_dir => 'pm_image', book => 'The perl debugger', chapter => 'with images and captions', ); my $rvars = \%vars; ## this function is to be debugged using the perl debugger my $return2 = make_initial_captions; say "return2 is $return2"; my $return = create_page($rvars); say "return is $return"; say $vars{"base_url"} . '/' . $vars{"html_dir"} . '/' . "$return"; __END__ $ cd template_stuff/ $ cat debug1.pm package debug1; require Exporter; use utils1; our @ISA = qw(Exporter); our @EXPORT = qw( get_content write_body get_html_filename create_html_file write_script write_bottom write_header write_footer write_module get_tiny create_page put_page get_tiny make_russian_captions make_initial_captions ); sub make_initial_captions { use 5.016; use warnings; use POSIX; use Path::Tiny; use Encode; use open OUT => ':encoding(UTF-8)', ':std'; use Data::Dumper; my $rvars = shift; my %vars = %$rvars; print Dumper $rvars; # put a break point here my $image_path = $vars{"to_images"}; my $caption_path = $vars{"eng_captions"}; return "nothing yet"; } sub make_russian_captions { use 5.011; use warnings; use POSIX qw(strftime); use Path::Tiny; use Encode; use open OUT => ':encoding(UTF-8)', ':std'; my $rvars = shift; my %vars = %$rvars; my $munge = strftime( "%d-%m-%Y-%H-%M-%S\.txt", localtime ); my $in_path = path( $vars{translations}, $munge )->touchpath; my $lang = 'ru'; #system("pwd >$in_path"); works my @matching2; opendir( my $hh, $vars{eng_captions} ) or die "death $!\n"; while ( defined( $_ = readdir($hh) ) ) { if (m/txt$/) { push( @matching2, $_ ); } } #important to sort @matching2 = sort @matching2; say "matching are @matching2"; my $rus_munge = path( $vars{translations}, "trans." . $munge ); say "rus_munge is $rus_munge"; # open file for writing my $fh = path($in_path)->openw_utf8; foreach (@matching2) { my $eng_path = path( $vars{eng_captions}, $_ ); say $fh "##$_##"; my $rus_path = path( $vars{rus_captions}, $_ )->touchpath; say "rus_path is $rus_path"; my $content = path($eng_path)->slurp_utf8; $content =~ s/^\s+|\s+$//g; say $fh "$content"; system("trans :$lang file://$eng_path >$rus_path"); } print "Get other translations(y/n)?: "; my $prompt = <STDIN>; chomp $prompt; if ( $prompt eq ( "y" | "Y" ) ) { my @translators = qw /yandex bing/; for my $remote (@translators) { my $trans_munge = path( $vars{translations}, "$remote." . $munge + ); ## use trans shell say "getting translation from $remote"; system("trans :$lang -e $remote file://$in_path >$trans_munge"); } } return "nothing yet"; } sub get_tiny { use 5.011; use warnings; use Net::SFTP::Foreign; use Config::Tiny; use Data::Dumper; my $ini_path = qw( /home/hogan/Documents/html_template_data/6.values +.ini ); say "ini path is $ini_path"; my $sub_hash = "my_sftp"; my $Config = Config::Tiny->new; $Config = Config::Tiny->read( $ini_path, 'utf8' ); say Dumper $Config; # -> is optional between brackets my $domain = $Config->{$sub_hash}{'domain'}; my $username = $Config->{$sub_hash}{'username'}; #my $password = $Config->{$sub_hash}{'password'}; my $port = $Config->{$sub_hash}{'port'}; #dial up the server say "values are $domain $username $port"; my $sftp = Net::SFTP::Foreign->new( $domain, #more => '-v', user => $username, port => $port, #password => $password ) or die "Can't connect: $!\n"; return $sftp; } sub create_page { use 5.011; #use trans1; use Net::SFTP::Foreign; use Encode; use open OUT => ':encoding(UTF-8)', ':std'; #create html page my $rvars = shift; my %vars = %$rvars; my $sftp = get_tiny(); say "object created, back with caller"; my $html_file = get_html_filename( $sftp, $rvars ); $vars{html_file} = $html_file; print "Make rus captions(y/n)?: "; my $prompt1 = <STDIN>; chomp $prompt1; if ( $prompt1 eq ( "y" | "Y" ) ) { my $ref_cap = make_russian_captions($rvars); } my $fh = create_html_file($html_file); my $remote_dir = $html_file; $remote_dir =~ s/\.html$//; say "remote_dir is $remote_dir"; $vars{remote_dir} = $remote_dir; $rvars = \%vars; ## why so necessary? # create header my $rhdr = write_header($rvars); print $fh $$rhdr; $vars{refc} = get_content($rvars); #print_aoa($refc); my $body = write_body( $rvars, $vars{refc} ); print $fh $$body; my $rftr = write_footer($rvars); print $fh $$rftr; if ( $vars{"print_script"} ) { my $script = write_script($rvars); print $fh $$script; } if ( $vars{"print_module"} ) { my $module = write_module($rvars); print $fh $$module; } my $rhbt = write_bottom($rvars); print $fh $$rhbt; close $fh; print "Put file to server(y/n)?: "; my $prompt2 = <STDIN>; chomp $prompt2; if ( $prompt2 =~ /y/i ) { put_page( $sftp, $rvars ); } return $html_file; } sub put_page { use 5.016; use utils1; use Net::SFTP::Foreign; use Encode; use open OUT => ':encoding(UTF-8)', ':std'; use Data::Dumper; my ( $sftp, $rvars ) = (@_); my %vars = %$rvars; ###### beginning overhaul 10-2020 # quick and easy print Dumper $rvars; ###### say " %%%%% change"; my $path1 = path( $vars{"apache_rt"}, $vars{"html_dir"}, $vars{"image_dir"}, $vars{"title"} ); say "path1 is $path1"; $sftp->mkpath($path1) or warn "mkpath1 failed $!\n"; #load html file to server my $path2 = path( $vars{"apache_rt"}, $vars{"html_dir"} ); say "path2 is $path2"; $sftp->setcwd($path2) or warn "setcwd1 failed $!\n"; $sftp->put( $vars{html_file} ) or die "html put failed $!\n"; $sftp->ls; #load css file to server my $path3 = path( $vars{"apache_rt"}, $vars{"css_remote"} ); say "path3 is $path3"; my $path6 = path( $vars{"css_path"}, $vars{"css_file"} ); say "path6 is $path6"; $sftp->mkpath($path3) or warn "mkpath3 failed $!\n"; $sftp->setcwd($path3) or warn "setcwd for path3 failed $!\n"; say " -----"; print $sftp->cwd(), "\n"; say " -----"; $sftp->put( $path6, $vars{"css_file"} ) or warn "css put failed $@\n +"; # upload images $sftp->setcwd($path1) or warn "setcwd for images failed $!\n"; print $sftp->cwd(), "\n"; say " %%%%% end 10-2020 change"; #print Dumper $rvars; my $ref_content = $vars{refc}; my @AoA = @$ref_content; for my $i ( 0 .. $#AoA ) { my $a = path( $vars{to_images}, $AoA[$i][0] ); say "a is $a"; my $b = $a->basename; say "b is $b"; $sftp->put( $a, $b ) or warn "AoA put failed $@\n"; } undef $sftp; return; } sub get_content { use 5.010; my $rvars = shift; my %vars = %$rvars; my $refimg = get_images($rvars); my $refcaps = get_utf8_text( $rvars, $vars{"eng_captions"} ); my $refruscaps = get_utf8_text( $rvars, $vars{"rus_captions"} ); my $aoa = [ $refimg, $refcaps, $refruscaps ]; my $b = invert_aoa($aoa); return ($b); } sub get_images { use 5.011; my $rvars = shift; my %vars = %$rvars; my @filetypes = qw/jpg gif png jpeg GIF/; my $pattern = join '|', map "($_)", @filetypes; my @matching2; opendir my $hh, $vars{to_images} or warn "warn $!\n"; while ( defined( $_ = readdir($hh) ) ) { if ( $_ =~ /($pattern)$/i ) { push( @matching2, $_ ); } } #important to sort @matching2 = sort @matching2; return \@matching2; } sub get_utf8_text { use 5.010; use HTML::FromText; use Path::Tiny; use utf8; use open qw/:std :utf8/; ### Passing in #reference to main data structure and directory for captions my ( $rvars, $dir ) = (@_); my %vars = %$rvars; say "dir is $dir"; opendir my $eh, $dir or warn "can't open dir for utf8 captions $!\n +"; while ( defined( $_ = readdir($eh) ) ) { next if m/~$/; next if -d; if (m/txt$/) { my $file = path( $dir, $_ ); my $guts = $file->slurp_utf8; my $temp = text2html( $guts, urls => 1, email => 1, paras => 1, ); # surround by divs my $oitop = $vars{"oitop"}; my $oben = $oitop->slurp_utf8; my $oibottom = $vars{"oibottom"}; my $unten = $oibottom->slurp_utf8; my $text = $oben . $temp . $unten; #say "text is $text"; $content{$_} = $text; } } closedir $eh; #important to sort my @return; foreach my $key ( sort keys %content ) { #print $content{$key} . "\n"; push @return, $content{$key}; } return \@return; } sub write_body { use warnings; use 5.011; use Text::Template; use Encode; my $rvars = shift; my $reftoAoA = shift; my %vars = %$rvars; my @AoA = @$reftoAoA; my $body = $vars{"body"}; my $template = Text::Template->new( ENCODING => 'utf8', SOURCE => $body ) or die "Couldn't construct template: $!"; my $return = ""; for my $i ( 0 .. $#AoA ) { $vars{"file"} = $AoA[$i][0]; $vars{"english"} = $AoA[$i][1]; my $ustring = $AoA[$i][2]; $vars{"russian"} = $ustring; my $result = $template->fill_in( HASH => \%vars ); $return = $return . $result; } return \$return; } sub write_bottom { use strict; use Text::Template; my ($rvars) = shift; my %vars = %$rvars; my $footer = $vars{"bottom"}; my $template = Text::Template->new( SOURCE => $footer ) or die "Couldn't construct template: $!"; my $result = $template->fill_in( HASH => $rvars ); return \$result; } sub get_html_filename { use Net::SFTP::Foreign; use File::Basename; use Cwd; use 5.01; binmode STDOUT, ":utf8"; my ( $sftp, $rvars ) = (@_); my %vars = %$rvars; # get working directory my $word = $vars{"title"}; say "word is $word"; my $path3 = path( $vars{"apache_rt"}, $vars{"html_dir"} ); say "path3 is $path3"; my $ls = $sftp->ls( "$path3", wanted => qr/$word/ ) or warn "unable to retrieve " . $sftp->error; print "$_->{filename}\n" for (@$ls); my @remote_files = map { $_->{filename} } @$ls; say "files are @remote_files"; my $rref = \@remote_files; my $filetype = "html"; my $old_num = highest_number( $rref, $filetype, $word ); print "old num is $old_num\n"; my $new_num = $old_num + 1; my $html_file = $word . $new_num . '.' . $filetype; return $html_file; } sub create_html_file { my $html_file = shift; open( my $fh, ">>:encoding(UTF-8)", $html_file ) or die("Can't open $html_file for writing: $!"); return $fh; } sub write_header { use Text::Template; use 5.011; use warnings; my $rvars = shift; my %vars = %$rvars; # get time my $now_string = localtime; $vars{"date"} = $now_string; my $headline = join( ' ', $vars{"book"}, $vars{"chapter"} ); $vars{"headline"} = $headline; my $header = $vars{"header"}; my $template = Text::Template->new( ENCODING => 'utf8', SOURCE => $header, ) or die "Couldn't construct template: $!"; my $result = $template->fill_in( HASH => \%vars ); say "result is $result"; return \$result; } sub write_footer { use Text::Template; my ($rvars) = shift; my %vars = %$rvars; my $footer = $vars{"footer"}; my $template = Text::Template->new( SOURCE => $footer ) or die "Couldn't construct template: $!"; my $result = $template->fill_in( HASH => $rvars ); return \$result; } sub write_script { use Text::Template; use 5.010; use utf8; my ($rvars) = shift; my %vars = %$rvars; my $tmpl = $vars{"code_tmpl"}; say "tmpl is $tmpl"; my $file = $vars{"script_file"}; my $text = do { open my $fh, '<:raw:encoding(UTF-8)', $file or die "$file: $!"; local $/; <$fh>; }; my %data = ( 'script', $text ); my $template = Text::Template->new( SOURCE => $tmpl ) or die "Couldn't construct template: $!"; my $result = $template->fill_in( HASH => \%data ); return \$result; } sub write_module { use 5.010; use File::Spec; use Text::Template; use utf8; my ($rvars) = shift; my %vars = %$rvars; my $tmpl = $vars{"module_tmpl"}; say "tmpl is $tmpl"; my $file = File::Spec->rel2abs(__FILE__); my $text = do { open my $fh, '<:raw:encoding(UTF-8)', $file or die "$file: $!"; local $/; <$fh>; }; my %data = ( 'module', $text ); my $template = Text::Template->new( SOURCE => $tmpl ) or die "Couldn't construct template: $!"; my $result = $template->fill_in( HASH => \%data ); return \$result; } 1; $
Line 397 has to be the most innocent looking thing I've ever seen:
use Cwd;, so the mystery is real to me, and the task authentic. What I want to do in this function is read in the names of the files in the order that would have occured had it been done by ls | . Order is super important for this exercise. Q1) When I
use POSIX;, do I have a canonical way to decide what alphanumeric order is in a world teemimg with things that could be filenames and what might be competing ways to decide precedence? jwkrahn brought up an example of a name with a question mark in the middle that seemed to confound ls | . I'm left wondering how many types of weird filenames out there might confound a script, too.
$ pwd /home/hogan/6.scripts/1.debug.1/template_stuff/captions $ touch caption{01..07}.txt $ ls caption01.txt caption03.txt caption05.txt caption07.txt caption02.txt caption04.txt caption06.txt $
What I would like this routine to do is take the filename from the nth file and store it in the nth caption. One should then see
$ pwd /home/hogan/6.scripts/1.debug.1/template_stuff/aimages $ ls 'Screenshot from 2021-02-03 15-20-48.png' 'Screenshot from 2021-02-03 15-22-28.png' 'Screenshot from 2021-02-03 15-23-42.png' 'Screenshot from 2021-02-03 15-24-01.png' 'Screenshot from 2021-02-03 15-25-04.png' 'Screenshot from 2021-02-03 15-29-08.png' 'Screenshot from 2021-02-03 15-32-57.png' $
So these would populate the content of the caption files.
and then, I would like to be able to step through that with the debugger, where I'm fishing fo tips. Be aware that I have bothered to take first steps, but, as this shows, it's a lot of content and pretty new (to me). Since the terminal doesn't lie, I see I approached it backwards:
$ history | grep perldeb 1980 perldoc perldebguts 1981 perldoc perldebug 1982 perldoc perldebtut 1990 history | grep perldeb $
Thanks for your comment,
|
---|