Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

The Monastery Gates

( #131=superdoc: print w/replies, xml ) Need Help??

If you're new here please read PerlMonks FAQ
and Create a new user.

Quests
poll ideas quest 2020
Starts at: Jan 01, 2020 at 00:00
Ends at: Dec 31, 2020 at 23:59
Current Status: Active
12 replies by pollsters
    First, read How do I create a Poll?. Then suggest your poll here. Complete ideas are more likely to be used.

    Note that links may be used in choices but not in the title.

Perl News
rt.cpan to close, 01/03/2021
on Dec 05, 2020 at 04:22
5 replies by marto
Perl advent calendar 2020
on Dec 01, 2020 at 03:17
2 replies by marto
Supplications
Here documents in blocks
9 direct replies — Read more / Contribute
by Bod
on Dec 19, 2020 at 11:25

    When I created an account here some five weeks ago, little did I realise just how much varied learning I would receive in such a short time...so I am asking for advice on an issue that has had me scratching my head many times over the years. How best to lay out code when quite a bit of text output is required, such as when dynamically creating a webpage, inside an indented block.

    In the main body of the code I usually use an interpolating heredoc with any runtime variations defined in variables ahead of printing it all out.

    my $login_text = $user_number?'logout':'login'; print<<"END_HTML"; <div> ...part of webpage... <input type="button" name="log" value="$login_text" onClick="doSomethi +ng();"> ...more of webpage... </div> END_HTML
    That works and looks fine for a block of procedural code but I run into difficulties when I want to put something similar into an indented block for any reason. It could be a subroutine that is called to display a largely different page based on the query string or a significant block of content that is only shown under some conditions.
    if (isAdmin($user_number)) { print ...some extra content... }
    Heredocs don't work so well in these circumstances. I am using Perl 5.16 so don't get to use the print<<~"END_HTML"; syntax introduced in Perl 5.26.

    This leaves a few option.
    The one that most of my legacy code has is to simply put every line in a separate print statement

    if (isAdmin($user_number)) { print "<table>\n"; print "<tr>\n"; print "<td class=\"someclass\" style=\"text-align:center\">Some Co +ntent</td>\n"; print "</tr><tr>\n<td class=\"someClass\">Restricted</td>\n" if $u +ser_number == 20; print "</tr>\n"; print "</table>"; }
    Not very pretty and quite difficult to follow as it becomes more involved, especially as more and more HTML gets added over time. So a slight improvement that I used for a short time is with qq to save having to escape the quotation marks.
    print qq[<td class="someclass" style="text-align:center">Some Conte +nt</td>\n]; print qq[</tr><tr>\n<td class="someClass">Restricted</td>\n] if $us +er_number == 20;
    Slightly better - but still not very nice...

    I have tried having a subroutine to strip out leading spaces but this has the disadvantage of always stripping leading spaces even when they are wanted! In this format it also strips out blank lines although this is not too tricky to solve.

    #!/usr/bin/perl use strict; print "Content-type: text/plain\n\n"; print "Test\n\n"; sub indent { my $text = shift; $text =~ s/^\s+//gm; return $text; } if (1) { print indent(<<"END_TEXT"); Here is some test text with plenty of space at the start END_TEXT } exit 0;
    This still requires END_TEXT to be written without an indent.

    Many times I have searched for a solution and found several references to the issue but nothing offering a 'proper' solution. The topic of indentation in some form or another crops up periodically in all sorts of forms including Mandatory indenting which was interesting despite not being directly relevant.

    Other than upgrading to Perl 5.26 or later, is there an elegant solution to laying out code to print a lot of text in an indented block?

Server-side caching of webpages in Mojolicious
1 direct reply — Read more / Contribute
by rajaman
on Dec 17, 2020 at 16:49

    Dear Perl Monks,

    I am trying to figure out how I can do server-side caching of dynamic webpages that Mojolicious generates in response to webrequests. So that, expensive processing (e.g. on data pulled from a database) done on regenerating the same webpages again is bypassed for subsequent webrequests.

    I was looking for a file-based caching solution for Mojolicious, something like what this module does, but unfortunately the module seems outdated and does not install: Mojolicious::Plugin::Cache. In CGI, such a solution is implemented in CGI::Buffer, and Cache::Cache.

    I found caching support in Mojolicious, but this appears to be client-side caching, as shown below:

    helper 'cache_control.five_minutes' => sub ($c) { $c->res->headers->ca +che_control('public, max-age=300') }; get '/some_older_story' => sub ($c) { $c->cache_control->five_minutes; $c->render(text => 'This one can be cached for a bit.'); }; #ref: https://metacpan.org/pod/distribution/Mojolicious/lib/Mojoliciou +s/Guides/Rendering.pod

    I also tried to use statements as below, but this does not seem to work for me, maybe I am missing something here.

    use Mojolicious::Lite app->renderer->cache->max_keys(100);

    Please advise how to go about.

    Thank you very much!

Qualified package variable access
4 direct replies — Read more / Contribute
by jerryhone
on Dec 17, 2020 at 12:39
    Brothers...any help to identify what I'm doing wrong would be greatly appreciated... I'm putting together some Perl scripts that all connect to an Oracle database. I've put the database connectivity in a library file although I'm leaving each script's specific SQL in the script itself. In my library file (ECClib.pm) I have
    package ECClib; my $dbh; sub initialise(){ . . $dbh = db_connect($dbuser, $dbpasswd, $dbserver); . . )
    That's all fine and dandy, and I seem to get a good database connection. However, if I then try to use $ECClib::dbh in my parent script, it fails. My calling script has
    use ECClib; ECClib::initialise(); my $sql="select InputID from ECCInput order by InputID"; my $sth = $ECClib::dbh->prepare($sql);
    The statement handle assignment fails - debugging shows that $ECClib::dbh is undefined. What am I doing wrong?
How to run a legacy perl version smoothly from perlbrew & Carton
4 direct replies — Read more / Contribute
by chrestomanci
on Dec 17, 2020 at 08:11

    Greetings wise brothers, I seek your advice on how to concurrently access the old and the new.

    I am working on a legacy Perl system that makes heavy use of Storable objects (in a database, traversing the network etc), so it has to run Perl 5.10.1 and no other version. Up until now, it has been run on Ubuntu 10.04 Lucid, which means running a 10 year old Linux distro (with no support) on 10 year old hardware also with no support that could die at any moment.

    I would like to migrate the system to a modern OS (Ubuntu 20.04 Focal) and hardware, while using perlbrew to run the application using the correct Perl version. I have successfully built and installed Perl 5.10.1 and all the necessary libraries using Carton, but I have two problems with this setup that I would like to solve.

    Firstly, to run a Perl script with the correct libraries, I need to put “carton exec” on the front of each script invocation. If you don’t do that then the correct Perl binary runs, but it fails because it cannot find the modules that carton installed.

    How can I arrange things so that just running perl from a shell will do the right thing? (Run Perl 5.10.0 with the carton installed modules available), Perhaps by tweaking PERL5LIB for bash shells, or putting a wrapper script into the path? (note that I don't need to worry about multi user accounts here, all users login as root!)

    Secondly, there are about 200 CGI scripts mostly in Perl, and each with a #!/usr/bin/perl shebang line. How should I configure Apache to call my perlbrew installed version of perl, again with the carton installed modules, preferably without re-writing the shebang line on every script, though if I must do that, then the change needs to be backwards compatible with the old setup.

    Note that this is plain old CGI, not modperl FastCGI or anything like that. I would not object to using an FCGI wrapper if it can be dropped in painlessly, but not if it would require modifications to the scripts, or could be a source of bugs or incompatibilities.

    And before you say it, Yes I am well aware that it would be better to migrate away from Perl Storable. I have seen Elizabeth Mattijsen’s talks on how Booking.com did so at various Perl events. I also know that plain old CGI is no longer considered best practice. My problem is that this is a legacy system, and there is not much time or money available for major system changes, and there is no appetite for anything that could introduce hard to find bugs.

Logging and tracing with DBIx::Simple
2 direct replies — Read more / Contribute
by kaldor
on Dec 16, 2020 at 17:39

    Dear Monks,

    I need some advice about logging with DBIx::Simple (+ SQL::Interp), since I can't figure it out myself.

    I'd like a unified way to trace the SQL queries and log the application errors, so something like Log::Any seems the way to go. Of course, I'd rather see the placeholders replaced by quoted bind values in my logs, like DBI::Log does (but limited to DBI tracing). And there's also DBIx::LogAny.

    If it's possible to use DBIx::Simple and DBIx::LogAny together, then I don't understand how to do it. For example, DBIx::Simple::connect seems to call DBI::connect and DBIx::LogAny::connect calls SUPER::connect, so what will happen if I use both modules? Should I pass them $dbh, but then in what order?

    Thanks.
XML::Atom on MacOS Catalina
3 direct replies — Read more / Contribute
by astoller
on Dec 16, 2020 at 11:00
    Environment:
    • MacOS X 10.15.7 Catalina
    • Perl 5.33.4 installed via 'brew' (Homebrew 2.6.2)
    • cpan 1.64
    Issue
      I want to build/install Net::Google:Spreadsheets, which depends on:
      • Any::Moose (though there are a bunch of warnings that this should be replaced with Moo)
      • Net::Google::DataAPI
      • XML::Atom
      • and other modules which I've had no problem installing
      • The last one seems to be my current blocker, as XML::Atom fails to install.
    Build Output
      slightly modified to reduce line-wraps
      cpan[6]> install XML::Atom Running install for module 'XML::Atom' MIYAGAWA/XML-Atom-0.42.tar.gz Has already been unwrapped into directory ~/.cpan/build/XML-Atom-0.4 +2-6 Configuring M/MI/MIYAGAWA/XML-Atom-0.42.tar.gz with Build.PL Creating new 'Build' script for 'XML-Atom' version '0.42' MIYAGAWA/XML-Atom-0.42.tar.gz ~/perl5/perlbrew/perls/perl-5.33.4/bin/perl5.33.4 Build.PL -- OK Running Build for M/MI/MIYAGAWA/XML-Atom-0.42.tar.gz cp lib/XML/Atom/Link.pm blib/lib/XML/Atom/Link.pm cp lib/XML/Atom/ErrorHandler.pm blib/lib/XML/Atom/ErrorHandler.pm cp lib/XML/Atom/Base.pm blib/lib/XML/Atom/Base.pm cp lib/XML/Atom/Server.pm blib/lib/XML/Atom/Server.pm cp lib/XML/Atom/Entry.pm blib/lib/XML/Atom/Entry.pm cp lib/XML/Atom/Category.pm blib/lib/XML/Atom/Category.pm cp lib/XML/Atom/Thing.pm blib/lib/XML/Atom/Thing.pm cp lib/XML/Atom/Util.pm blib/lib/XML/Atom/Util.pm cp lib/XML/Atom.pm blib/lib/XML/Atom.pm cp lib/XML/Atom/Feed.pm blib/lib/XML/Atom/Feed.pm cp lib/XML/Atom/Content.pm blib/lib/XML/Atom/Content.pm cp lib/XML/Atom/Person.pm blib/lib/XML/Atom/Person.pm cp lib/XML/Atom/Client.pm blib/lib/XML/Atom/Client.pm MIYAGAWA/XML-Atom-0.42.tar.gz ./Build -- OK Running Build test for MIYAGAWA/XML-Atom-0.42.tar.gz t/00-compile.t ................... ok t/01-util.t ...................... ok t/02-content.t ................... ok t/03-link.t ...................... ok t/04-person.t .................... ok t/11-entry.t ..................... ok t/12-feed.t ...................... ok t/13-atom1.t ..................... ok t/14-atom1-create.t .............. ok t/15-content-image.t ............. ok t/16-content-binary.t ............ ok t/17-renames.t ................... ok t/18-unicode.t ................... skipped: Skipping Unicode test sinc +e it depends on LibXML t/19-ext.t ....................... ok t/20-content-xhtml.t ............. ok t/21-client.t .................... skipped: Don't do live Atom test t/22-autodiscovery.t ............. skipped: http://diveintomark.org/te +sts/client/autodiscovery/: 200 OK t/23-category.t .................. ok t/24-bad-content.t ............... ok t/25-utf8-create.t ............... ok t/27-client-leaks.t .............. ok t/28-ext.t ....................... ok t/29-source.t .................... ok t/30-datetime-stringification.t .. ok t/31-external-entities-libxml.t .. 1/4 # Failed test 'resolved entity' # at t/31-external-entities-libxml.t line 57. # '<p>No, Ben isn't updating. It's me testing out gu +est author functionality.</p>' # doesn't match '(?^:This is what you get when you do unit testing +)' # Looks like you failed 1 test of 4. t/31-external-entities-libxml.t .. Dubious, test returned 1 (wstat 256 +, 0x100) Failed 1/4 subtests t/31-external-entities-xpath.t ... # XPath Override in place Constant subroutine XML::Atom::LIBXML redefined at t/31-external-entit +ies-xpath.t line 18. External Entities disabled. at ~/.cpan/build/XML-Atom-0.42-6/blib/lib/ +XML/Atom.pm line 52. t/31-external-entities-xpath.t ... ok t/author-pod-syntax.t ............ skipped: these tests are for testin +g by the author Test Summary Report ------------------- t/31-external-entities-libxml.t (Wstat: 256 Tests: 4 Failed: 1) Failed test: 4 Non-zero exit status: 1 Files=27, Tests=285, 6 wallclock secs ( 0.09 usr 0.05 sys + 4.73 cu +sr 0.78 csys = 5.65 CPU) Result: FAIL MIYAGAWA/XML-Atom-0.42.tar.gz ./Build test -- NOT OK //hint// to see the cpan-testers results for installing this module, t +ry: reports MIYAGAWA/XML-Atom-0.42.tar.gz Failed during this command: MIYAGAWA/XML-Atom-0.42.tar.gz : make_test NO cpan[7]>
    Initial Question
      At first I was hung up on:
      t/18-unicode.t ................... skipped: Skipping Unicode test sinc +e it depends on LibXML
      which becomes more confusing when I see:
      cpan[7]> install XML::LibXML XML::LibXML is up to date (2.0206).
      but clearly the main issue is:
      t/31-external-entities-libxml.t .. 1/4 # Failed test 'resolved entity' # at t/31-external-entities-libxml.t line 57. # '<p>No, Ben isn't updating. It's me testing out gu +est author functionality.</p>' # doesn't match '(?^:This is what you get when you do unit testing +)' # Looks like you failed 1 test of 4.
      So... what can I do to fix this?
search json for key with particular value
3 direct replies — Read more / Contribute
by rahulruns
on Dec 15, 2020 at 09:00

    In a json if I want to search for a key which could be at any level and multiple places, how do I do it. Example I have below JSON. In JSON there are places where componentID is present. Each ComponentId is different. I need to search value of that componentId in json and where it matches pick that object in json. This is kind of function which helps to pickup that object out of json based on componentId value. Any module to achieve this or any idea to help on this

    json "infra": { "config": { "rack": [ { "componentId": "xxx-001", "model": "xxx", "server": [ { "componentId": "server-001", "type": "xxxx", "model": "xxxx", "role": "Management", "specificAttributes": "" ............ "platform": { "config": { "mgmtser": [{ "componentId": "sr-001", "domainName": "xxxxx", "thinDiskMode": true, "deployment": "small",
Override built-in functions?
1 direct reply — Read more / Contribute
by TorontoJim
on Dec 15, 2020 at 07:20
    I'm asking as a point of learning here. I have a simple module that takes a key/value pair, stores it, then lets the user access it. Basically, a hash but as a module. Why? Just so I can try different things out.

    The question is about naming methods in the module the same as Perl's built-in functions. For example, since I am storing key/value pairs I want to know if a key exists. Perl has a built-in function exists() and has to be called on an array or hash, e.g. exists(foo[0])

    That name "exists" is the perfect description of what I want to do with this module. So if I write in the module:

    sub exists { ... blah ... }
    I can call it without issue like this:
    use MyPackage; my $obj = MyPackage->new(); $obj->set_value('foo', 'bar'); if($obj->exists('foo')) { print "that key is there\n"; }

    It works just fine. So I want to know why I'm able to override the built-in function? Is it because the procedure I'm writing is always called by the object handle? Does that make it NOT the same as the built-in function?

    Just trying to understand how it works

Calculate jackknife error from of each column of a multi-column file
6 direct replies — Read more / Contribute
by pyari_billi
on Dec 15, 2020 at 03:03
    Hello Dear Monks I am a perl newbie. I am trying to calculate the jacknife average and error of each column in a multi-column file. My example data file look like this:
    $ cat data.HW2 1.1 2.1 3.1 4.1 1.2 2.2 3.2 4.2 1.3 2.3 3.3 4.3 1.4 2.4 3.4 4.4
    My attempted solution is to define arrays that will eventually be the size same as the number of columns (in this case 4) and iterate over them line by line:
    cat jackkinfe.pl #! /usr/bin/perl use warnings; use strict; my @n=0; my @x; my $j; my $i; my $dg; my @x_jack; my @x_tot=0; my $cols; my $col_start=0; # read in the data while(<>) { my @column = split(); $cols=@column; foreach my $j ($col_start .. $#column) { $x[$n[$j]][$j] = $column[$j]; $x_tot[$j] += $x[$n[$j]][$j]; $n[$j]++; } } # Do the jackknife estimates for ($j=$col_start; $j<$cols; $j++) { for ($i = 0; $i < $n[$j]; $i++) { $x_jack[$i][$j] = ($x_tot[$j] - $x[$i][$j]) / ($n[$j] - 1); } # Do the final jackknife estimate my @g_jack_av=0; my @g_jack_err=0; for ($i = 0; $i < $n[$j]; $i++) { $dg = $x_jack[$i][$j]; $g_jack_av[$j] += $dg; $g_jack_err[$j] += $dg**2; } $g_jack_av[$j] /= $n[$j]; $g_jack_err[$j] /= $n[$j]; $g_jack_err[$j] = sqrt(($n[$j] - 1) * abs($g_jack_err[$j] - $g_jack_ +av[$j]**2)); printf "%e %e ", $g_jack_av[$j], $g_jack_err[$j]; } printf "\n";
    It gives me the following two warnings:
    $cat data.HW2 | perl jackknife.pl Use of uninitialized value within @n in array element at cols_jacknife +.pl line 19, <> line 1. Use of uninitialized value within @n in array element at cols_jacknife +.pl line 20, <> line 1.
    It is complaining at the following two lines:
    $x[$n[$j]][$j] = $column[$j]; $x_tot[$j] += $x[$n[$j]][$j];
    But I want to set the size of @n dynamically depending on the size of the data file. How do I remove this warning? Any other suggestions on my perl usage are also welcome and much appreciated since I am trying to learn the best practices.
List into two-dimensional array
9 direct replies — Read more / Contribute
by Anonymous Monk
on Dec 14, 2020 at 13:21
    my ($C,$R)=(4,3); #Columns,Rows my @list = qw(1 2 3 4 5 6 7 8 9 10 11 12); my @AoA=(); while (@list) { push(@AoA, [ splice(@list, 0, $C) ]); } pp \@AoA; pp \@list; [[1 .. 4], [5 .. 8], [9 .. 12]] []

    I'm seeking an equivalent without splice - so that @list remains unaffected. Any suggestions...?

Cool Uses for Perl
Dynamically generate setter/getter methods
1 direct reply — Read more / Contribute
by stevieb
on Dec 20, 2020 at 04:03

    This isn't really a cool use for Perl, but more of a cool use of Perl.

    I was making some updates to my Hook::Output::Tiny software, in which I have a couple of subs that do the exact same thing, but the names are different. One thing I like to do in cases such as this is auto generate the subs dynamically.

    For example... you've got a module that has subs one(), two(), three() etc, and they all do the same thing... accept an optional value to stash into the object (setter), and return the value (getter). Each sub has the same (or perhaps different) default values. I always use the old-fashioned Perl way of writing OO code, so that would look like this:

    sub one { my ($self, $value) = @_; $self->{one} = $value if defined $value; return $self->{one} // 1; } sub two { my ($self, $value) = @_; $self->{two} = $value if defined $value; return $self->{two} // 2; } # and so on...

    That gets tedious and frustrating, and is prone to mistypes and other mistakes. What I often do in cases such as this, is auto generate these types of subs within a BEGIN block dynamically, using the magical no strict 'refs';, which allows us to muck with the symbol table directly and do very dangerous stuff in ways that one shouldn't normally do. Here's an example module:

    package Dynamic; use warnings; use strict; BEGIN { my %sub_info = ( one => 1, two => 2, three => 3, four => 4, five => 5, ); no strict 'refs'; for (keys %sub_info) { my $sub_name = $_; # Take a copy of the key, which is the sub +name *$_ = sub { my ($self, $value) = @_; $self->{$sub_name} = $value if defined $value; return $self->{$sub_name} // $sub_info{$sub_name}; }; } } sub new { return bless {}, $_[0]; } 1; __END__

    First, we set things up near the top of the file so it's easily visible within a BEGIN block to ensure the code is compiled first. Here's what's happening:

    • %sub_info is a hash that contains each sub name as the key, and the default value we'll return if the user doesn't change it
    • We disable strict's reference checking with no strict 'refs' so that we can perform super-dangerous stuff, like using a string as a symbol reference
    • Iterate over the hash and copy the key name into a separate variable
    • Set the current key name as the name of the new subroutine by prepending an asterisk to signify a symbol table entry, and assign it a new anonymous sub
    • Just like any other method, we put the code in exactly as we would if we were manually writing it out. Note the use of $sub_name instead of using just $_. This is because we've clobbered $_ by assigning a sub to it. This is why we made a copy of it above
    • Done! Looks just like any other setter/getter, but instead of typing out five subs that look near identical, we've only typed it out once, and let Perl write them for us in a loop

    Here's a script that puts the new module into action. Note that both the module and script are in the same directory for this demonstration:

    use warnings; use strict; use feature 'say'; use lib '.'; use Dynamic; my $dyn = Dynamic->new; say "Manual calls"; say $dyn->one; say $dyn->two; # Or even say "Stringified calls"; for (qw(one two three four five)) { if ($_ eq 'three') { # Update the value of the 'three' method $dyn->three(99); } printf "sub $_: %d\n", $dyn->$_(); }

    Output:

    spek@scelia ~/repos/scripts/perl/dynamically_auto_generate_subs $ perl + dyn.pl Manual calls 1 2 Stringified calls sub one: 1 sub two: 2 sub three: 99 sub four: 4 sub five: 5

    In closing, if you're only doing a couple of subs, it probably isn't worth the hassle, but when you are doing several, it makes things very simple, especially if you need to add new ones in the future. You simply have to enter a new record into the hash.

    Here's the code section that I just wrote that inspired me to write this post. It's from my Hook::Output::Tiny distribution. I am dynamically creating four methods... stdout() and stderr() which effectively do the same thing but act on different things, and their helper counterparts _stdout() and _stderr():

    BEGIN { # Auto generate the stdout() and stderr() methods, and their priva +te # helper counterparts no strict 'refs'; for ('stdout', 'stderr') { my $sub_name = $_; # Public *$_ = sub { my ($self) = @_; if (! wantarray) { warn "Calling $sub_name() in non-list context is depre +cated!\n"; } return defined $self->{$sub_name}{data} ? split /\n/, $self->{$sub_name}{data} : @{[ () ]}; # Empty list }; # Private my $private_sub_name = "_$sub_name"; *$private_sub_name = sub { my ($self) = @_; my $HANDLE = uc $sub_name; open $self->{$sub_name}{handle}, ">&$HANDLE" or die "can't hook " . uc $sub_name . ": $!"; close $HANDLE; open $HANDLE, '>>', \$self->{$sub_name}{data} or die $!; }; } }
    Disclaimer: I'm not joking about hacking at the symbol table directly in ways perl doesn't normally allow being dangerous. It's very easy to clobber stuff far away in your code when you do these things.
Log In?
Username:
Password:

What's my password?
Create A New User
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others contemplating the Monastery: (2)
As of 2020-12-20 18:40 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    How often do you use taint mode?





    Results (183 votes). Check out past polls.

    Notices?