Tag: work

  • Lightweight object-​oriented Perl scripts: From modulinos to moodulinos

    Lightweight object-​oriented Perl scripts: From modulinos to moodulinos

    Last week I found myself devel­op­ing a Perl script to cat­a­log some infor­ma­tion for our qual­i­ty assur­ance team. Unfortunately, as these things some­times do, the scrip­t’s com­plex­i­ty and require­ments start­ed increas­ing. I still want­ed to keep it as a sim­ple script. Yet, it was grow­ing com­mand line argu­ments that need­ed extra val­i­da­tion. I also need­ed to test some func­tions with­out wait­ing for the entire script to run.

    As with many things Perl, the basic solu­tion is fair­ly old. Over twen­ty years ago, bri­an d foy pop­u­lar­ized the mod­uli­no pat­tern. in which Perl scripts that you exe­cute from the com­mand line can also act as Perl mod­ules. You can even use these mod­ules in oth­er con­texts, for exam­ple test­ing.* A mod­uli­no seemed like the per­fect solu­tion for test­ing indi­vid­ual script func­tions, but writ­ing object-​oriented Perl out­side of a frame­work (or the new Perl class syn­tax) can be chal­leng­ing and verbose.

    Enter the cow (Moo)

    The Moo sys­tem of mod­ules are billed as a light­weight way ​“to con­cise­ly define objects and roles with a con­ve­nient syn­tax that avoids the details of Perl’s object sys­tem.” It does­n’t have any XS code. Thus, it does­n’t need a C com­pil­er to install. Unlike its inspi­ra­tion, Moose, it’s opti­mized for the fast start­up time need­ed for a command-​line script. Sure, you don’t get a full-​strength meta-​object pro­to­col for query­ing and manip­u­lat­ing class­es, objects, and attributes—those capa­bil­i­ties are con­cerns for larg­er appli­ca­tions or libraries. In keep­ing with the light­weight theme, you can use Type::Tiny con­straints for para­me­ter val­i­da­tion. Additionally, there are sev­er­al solu­tions for turn­ing command-​line argu­ments into object attrib­ut­es. (I chose to use MooX::Options, main­ly because of its easy avail­abil­i­ty as an Ubuntu Linux pack­age.)

    I’m not about to dump a pro­pri­etary script here on my blog. Yet, I have worked up an illus­tra­tive exam­ple of how to incor­po­rate Moo into a mod­uli­no. Call it a ​“mooduli­no” if you like; here’s a short-​ish script to tell Perl just how you feel at this time of day:

    #!/usr/bin/env perl
    
    use v5.38;
    
    package moodulino;
    use Moo;
    use MooX::Options;
    use Types::Standard qw(ArrayRef Str);
    
    option name => (
        is       => 'ro',
        isa      => Str,
        required => 1,
        short    => 'n',
        doc      => 'your name here',
        format   => 's',
    );
    
    option moods => (
        is        => 'ro',
        isa       => ArrayRef [Str],
        predicate => 1,
        short     => 'm',
        doc       => 'a list of how you might feel',
        format    => 's@',
        autosplit => ',',
    );
    
    has time_of_day => (
        is      => 'ro',
        isa     => Str,
        builder => 1,
    );
    
    sub _build_time_of_day ($self) {
        my %hours = (
             5 => ‘morning’,
            12 => 'afternoon',
            17 => 'evening',
            21 => 'night',
        );
    
        for ( sort { $b <=> $a } keys %hours ) {
            return $hours{$_} if (localtime)[2] >= $_;
        }
        return 'night';
    }
    
    sub run ($self) {
        printf "Good %s, %s!\n",
          $self->time_of_day,
          $self->name;
    
        if ( $self->has_moods ) {
            say 'How are you feeling?';
            say "- $_?" for $self->moods->@*;
        }
    }
    
    package main;
    
    main() unless caller;
    
    sub main { moodulino->new_with_options->run() }

    And here’s what hap­pens when I run it:

    % chmod a+x moodulino.pm
    % ./moodulino.pm
    name is missing
    USAGE: moodulino.pm [-h] [long options ...]
    
        -m --moods=[Strings]  a list of how you might feel
        -n --name=String      your name here
    
        --usage               show a short help message
        -h                    show a compact help message
        --help                show a long help message
        --man                 show the manual
    % ./moodulino.pm --name Mark
    Good afternoon, Mark!
    % ./moodulino.pm —name Mark --moods happy --moods sad --moods excited
    Good afternoon, Mark!
    How are you feeling?
    - happy?
    - sad?
    - excited?
    % ./moodulino.pm —name Mark --moods happy,sad,excited
    Good afternoon, Mark!
    How are you feeling?
    - happy?
    - sad?
    - excited?

    If the mood strikes, I can even write a test script for my script:

    #!/usr/bin/env perl
    
    use v5.38;
    use Test2::V0;
    use moodulino;
    
    plan(3);
    
    my $mood = moodulino->new( name => 'Bessy' );
    isa_ok( $mood, 'moodulino' );
    can_ok( $mood, 'time_of_day' );
    
    is( $mood->time_of_day,
        in_set( qw(
            morning
            afternoon
            evening
            night
        ) ) );

    And run it:

    % prove -I. t/time_of_day.t
    t/daytime.t .. ok
    All tests successful.
    Files=1, Tests=3,  0 wallclock secs ( 0.00 usr  0.00 sys +  0.07 cusr  0.01 csys =  0.08 CPU)
    Result: PASS

    * foy lat­er expand­ed this idea into the chap­ter ​“Modules as Programs” in Mastering Perl (2007). You can also read more in his 2014 arti­cle ​“Rescue lega­cy code with mod­uli­nos”. Also explore Gábor Szabó’s arti­cles on the top­ic. ↩︎

  • Perl list processing is for hashes, too

    Perl list processing is for hashes, too

    This month I start­ed a new job at Alert Logic, a cyber­se­cu­ri­ty provider with Perl (among many oth­er things) at its beat­ing heart. I’ve been learn­ing a lot, and part of the process has been under­stand­ing the APIs in the code base. To that end, I’ve been writ­ing small test scripts to tease apart data struc­tures, using Perl array-​processing, list-​processing, and hash- (i.e., asso­cia­tive array)-processing func­tions.

    I’ve cov­ered map, grep, and friends a cou­ple times before. Most recent­ly, I described using List::Util’s any func­tion to check if a con­di­tion is true for any item in a list. In the sim­plest case, you can use it to check to see if a giv­en val­ue is in the list at all:

    use feature 'say';
    use List::Util 'any';
    my @colors =
      qw(red orange yellow green blue indigo violet);
    say 'matched' if any { /^red$/ } @colors;

    However, if you’re going to be doing this a lot with arbi­trary strings, Perl FAQ sec­tion 4 advis­es turn­ing the array into the keys of a hash and then check­ing for mem­ber­ship there. For exam­ple, here’s a sim­ple script to check if the col­ors input (either from the key­board or from files passed as argu­ments) are in the rainbow:

    #!/usr/bin/env perl
    
    use v5.22; # introduced <<>> for safe opening of arguments
    use warnings;
     
    my %in_colors = map {$_ => 1}
      qw(red orange yellow green blue indigo violet);
    
    while (<<>>) {
      chomp;
      say "$_ is in the rainbow" if $in_colors{$_};
    }

    List::Util has a bunch of func­tions for pro­cess­ing lists of pairs that I’ve found use­ful when paw­ing through hash­es. pairgrep, for exam­ple, acts just like grep but instead assigns $a and $b to each key and val­ue passed in and returns the result­ing pairs that match. I’ve used it as a quick way to search for hash entries match­ing cer­tain val­ue conditions:

    use List::Util 'pairgrep';
    my %numbers = (zero => 0, one => 1, two => 2, three => 3);
    my %odds = pairgrep {$b % 2} %numbers;

    Sure, you could do this by invok­ing a mix of plain grep, keys, and a hash slice, but it’s nois­i­er and more repetitive:

    use v5.20; # for key/value hash slice 
    my %odds = %numbers{grep {$numbers{$_} % 2} keys %numbers};

    pairgrep​’s com­piled C‑based XS code can also be faster, as evi­denced by this Benchmark script that works through a hash made of the Unix words file (479,828 entries on my machine):

    #!/usr/bin/env perl
    
    use v5.20;
    use warnings;
    use List::Util 'pairgrep';
    use Benchmark 'cmpthese';
    
    my (%words, $count);
    open my $fh, '<', '/usr/share/dict/words'
      or die "can't open words: $!";
    while (<$fh>) {
      chomp;
      $words{$_} = $count++;
    }
    close $fh;
    
    cmpthese(100, {
      grep => sub {
        my %odds = %words{grep {$words{$_} % 2} keys %words};
      },
      pairgrep => sub {
        my %odds = pairgrep {$b % 2} %words;
      },
    } );

    Benchmark out­put:

               Rate     grep pairgrep
    grep     1.47/s       --     -20%
    pairgrep 1.84/s      25%       --

    In gen­er­al, I urge you to work through the Perl doc­u­men­ta­tion​’s tuto­ri­als on ref­er­ences, lists of lists, the data struc­tures cook­book, and the FAQs on array and hash manip­u­la­tion. Then dip into the var­i­ous list-​processing mod­ules (espe­cial­ly the includ­ed List::Util and CPAN’s List::SomeUtils) for ready-​made func­tions for com­mon oper­a­tions. You’ll find a wealth of tech­niques for cre­at­ing, man­ag­ing, and pro­cess­ing the data struc­tures that your pro­grams need.

  • 34 at 34 for v5.34: Modern Perl features for Perl’s birthday

    34 at 34 for v5.34: Modern Perl features for Perl’s birthday

    Friday, December 17, 2021, marked the thirty-​fourth birth­day of the Perl pro­gram­ming lan­guage, and coin­ci­den­tal­ly this year saw the release of ver­sion 5.34. There are plen­ty of Perl devel­op­ers out there who haven’t kept up with recent (and not-​so-​recent) improve­ments to the lan­guage and its ecosys­tem, so I thought I might list a batch. (You may have seen some of these before in May’s post ​“Perl can do that now!”)

    The feature pragma

    Perl v5.10 was released in December 2007, and with it came feature, a way of enabling new syn­tax with­out break­ing back­ward com­pat­i­bil­i­ty. You can enable indi­vid­ual fea­tures by name (e.g., use feature qw(say fc); for the say and fc key­words), or by using a fea­ture bun­dle based on the Perl ver­sion that intro­duced them. For exam­ple, the following:

    use feature ':5.34';

    …gives you the equiv­a­lent of:

    use feature qw(bareword_filehandles bitwise current_sub evalbytes fc indirect multidimensional postderef_qq say state switch unicode_eval unicode_strings);

    Boy, that’s a mouth­ful. Feature bun­dles are good. The cor­re­spond­ing bun­dle also gets implic­it­ly loaded if you spec­i­fy a min­i­mum required Perl ver­sion, e.g., with use v5.32;. If you use v5.12; or high­er, strict mode is enabled for free. So just say:

    use v5.34;

    And last­ly, one-​liners can use the -E switch instead of -e to enable all fea­tures for that ver­sion of Perl, so you can say the fol­low­ing on the com­mand line:

    perl -E 'say "Hello world!"'

    Instead of:

    perl -e 'print "Hello world!\n"'

    Which is great when you’re try­ing to save some typing.

    The experimental pragma

    Sometimes new Perl fea­tures need to be dri­ven a cou­ple of releas­es around the block before their behav­ior set­tles. Those exper­i­ments are doc­u­ment­ed in the per­l­ex­per­i­ment page, and usu­al­ly, you need both a use feature (see above) and no warnings state­ment to safe­ly enable them. Or you can sim­ply pass a list to use experimental of the fea­tures you want, e.g.:

    use experimental qw(isa postderef signatures);

    Ever-​expanding warnings categories

    March 2000 saw the release of Perl 5.6, and with it, the expan­sion of the -w command-​line switch to a sys­tem of fine-​grained con­trols for warn­ing against ​“dubi­ous con­structs” that can be turned on and off depend­ing on the lex­i­cal scope. What start­ed as 26 main and 20 sub­cat­e­gories has expand­ed into 31 main and 43 sub­cat­e­gories, includ­ing warn­ings for the afore­men­tioned exper­i­men­tal features.

    As the rel­e­vant Perl::Critic pol­i­cy says, ​“Using warn­ings, and pay­ing atten­tion to what they say, is prob­a­bly the sin­gle most effec­tive way to improve the qual­i­ty of your code.” If you must vio­late warn­ings (per­haps because you’re reha­bil­i­tat­ing some lega­cy code), you can iso­late such vio­la­tions to a small scope and indi­vid­ual cat­e­gories. Check out the stric­tures mod­ule on CPAN if you’d like to go fur­ther and make a safe sub­set of these cat­e­gories fatal dur­ing development.

    Document other recently-​introduced syntax with Syntax::Construct

    Not every new bit of Perl syn­tax is enabled with a feature guard. For the rest, there’s E. Choroba’s Syntax::Construct mod­ule on CPAN. Rather than hav­ing to remem­ber which ver­sion of Perl intro­duced what, Syntax::Construct lets you declare only what you use and pro­vides a help­ful error mes­sage if some­one tries to run your code on an old­er unsup­port­ed ver­sion. Between it and the feature prag­ma, you can pre­vent many head-​scratching moments and give your users a chance to either upgrade or workaround.

    Make built-​in functions throw exceptions with autodie

    Many of Perl’s built-​in func­tions only return false on fail­ure, requir­ing the devel­op­er to check every time whether a file can be opened or a system com­mand exe­cut­ed. The lex­i­cal autodie prag­ma replaces them with ver­sions that raise an excep­tion with an object that can be inter­ro­gat­ed for fur­ther details. No mat­ter how many func­tions or meth­ods deep a prob­lem occurs, you can choose to catch it and respond appro­pri­ate­ly. This leads us to…

    try/​catch exception handling and Feature::Compat::Try

    This year’s Perl v5.34 release intro­duced exper­i­men­tal try/​catch syn­tax for excep­tion han­dling that should look more famil­iar to users of oth­er lan­guages while han­dling the issues sur­round­ing using block eval and test­ing of the spe­cial $@ vari­able. If you need to remain com­pat­i­ble with old­er ver­sions of Perl (back to v5.14), just use the Feature::Compat::Try mod­ule from CPAN to auto­mat­i­cal­ly select either v5.34’s native try/​catch or a sub­set of the func­tion­al­i­ty pro­vid­ed by Syntax::Keyword::Try.

    Pluggable keywords

    The above­men­tioned Syntax::Keyword::Try was made pos­si­ble by the intro­duc­tion of a plug­gable key­word mech­a­nism in 2010’s Perl v5.12. So was the Future::AsyncAwait asyn­chro­nous pro­gram­ming library and the Object::Pad test­bed for new object-​oriented Perl syn­tax. If you’re handy with C and Perl’s XS glue lan­guage, check out Paul ​“LeoNerd” Evans’ XS::Parse::Keyword mod­ule to get a leg up on devel­op­ing your own syn­tax module.

    Define packages with versions and blocks

    Perl v5.12 also helped reduce clut­ter by enabling a package name­space dec­la­ra­tion to also include a ver­sion num­ber, instead of requir­ing a sep­a­rate our $VERSION = ...; v5.14 fur­ther refined packages to be spec­i­fied in code blocks, so a name­space dec­la­ra­tion can be the same as a lex­i­cal scope. Putting the two togeth­er gives you:

    package Local::NewHotness v1.2.3 {
        ...
    }

    Instead of:

    {
        package Local::OldAndBusted;
        use version 0.77; our $VERSION = version->declare("v1.2.3");
        ...
    }

    I know which I’d rather do. (Though you may want to also use Syntax::Construct qw(package-version package-block); to help along with old­er instal­la­tions as described above.)

    The // defined-​or operator

    This is an easy win from Perl v5.10:

    defined $foo ? $foo : $bar  # replace this
    $foo // $bar                # with this

    And:

    $foo = $bar unless defined $foo  # replace this
    $foo //= $bar                    # with this

    Perfect for assign­ing defaults to variables.

    state variables only initialize once

    Speaking of vari­ables, ever want one to keep its old val­ue the next time a scope is entered, like in a sub? Declare it with state instead of my. Before Perl v5.10, you need­ed to use a clo­sure instead.

    Save some typing with say

    Perl v5.10’s bumper crop of enhance­ments also includ­ed the say func­tion, which han­dles the com­mon use case of printing a string or list of strings with a new­line. It’s less noise in your code and saves you four char­ac­ters. What’s not to love?

    Note unimplemented code with ...

    The ... ellip­sis state­ment (col­lo­qui­al­ly ​“yada-​yada”) gives you an easy place­hold­er for yet-​to-​be-​implemented code. It pars­es OK but will throw an excep­tion if exe­cut­ed. Hopefully, your test cov­er­age (or at least sta­t­ic analy­sis) will catch it before your users do.

    Loop and enumerate arrays with each, keys, and values

    The each, keys, and values func­tions have always been able to oper­ate on hash­es. Perl v5.12 and above make them work on arrays, too. The lat­ter two are main­ly for con­sis­ten­cy, but you can use each to iter­ate over an array’s indices and val­ues at the same time:

    while (my ($index, $value) = each @array) {
        ...
    }

    This can be prob­lem­at­ic in non-​trivial loops, but I’ve found it help­ful in quick scripts and one-liners.

    delete local hash (and array) entries

    Ever need­ed to delete an entry from a hash (e.g, an envi­ron­ment vari­able from %ENV or a sig­nal han­dler from %SIG) just inside a block? Perl v5.12 lets you do that with delete local.

    Paired hash slices

    Jumping for­ward to 2014’s Perl v5.20, the new %foo{'bar', 'baz'} syn­tax enables you to slice a sub­set of a hash with its keys and val­ues intact. Very help­ful for cherry-​picking or aggre­gat­ing many hash­es into one. For example:

    my %args = (
        verbose => 1,
        name    => 'Mark',
        extra   => 'pizza',
    );
    # don't frob the pizza
    $my_object->frob( %args{ qw(verbose name) };

    Paired array slices

    Not to be left out, you can also slice arrays in the same way, in this case return­ing indices and values:

    my @letters = 'a' .. 'z';
    my @subset_kv = %letters[16, 5, 18, 12];
    # @subset_kv is now (16, 'p', 5, 'e', 18, 'r', 12, 'l')

    More readable dereferencing

    Perl v5.20 intro­duced and v5.24 de-​experimentalized a more read­able post­fix deref­er­enc­ing syn­tax for nav­i­gat­ing nest­ed data struc­tures. Instead of using {braces} or smoosh­ing sig­ils to the left of iden­ti­fiers, you can use a post­fixed sigil-and-star:

    push @$array_ref,    1, 2, 3;  # noisy
    push @{$array_ref},  1, 2, 3;  # a little easier
    push $array_ref->@*, 1, 2, 3;  # read from left to right

    So much of web devel­op­ment is sling­ing around and pick­ing apart com­pli­cat­ed data struc­tures via JSON, so I wel­come any­thing like this to reduce the cog­ni­tive load.

    when as a statement modifier

    Starting in Perl v5.12, you can use the exper­i­men­tal switch fea­ture​’s when key­word as a post­fix mod­i­fi­er. For example:

    for ($foo) {
        $a =  1 when /^abc/;
        $a = 42 when /^dna/;
        ...
    }

    But I don’t rec­om­mend when, given, or given​’s smart­match oper­a­tions as they were ret­conned as exper­i­ments in 2013’s Perl v5.18 and have remained so due to their tricky behav­ior. I wrote about some alter­na­tives using sta­ble syn­tax back in February.

    Simple class inheritance with use parent

    Sometimes in old­er object-​oriented Perl code, you’ll see use base as a prag­ma to estab­lish inher­i­tance from anoth­er class. Older still is the direct manip­u­la­tion of the package’s spe­cial @ISA array. In most cas­es, both should be avoid­ed in favor of use parent, which was added to core in Perl v5.10.1.

    Mind you, if you’re fol­low­ing the Perl object-​oriented tutorial’s advice and have select­ed an OO sys­tem from CPAN, use its sub­class­ing mech­a­nism if it has one. Moose, Moo, and Class::Accessor’s ​“antlers” mode all pro­vide an extends func­tion; Object::Pad pro­vides an :isa attribute on its class key­word.

    Test for class membership with the isa operator

    As an alter­na­tive to the isa() method pro­vid­ed to all Perl objects, Perl v5.32 intro­duced the exper­i­men­tal isa infix oper­a­tor:

    $my_object->isa('Local::MyClass')
    # or
    $my_object isa Local::MyClass

    The lat­ter can take either a bare­word class name or string expres­sion, but more impor­tant­ly, it’s safer as it also returns false if the left argu­ment is unde­fined or isn’t a blessed object ref­er­ence. The old­er isa() method will throw an excep­tion in the for­mer case and might return true if called as a class method when $my_object is actu­al­ly a string of a class name that’s the same as or inher­its from isa()​’s argu­ment.

    Lexical subroutines

    Introduced in Perl v5.18 and de-​experimentalized in 2017’s Perl v5.26, you can now pre­cede sub dec­la­ra­tions with my, state, or our. One use of the first two is tru­ly pri­vate func­tions and meth­ods, as described in this 2018 Dave Jacoby blog and as part of Neil Bowers’ 2014 sur­vey of pri­vate func­tion techniques.

    Subroutine signatures

    I’ve writ­ten and pre­sent­ed exten­sive­ly about sig­na­tures and alter­na­tives over the past year, so I won’t repeat that here. I’ll just add that the Perl 5 Porters devel­op­ment mail­ing list has been mak­ing a con­cert­ed effort over the past month to hash out the remain­ing issues towards ren­der­ing this fea­ture non-​experimental. The pop­u­lar Mojolicious real-​time web frame­work also pro­vides a short­cut for enabling sig­na­tures and uses them exten­sive­ly in examples.

    Indented here-​documents with <<~

    Perl has had shell-​style ​“here-​document” syn­tax for embed­ding multi-​line strings of quot­ed text for a long time. Starting with Perl v5.26, you can pre­cede the delim­it­ing string with a ~ char­ac­ter and Perl will both allow the end­ing delim­iter to be indent­ed as well as strip inden­ta­tion from the embed­ded text. This allows for much more read­able embed­ded code such as runs of HTML and SQL. For example:

    if ($do_query) {
        my $rows_deleted = $dbh->do(<<~'END_SQL', undef, 42);
          DELETE FROM table
          WHERE status = ?
          END_SQL
        say "$rows_deleted rows were deleted."; 
    }

    More readable chained comparisons

    When I learned math in school, my teach­ers and text­books would often describe mul­ti­ple com­par­isons and inequal­i­ties as a sin­gle expres­sion. Unfortunately, when it came time to learn pro­gram­ming every com­put­er lan­guage I saw required them to be bro­ken up with a series of and (or &&) oper­a­tors. With Perl v5.32, this is no more:

    if ( $x < $y && $y <= $z ) { ... }  # old way
    if ( $x < $y <= $z )       { ... }  # new way

    It’s more con­cise, less noisy, and more like what reg­u­lar math looks like.

    Self-​documenting named regular expression captures

    Perl’s expres­sive reg­u­lar expres­sion match­ing and text-​processing prowess are leg­endary, although overuse and poor use of read­abil­i­ty enhance­ments often turn peo­ple away from them (and Perl in gen­er­al). We often use reg­ex­ps for extract­ing data from a matched pat­tern. For example:

    if ( /Time: (..):(..):(..)/ ) {  # parse out values
        say "$1 hours, $2 minutes, $3 seconds";
    }

    Named cap­ture groups, intro­duced in Perl v5.10, make both the pat­tern more obvi­ous and retrieval of its data less cryptic:

    if ( /Time: (?<hours>..):(?<minutes>..):(?<seconds>..)/ ) {
        say "$+{hours} hours, $+{minutes} minutes, $+{seconds} seconds";
    }

    More readable regexp character classes

    The /x reg­u­lar expres­sion mod­i­fi­er already enables bet­ter read­abil­i­ty by telling the pars­er to ignore most white­space, allow­ing you to break up com­pli­cat­ed pat­terns into spaced-​out groups and mul­ti­ple lines with code com­ments. With Perl v5.26 you can spec­i­fy /xx to also ignore spaces and tabs inside [brack­et­ed] char­ac­ter class­es, turn­ing this:

    /[d-eg-i3-7]/
    /[!@"#$%^&*()=?<>']/

    …into this:

    / [d-e g-i 3-7]/xx
    /[ ! @ " # $ % ^ & * () = ? <> ' ]/xx

    Set default regexp flags with the re pragma

    Beginning with Perl v5.14, writ­ing use re '/xms'; (or any com­bi­na­tion of reg­u­lar expres­sion mod­i­fi­er flags) will turn on those flags until the end of that lex­i­cal scope, sav­ing you the trou­ble of remem­ber­ing them every time.

    Non-​destructive substitution with s///r and tr///r

    The s/// sub­sti­tu­tion and tr/// translit­er­a­tion oper­a­tors typ­i­cal­ly change their input direct­ly, often in con­junc­tion with the =~ bind­ing oper­a­tor:

    s/foo/bar/;  # changes the first foo to bar in $_
    $baz =~ s/foo/bar/;  # the same but in $baz

    But what if you want to leave the orig­i­nal untouched, such as when pro­cess­ing an array of strings with a map? With Perl v5.14 and above, add the /r flag, which makes the sub­sti­tu­tion on a copy and returns the result:

    my @changed = map { s/foo/bar/r } @original;

    Unicode case-​folding with fc for better string comparisons

    Unicode and char­ac­ter encod­ing in gen­er­al are com­pli­cat­ed beasts. Perl has han­dled Unicode since v5.6 and has kept pace with fix­es and sup­port for updat­ed stan­dards in the inter­ven­ing decades. If you need to test if two strings are equal regard­less of case, use the fc func­tion intro­duced in Perl v5.16.

    Safer processing of file arguments with <<>>

    The <> null file­han­dle or ​“dia­mond oper­a­tor” is often used in while loops to process input per line com­ing either from stan­dard input (e.g., piped from anoth­er pro­gram) or from a list of files on the com­mand line. Unfortunately, it uses a form of Perl’s open func­tion that inter­prets spe­cial char­ac­ters such as pipes (|) that would allow it to inse­cure­ly run exter­nal com­mands. Using the <<>> ​“dou­ble dia­mond” oper­a­tor intro­duced in Perl v5.22 forces open to treat all command-​line argu­ments as file names only. For old­er Perls, the per­lop doc­u­men­ta­tion rec­om­mends the ARGV::readonly CPAN mod­ule.

    Safer loading of Perl libraries and modules from @INC

    Perl v5.26 removed the abil­i­ty for all pro­grams to load mod­ules by default from the cur­rent direc­to­ry, clos­ing a secu­ri­ty vul­ner­a­bil­i­ty orig­i­nal­ly iden­ti­fied and fixed as CVE-2016–1238 in pre­vi­ous ver­sions’ includ­ed scripts. If your code relied on this unsafe behav­ior, the v5.26 release notes include steps on how to adapt.

    HTTP::Tiny simple HTTP/1.1 client included

    To boot­strap access to CPAN on the web in the pos­si­ble absence of exter­nal tools like curl or wget, Perl v5.14 began includ­ing the HTTP::Tiny mod­ule. You can also use it in your pro­grams if you need a sim­ple web client with no dependencies.

    Test2: The next generation of Perl testing frameworks

    Forked and refac­tored from the ven­er­a­ble Test::Builder (the basis for the Test::More library that many are famil­iar with), Test2 was includ­ed in the core mod­ule library begin­ning with Perl v5.26. I’ve exper­i­ment­ed recent­ly with using the Test2::Suite CPAN library instead of Test::More and it looks pret­ty good. I’m also intrigued by Test2::Harness’ sup­port for thread­ing, fork­ing, and pre­load­ing mod­ules to reduce test run times.

    Task::Kensho: Where to start for recommended Perl modules

    This last item may not be includ­ed when you install Perl, but it’s where I turn for a col­lec­tion of well-​regarded CPAN mod­ules for accom­plish­ing a wide vari­ety of com­mon tasks span­ning from asyn­chro­nous pro­gram­ming to XML. Use it as a start­ing point or inter­ac­tive­ly select the mix of libraries appro­pri­ate to your project.


    And there you have it: a selec­tion of 34 fea­tures, enhance­ments, and improve­ments for the first 34 years of Perl. What’s your favorite? Did I miss any­thing? Let me know in the comments.

  • A brief note on Log4perl

    A brief note on Log4perl

    The Java world had an… inter­est­ing week­end when secu­ri­ty researchers revealed on December 9 a vul­ner­a­bil­i­ty in the pop­u­lar Apache Log4j 2 soft­ware library for record­ing and debug­ging events. Systems as diverse as Amazon Web Services, Apple iCloud, and the Minecraft video game could be exploit­ed to run arbi­trary code on a serv­er mere­ly by send­ing a specially-​crafted string of text. Information tech­nol­o­gy pro­fes­sion­als have been scram­bling ever since the ini­tial dis­clo­sure to patch, upgrade, recon­fig­ure, or oth­er­wise pro­tect affect­ed servers. It’s bad, and past unpatched vul­ner­a­bil­i­ties like this have been respon­si­ble for the expo­sure of mil­lions of people’s sen­si­tive data.

    Many Perl appli­ca­tions use the similarly-​named and ‑designed Log::Log4perl library, and the good news is that as far as I can tell the lat­ter doesn’t suf­fer from the type of vul­ner­a­bil­i­ty described above. This doesn’t mean poorly-​written or ‑con­fig­ured Perl-​based sys­tems are immune to all exploits, just this par­tic­u­lar one. You should be safe to con­tin­ue using Log4perl unless some­one has delib­er­ate­ly con­fig­ured it oth­er­wise, and in fact, my work uses it extensively.

    You might be sur­prised to read me sug­gest­ing a log­ging frame­work after writ­ing mul­ti­ple arti­cles espous­ing the Perl step debug­ger as an alter­na­tive. Log4perl devel­op­er Mike Schilli’s 2002 intro­duc­tion to the pack­age for Perl.com came down on the oppo­site side of the argu­ment. It can seem like one of those pro­gram­mer reli­gious issues like tabs vs. spaces, vim vs. Emacs, or Linux vs. Windows. (For the record, the cor­rect answers are spaces, BBEdit, and macOS. 😉)

    But in this case, you can and should have the best of both worlds—logging at dif­fer­ent lev­els to appro­pri­ate des­ti­na­tions while still drop­ping into the inter­ac­tive debug­ger when you need to do some­thing trick­i­er like exam­ine pro­gram state or tweak a data struc­ture on the fly. I use both tech­niques and only empha­size the advo­ca­cy of step debug­ging because it’s under­stood less.

  • Multiple ways to inheritance in Perl

    Multiple ways to inheritance in Perl

    Inspired by my par­ents com­ing to vis­it at the end of the week, I thought I’d write about how Perl class­es can have ​“par­ents” as well, from which they inher­it meth­ods. Although it might seem on the sur­face as though there’s more than one way to do it, these tech­niques all share the same under­ly­ing mechanism.

    Where it all BEGINs: @ISA

    Perl class­es are just repur­posed packages, i.e., a name­space for vari­ables and sub­rou­tines. The two key dif­fer­ences are:

    If you want­ed to do every­thing by hand at the low­est lev­el, you could make a sub­class at com­pile time like this:

    package Local::MyChildClass;
    BEGIN { # don't do this:
        require Local::MyParentClass;
        push @ISA, 'Local::MyParentClass';
    }

    Don’t do that though, because we have…

    base and parent

    In 1997 Perl 5.004_04 intro­duced the base prag­ma (back when Perl used that kind of ver­sion­ing scheme; in these days of seman­tic ver­sion­ing we’d call it ver­sion 5.4.4). It does the above BEGIN block in a sin­gle line:

    use base 'Local::MyParentClass'; # don't do this unless you're also using fields

    You might see use base in old­er code espe­cial­ly if it’s also using the fields prag­ma. However, Perl devel­op­ers dis­cour­age both as the for­mer silences cer­tain mod­ule load­ing errors while the lat­ter is at odds with the object-​oriented pro­gram­ming prin­ci­ple of encap­su­la­tion.

    So use parent instead, which Perl has includ­ed since ver­sion 5.10.1 in 2009:

    use parent 'Local::MyParentClass';

    A cou­ple of years ago my Newfold Digital col­league David Oswald cre­at­ed a fork of par­ent called parent::versioned that sup­ports spec­i­fy­ing the low­est ver­sion for super­class­es. You call it like this:

    use parent::versioned ['Local::MyParentClass' => 1.23];

    Within an OO system

    There are dozens of object-​oriented pro­gram­ming sys­tems on CPAN that pro­vide syn­tac­tic sug­ar and extra fea­tures to Perl’s min­i­mal but flex­i­ble basics. Two of the more pop­u­lar ones, Moose and Moo, offer an extends key­word that you should use instead of use parent so that your sub­class­es may take advan­tage of their features:

    package Local::MyChildClass;
    use Moo;
    extends 'Local::MyParentClass';

    Moose can also spec­i­fy a required super­class version:

    package Local::MyChildClass;
    use Moose;
    extends 'Local::MyParentClass' => {-version => 1.23};

    Also, use the MooseX::NonMoose mod­ule when extend­ing non-​Moose class­es, again so you get Moose fea­tures even though your meth­ods are com­ing from some­where else:

    package Local::MyMooseClass;
    use Moose;
    use MooseX::NonMoose;
    extends 'Local::MyPlainParentClass';

    The exper­i­men­tal Object::Pad mod­ule spec­i­fies a sin­gle super­class while defin­ing the class name with an option­al ver­sion. Per the author’s sug­gest­ed file lay­out, includ­ing a required min­i­mum ver­sion, it would look like:

    use Object::Pad 0.41;
    package Local::MyChildClass;
    class Local::MyChildClass isa Local::MyParentClass 1.23;

    Object::Pad and Corinna, its inspi­ra­tion, are works in progress so this syn­tax isn’t set in stone. The latter’s design­er Curtis ​“Ovid” Poe blogged ear­li­er this week about con­sid­er­ing a more self-​consistent syntax.

    Multiple inheritance vs. roles

    To quote the Perl doc­u­men­ta­tion, ​“mul­ti­ple inher­i­tance often indi­cates a design prob­lem, but Perl always gives you enough rope to hang your­self with if you ask for it.” All the tech­niques described above except for Object::Pad sup­port mul­ti­ple inher­i­tance by spec­i­fy­ing a list of super­class­es. For example:

    package Local::MyChildClass;
    use parent qw(Local::MyParentClass1 Local::MyParentClass2);

    If you’re using roles instead of or on top of super­class­es (I’ve seen both sit­u­a­tions) and your OO sys­tem doesn’t sup­port them on its own, you can use the Role::Tiny mod­ule, first by describ­ing your role in one pack­age and then con­sum­ing it in another:

    package Local::DoesSomething;
    use Role::Tiny;
    
    ...
    
    1;
    package Local::MyConsumer;
    use Role::Tiny::With;
    with 'Local::DoesSomething';
    
    ...
    
    1;

    Moo::Role uses Role::Tiny under the hood and Moo can com­pose roles from either. The syn­tax for both Moo and Moose is similar:

    package Local::DoesSomething;
    use Moo::Role; # or "use Moose::Role;"
    
    ...
    
    1;
    package Local::MyConsumer;
    use Moo; # or "use Moose;"
    with 'Local::DoesSomething';
    
    ...
    
    1;

    Object::Pad spec­i­fies roles with the role key­word, and both class­es and roles use does to con­sume them:

    use Object::Pad 0.56;
    package Local::DoesSomething;
    role Local::DoesSomething does Local::DoesSomethingElse;
    
    ...
    
    1;
    use Object::Pad 0.56;
    package Local::MyConsumer;
    class Local::MyConsumer does Local::DoesSomething;
    
    ...
    
    1;

    The pre­vi­ous caveat about pos­si­ble changes to this syn­tax applies.

    Like parent, (sort of) like child

    Of course, the whole point of inher­i­tance or role con­sump­tion is so your child or con­sumer class can reuse func­tions and meth­ods. Each of the tech­niques above has its ways of over­rid­ing that code, from the Perl built-​in SUPER pseudo-​class to Moose’s override and super key­words, to Moose’s and Moo’s method mod­i­fiers. (You can use the lat­ter out­side of Moo since it’s pro­vid­ed by Class::Method::Modifiers.)

    I’ve writ­ten about choos­ing between over­rid­ing and mod­i­fy­ing meth­ods before, and when it comes to Moose and Moo code I’m now on the side of using the around method mod­i­fi­er if a method needs to call an inher­it­ed or con­sumed method of the same name. Object::Pad doesn’t have method mod­i­fiers (yet), so classes that use it will have to sat­is­fy them­selves with SUPER in their methods with an :override attribute that will throw an error if a par­ent doesn’t also pro­vide the same method.

    The Parent Wrap

    In the end, your choice of Perl OO sys­tem will deter­mine how (or whether) you han­dle inher­i­tance and may even be a decid­ing fac­tor. Which would you choose? And more impor­tant­ly, have I made my par­ents proud with this post?