http://qs321.pair.com?node_id=11117935


in reply to Collapsing smaller scripts into a larger one, request for comment

Update: I am done mostly with writing the indexes. There are a few parts of the code that I am still mulling over. The following is a basic index script.

#!/usr/bin/perl # This is the index for <dir>. use strict; use warnings FATAL => qw( all ); use CGI::Carp qw(fatalsToBrowser); use CGI::Minimal; use HTML::Entities qw(encode_entities); use lib '../files/lib'; use Base::Page qw(page story); use HTML::Elements qw(list anchor); use Util::Convert qw(searchify); use Util::Data qw(file_directory file_list); use Util::Menu qw(file_menu); use Util::Sort qw(article_sort); my $cgi = CGI::Minimal->new; my $page = $cgi->param('page') ? encode_entities($cgi->param('pa +ge'),'/<>"') : undef; my $pages_dir = file_directory(<dir>, 'text'); my @pages_list = file_list($pages_dir); my @pages = sort { article_sort($a, $b) } map { $_ =~ s/\.txt//; $_ =~ s/_/ /g; $_ } grep { -f "$pages_dir/$_" && /^\p{uppercase}/ } @pages_list; my $heading = q(<the heading for the index>); my $page_file = "$pages_dir/index.txt"; if ( $page && grep { $_ eq $page } @pages ) { $heading = $page; $page_file = "$pages_dir/$page.txt"; $page_file =~ s/ /_/g; } open(my $page_fh, '<', $page_file) || die "Can't open $page_file. $!"; my $magic; $magic->{'pages'} = sub { my $file_menu = file_menu('page', \@pages, $page); list(4, 'u', $file_menu); }; page( 'heading' => $heading, 'selected' => $page, 'code' => sub { story($page_fh, { 'doc magic' => $magic, 'line magic' => $magic }) +; } );

I have 5 page-scripts that do not use story, so they are still independent scripts for now until I can figure out how to get them into the menu automatically if I put their code into their indexes. I mentioned in the OP that I had to rewrite my base_menu subroutine. Lines 16-28 took me several hours over a couple of days to get right.

sub base_menu { my %opt = @_; my $directory = $opt{'directory'}; my $root_path = $opt{'root path'}; my $curr_cwd = cwd; my @contents = file_list($directory); @contents = grep {/^\p{uppercase}/} @contents if (!$opt{'full'} || $ +opt{'full'} !~ /^[yt1]/); # Thank you [tye]! # Thank you [davido]! my $sub = $directory =~ /(Other_poets|Player_characters|Spellbooks)$ +/ ? \&name_sort : \&article_sort; @contents = sort { $sub->($a, $b, { 'misc' => $opt{'misc'} }) } @con +tents; my (@files, @directories); if (!$opt{'full'} || $opt{'full'} !~ /^[yt1]/) { my $text_dir = $directory; $text_dir =~ s|(\Q$root_path\E)|$1/files/text|; my @text_files = sort { $sub->($a, $b, { 'misc' => $opt{'misc'} }) + } file_list($text_dir, { 'uppercase' => 1 }) if -e $text_dir; for my $text_file (@text_files) { my $text = textify($text_file); my $select = searchify($text_file); my $link = File::Spec->abs2rel("$directory/index.pl?page=$sele +ct"); my $class = $opt{'selected'} && $opt{'selected'} eq $text ? 'ac +tive' : 'inactive'; my $anchor = anchor($text, { 'href' => $link, 'title' => $text}) +; push @files, [$anchor, { 'class' => $class }] if -f "$text_dir/$ +text_file"; } } for my $content (@contents) { my $long_content = "$directory/$content"; my $link = File::Spec->abs2rel($long_content); my $text = $content !~ /^\./ ? textify($content) : $content; if (-f $long_content) { my $active = realpath($0) eq $long_content ? 'active' : 'inactiv +e'; my $color = $opt{'color'} == 1 ? link_color($content,1) : undef +; my $inlist = $active eq 'active' && $opt{'file menu'} ? ['u', $o +pt{'file menu'}, { 'class' => 'sub_menu' }] : undef; $active .= $active eq 'active' && $opt{'file menu'} ? ' open' +: ''; if (-M $long_content < 3) { $active .= ' updated'; } my $anchor = anchor($text, { 'href' => $link, 'title' => $text, +'style' => $color }); push @files, [$anchor, { 'class' => $active, 'inlist' => $inlist + }]; } if (-d $long_content) { my $active = $curr_cwd =~ /$long_content/ ? 'open active' : 'clo +sed inactive'; my $index = "$long_content/index.pl"; my $file_list; my $anchor; if (-e $index && (!$opt{'full'} || $opt{'full'} !~ /^[yt1]/)) { $link .= "/index.pl"; my $color = $opt{'color'} == 1 ? link_color($link,1) : undef; $anchor = anchor($text, { 'href' => $link, 'title' => $text, ' +style' => $color }); $file_list = "$curr_cwd/$0" =~ /$index/ && $active =~ / active +$/ && $opt{'file menu'} ? $opt{'file menu'} : undef; } my $next_list = base_menu( 'directory' => $long_content, 'color' => $opt{'color'}, 'full' => $opt{'full'}, 'misc' => $opt{'misc'}, 'selected' => $opt{'selected'}, 'file menu' => $opt{'file menu'}, 'root path' => $opt{'root path'} ); push @$next_list, @$file_list if $file_list; my $inlist = $next_list ? ['u', $next_list] : undef; $active =~ s/^(?:open|closed) // if !$inlist; push @directories, [$anchor ? $anchor : $text, { 'class' => $act +ive, 'inlist' => $inlist}]; } } my @file_lines = (@files, @directories); return @file_lines > 0 ? \@file_lines : undef; }

My OS is Debian 10 (Buster); my perl versions are 5.28.1 local and 5.8.8 on web host.

Version control is a non-issue, I do not use it.

No matter how hysterical I get, my problems are not time sensitive. So, relax, have a cookie, and a very nice day!
Lady Aleena

Replies are listed 'Best First'.
Re^2: Collapsing smaller scripts into a larger one, request for comment
by perlfan (Vicar) on Jun 13, 2020 at 20:07 UTC
    After our CB convo, I decide to try to follow my own advice, this is what I got for Programs.pl:
    #!/usr/bin/perl use strict; use warnings FATAL => qw( all ); package my::site::Programs; sub get_data { my $self = shift; # not used but passed with '->' notation return q{This is a list of B<programs> that I am using or have use +d. I can not account for I<all> the software we have had and used ove +r the years. Some of it was so bad, we blanked it out of our heads. T +his list does not include a full list of hardware drivers either. So +much software, so little time or in this case patience.}; } 1; # not sure if this is actually needed here, but would be if you mov +ed this to a .pm that is "use"d or "require"d # replicate the functionality of the original Programs.pl package main; use CGI::Carp qw(fatalsToBrowser); use lib '../files/lib'; use Base::Page qw(page story); use Util::StoryMagic qw(program_magic); my $magic = program_magic; page( 'code' => sub { story(my::site::Programs->get_data(), { 'line ma +gic' => $magic }) }); # note you'll have to change how you handle wha +t was passed as "*DATA" # # NOTE, since you're now not using __DATA__ (via *DATA handle), you ca +n make the "main" content # minimal by passing in just the code reference: # # package main; # use lib '../files/lib'; # Base::Page->page( code => \&my::site::Program::get_data, story => q{ +Util::StoryMagic} ); #

    The goal here was to show what I meant by making the catagory files into modules and to drop __DATA__. This offers no change to how things work now, but by converting all of your .pl files to a module internally, this sets you up for some things:

    1. incrementally put your data into module-like libraries
    2. move them to functional libraries by turning the above into a modulino - allows you to  use require q{../file/Programs.pl}, e.g.,
    3. once they work as they do now, but can be used us libraries as modulinos, you are free to experiment with Dancer2 or Mojo since they will fundamentally differ from your existing code being router/dispatch based and not file based (e.g., require content modules in the route handlers)
    4. then you can decide how to proceed, but this allows you to retain the functionality of the site now while exploring a more modern approach

    Then eventually if you made them full libraries, you'd pull them into to the framework like:

    # in framework route handing require q{path/to/Programs.pl}; my $data = my::site::Programs->get_data(); #...now do something with $data