Tag: perlcritic

  • Get out early with Perl statement modifiers

    Get out early with Perl statement modifiers

    When I first start­ed writ­ing Perl in my ear­ly 20’s, I tend­ed to fol­low a lot of the struc­tured pro­gram­mingcon­ven­tions I had learned in school through Pascal, espe­cial­ly the notion that every func­tion has a sin­gle point of exit. For example:

    sub double_even_number {
        # not using signatures, this is mid-1990's code
        my $number = shift;
    
        if (not $number % 2) {
            $number *= 2;
        }
    
        return $number; 
    }

    This could get pret­ty con­vo­lut­ed, espe­cial­ly if I was doing some­thing like val­i­dat­ing mul­ti­ple argu­ments. And at the time I didn’t yet grok how to han­dle excep­tionswith evaland die, so I’d end up with code like:

    sub print_postal_address {
        # too many arguments, I know
        my ($name, $street1, $street2, $city, $state, $zip) = @_;
        # also this notion of addresses is naive and US-centric
    
        my $error;
    
        if (!$name) {
            $error = 'no name';
        }
        else {
            print "$name\n";
    
            if (!$street1) {
                $error = 'no street';
            }
            else {
                print "$street1\n";
    
                if ($street2) {
                    print "$street2\n";
                }
    
                if (!$city) {
                    $error = 'no city';
                }
                else {
                    print "$city, ";
    
                    if (!$state) {
                        $error = 'no state';
                    }
                    else {
                        print "$state ";
    
                        if (!$zip) {
                            $error = 'no ZIP code';
                        }
                        else {
                            print "$zip\n";
                        }
                    }
                }
            }
        }
    
        return $error;
    }

    What a mess. Want to count all those braces to make sure they’re bal­anced? This is some­times called the arrow anti-​pattern, with the arrowhead(s) being the most nest­ed state­ment. The default ProhibitDeepNests perlcriticpol­i­cyis meant to keep you from doing that.

    The way out (lit­er­al­ly) is guard claus­es: check­ing ear­ly if some­thing is valid and bail­ing out quick­ly if not. The above exam­ple could be written:

    sub print_postal_address {
        my ($name, $street1, $street2, $city, $state, $zip) = @_;
    
        if (!$name) {
            return 'no name';
        }
        if (!$street1) {
            return 'no street1';
        }
        if (!$city) {
            return 'no city';
        }
        if (!$state) {
            return 'no state';
        }
        if (!$zip) {
            return 'no zip';
        }
    
        print join "\n",
          $name,
          $street1,
          $street2 ? $street2 : (),
          "$city, $state $zip\n";
    
        return;
    }

    With Perl’s state­ment mod­i­fiers(some­times called post­fix con­trols) we can do even better:

        ...
    
        return 'no name'    if !$name;
        return 'no street1' if !$street1;
        return 'no city'    if !$city;
        return 'no state'   if !$state;
        return 'no zip'     if !$zip;
    
        ...

    (Why ifinstead of unless? Because the lat­ter can be con­fus­ing with double-​negatives.)

    Guard claus­es aren’t lim­it­ed to the begin­nings of func­tions or even exit­ing func­tions entire­ly. Often you’ll want to skip or even exit ear­ly con­di­tions in a loop, like this exam­ple that process­es files from stan­dard input or the com­mand line:

    while (<>) {
        next if /^SKIP THIS LINE: /;
        last if /^END THINGS HERE$/;
    
        ...
    }

    Of course, if you are val­i­dat­ing func­tion argu­ments, you should con­sid­er using actu­al sub­rou­tine sig­na­turesif you have a Perl new­er than v5.20 (released in 2014), or one of the oth­er type val­i­da­tion solu­tionsif not. Today I would write that postal func­tion like this, using Type::Paramsfor val­i­da­tion and named arguments:

    use feature qw(say state); 
    use Types::Standard 'Str';
    use Type::Params 'compile_named';
    
    sub print_postal_address {
        state $check = compile_named(
            name    => Str,
            street1 => Str,
            street2 => Str, {optional => 1},
            city    => Str,
            state   => Str,
            zip     => Str,
        );
        my $arg = $check->(@_);
    
        say join "\n",
          $arg->{name},
          $arg->{street1},
          $arg->{street2} ? $arg->{street2} : (),
          "$arg->{city}, $arg->{state} $arg->{zip}";
    
        return;
    }
    
    print_postal_address(
        name    => 'J. Random Hacker',
        street1 => '123 Any Street',
        city    => 'Somewhereville',
        state   => 'TX',
        zip     => 12345,
    );

    Note that was this part of a larg­er pro­gram, I’d wrap that print_postal_addresscall in a tryblock and catchexcep­tions such as those thrown by the code ref­er­ence $checkgen­er­at­ed by compile_named. This high­lights one con­cern of guard claus­es and oth­er “return ear­ly” pat­terns: depend­ing on how much has already occurred in your pro­gram, you may have to per­form some resource cleanup either in a catchblock or some­thing like Syntax::Keyword::Try’s finallyblock if you need to tidy up after both suc­cess and failure.

  • 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­dayof 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 featurepragma

    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 sayand fckey­words), or by using a fea­ture bun­dlebased 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 loadedif 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, strictmodeis enabled for free. So just say:

    use v5.34;

    And last­ly, one-​liners can use the -Eswitchinstead of -eto 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 experimentalpragma

    Sometimes new Perl fea­tures need to be dri­ven a cou­ple of releas­es around the blockbefore 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 warningsstate­ment to safe­ly enable them. Or you can sim­ply pass a list to use experimentalof the fea­tures you want, e.g.:

    use experimental qw(isa postderef signatures);

    Ever-​expanding warningscategories

    March 2000 saw the release of Perl 5.6, and with it, the expan­sion of the -wcommand-​line switchto 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­gorieshas 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 CPANif 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 featureguard. 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 featureprag­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 systemcom­mand exe­cut­ed. The lex­i­cal autodieprag­mareplaces them with ver­sions that raise an excep­tionwith an objectthat 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/​catchexception handlingand Feature::Compat::Try

    This year’s Perl v5.34 releaseintro­duced exper­i­men­tal try/​catchsyn­taxfor excep­tion han­dling that should look more famil­iar to users of oth­er lan­guages while han­dling the issuessur­round­ing using block evaland 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 CPANto auto­mat­i­cal­ly select either v5.34’s native try/​catchor 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::AsyncAwaitasyn­chro­nous pro­gram­ming library and the Object::Padtest­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::Keywordmod­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 packagename­space dec­la­ra­tionto 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.

    statevariablesonly 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 stateinstead 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­mentsalso includ­ed the sayfunc­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 valuesfunc­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 eachto 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 localhash (and array) entries

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

    Paired hash slices

    Jumping for­ward to 2014’s Perl v5.20, the new %foo{'bar', 'baz'}syn­taxenables you to slice a sub­set of a hashwith 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 arraysin 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­ducedand v5.24 de-​experimentalizeda more read­able post­fix deref­er­enc­ing syn­taxfor 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­turesvia JSON, so I wel­come any­thing like this to reduce the cog­ni­tive load.

    whenas a statement modifier

    Starting in Perl v5.12, you can use the exper­i­men­tal switch fea­ture​’s whenkey­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­matchoper­a­tions as they were ret­conned as exper­i­ments in 2013’s Perl v5.18and have remained so due to their tricky behav­ior. I wrote about some alter­na­tives using sta­ble syn­taxback in February.

    Simple class inheritance with use parent

    Sometimes in old­er object-​oriented Perl code, you’ll see use baseas 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 @ISAarray. 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­temfrom CPAN, use its sub­class­ing mech­a­nism if it has one. Moose, Moo, and Class::Accessor’s ​“antlers” modeall pro­vide an extendsfunc­tion; Object::Pad pro­vides an :isaattributeon its classkey­word.

    Test for class membership with the isaoperator

    As an alter­na­tive to the isa()methodpro­vid­ed to all Perl objects, Perl v5.32 intro­ducedthe exper­i­men­tal isainfix 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_objectis 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.18and 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 blogand as part of Neil Bowers’ 2014 sur­veyof pri­vate func­tion techniques.

    Subroutine signatures

    I’ve writ­tenand pre­sent­ed exten­sive­lyabout 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 Portersdevel­op­ment mail­ing list has been mak­ing a con­cert­ed effortover 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­turesand uses them exten­sive­ly in examples.

    Indented here-​documents with <<~

    Perl has had shell-​style “here-​document” syn­taxfor 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­sionmatch­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 /xreg­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 /xxto 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 repragma

    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///rand tr///r

    The s///sub­sti­tu­tionand tr///translit­er­a­tionoper­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 /rflag, 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 fcfor 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.6and 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 fcfunc­tionintro­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 whileloopsto 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 openfunc­tionthat 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.22forces opento treat all command-​line argu­ments as file names only. For old­er Perls, the per­lop doc­u­men­ta­tionrec­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–1238in pre­vi­ous ver­sions’ includ­ed scripts. If your code relied on this unsafe behav­ior, the v5.26 release notes include stepson how to adapt.

    HTTP::Tinysimple HTTP/1.1 client included

    To boot­strap access to CPANon the web in the pos­si­ble absence of exter­nal tools like curlor 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::Morelibrary that many are famil­iar with), Test2was includ­ed in the core mod­ule library begin­ning with Perl v5.26. I’ve exper­i­ment­ed recent­lywith using the Test2::SuiteCPAN 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­mingto XML. Use it as a start­ing point or inter­ac­tive­lyselect 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.

  • Vicious (test) mockery of a Perl modulino

    Vicious (test) mockery of a Perl modulino

    Over the past two years, I’ve got­ten back into play­ing Dungeons & Dragons, the famous table­top fan­ta­sy role-​playing game. As a soft­ware devel­op­er and musi­cian, one of my favorite char­ac­ter class­es to play is the bard, a mag­i­cal and inspir­ing per­former or word­smith. The list of basic bardic spells includes Vicious Mockery, enchant­i­ng ver­bal barbs that have the pow­er to psy­chi­cal­ly dam­age and dis­ad­van­tage an oppo­nent even if they don’t under­stand the words. (Can you see why this is so appeal­ing to a coder?)

    Mocking has a role to play in soft­ware test­ing as well, in the form of mock objectsthat sim­u­late parts of a sys­tem that are too brit­tle, too slow, too com­pli­cat­ed, or oth­er­wise too finicky to use in real­i­ty. They enable dis­crete unit test­ingwith­out rely­ing on depen­den­cies exter­nal to the code being test­ed. Mocks are great for data­bas­es, web ser­vices, or oth­er net­work resources where the goal is to test what you wrote, not what’s out in ​“the cloud” somewhere.

    Speaking of web ser­vices and mock­ing, one of my favorites is the long-​running FOAAS(link has lan­guage not safe for work), a sur­pris­ing­ly expan­sive RESTfulinsult ser­vice. There’s a cor­re­spond­ing Perl client API, of course, but what I was miss­ing was a handy Perl script to call that API from the ter­mi­nal com­mand line. So I wrote the fol­low­ing over Thanksgivingbreak, try­ing to keep it sim­ple while also show­ing the basics of mock­ing such an API. It also demon­strates some new­er Perl syn­tax and test­ing tech­niques as well as bri­an d foy​’s mod­uli­nocon­cept from Mastering Perl(sec­ond edi­tion, 2014)that mar­ries script and mod­ule into a self-​contained exe­cutable library.

    #!/usr/bin/env perl
    
    package Local::CallFOAAS;  # this is a modulino
    use Test2::V0;             # enables strict, warnings, utf8
    
    # declare all the new stuff we're using
    use feature qw(say state);
    use experimental qw(isa postderef signatures);
    use Feature::Compat::Try;
    use Syntax::Construct qw(non-destructive-substitution);
    
    use WebService::FOAAS ();
    use Package::Stash;
    use Exception::Class (
        NoMethodException => {
            alias  => 'throw_no_method',
            fields => 'method',
        },
        ServiceException => { alias => 'throw_service' },
    );
    
    my $foaas = Package::Stash->new('WebService::FOAAS');
    
    my $run_as =
        !!$ENV{CPANTEST}       ? 'test'
      : !defined scalar caller ? 'run'
      :                          undef;
    __PACKAGE__->$run_as(@ARGV) if defined $run_as;
    
    sub run ( $class, @args ) {
        try { say $class->call_method(@args) }
        catch ($e) {
            die 'No method ', $e->method, "\n"
              if $e isa NoMethodException;
            die 'Service error: ', $e->error, "\n"
              if $e isa ServiceException;
            die "$e\n";
        }
        return;
    }
    
    # Utilities
    
    sub methods ($) {
        state @methods = sort map s/^foaas_(.+)/$1/r,
          grep /^foaas_/, $foaas->list_all_symbols('CODE');
        return @methods;
    }
    
    sub call_method ( $class, $method = '', @args ) {
        state %methods = map { $_ => 1 } $class->methods();
        throw_no_method( method => $method )
          unless $methods{$method};
        return do {
            try { $foaas->get_symbol("&$method")->(@args) }
            catch ($e) { throw_service( error => $e ) }
        };
    }
    
    # Testing
    
    sub test ( $class, @ ) {
        state $stash = Package::Stash->new($class);
        state @tests = sort grep /^_test_/,
          $stash->list_all_symbols('CODE');
    
        for my $test (@tests) {
            subtest $test => sub {
                try { $class->$test() }
                catch ($e) { diag $e }
            };
        }
        done_testing();
        return;
    }
    
    sub _test_can ($class) {
        state @subs = qw(run call_method methods test);
        can_ok( $class, \@subs, "can do: @subs" );
        return;
    }
    
    sub _test_methods ($class) {
        my $mock = mock 'WebService::FOAAS' => ( track => 1 );
    
        for my $method ( $class->methods() ) {
            $mock->override( $method => 1 );
    
            ok lives { $class->call_method($method) },
              "$method lives";
            ok scalar $mock->sub_tracking->{$method}->@*,
              "$method called";
        }
        return;
    }
    
    sub _test_service_failure ($class) {
        my $mock = mock 'WebService::FOAAS';
    
        for my $method ( $class->methods() ) {
            $mock->override( $method => sub { die 'mocked' } );
    
            my $exception =
              dies { $class->call_method($method) };
            isa_ok $exception, ['ServiceException'],
              "$method throws ServiceException on failure";
            like $exception->error, qr/^mocked/,
              "correct error in $method exception";
        }
        return;
    }
    
    1;

    Let’s walk through the code above.

    Preliminaries

    First, there’s a gener­ic she­bang lineto indi­cate that Unix and Linux sys­tems should use the perlexe­cutable found in the user’s PATH via the envcom­mand. I declare a pack­age name (in the Local:: name­space) so as not to pol­lute the default mainpack­age of oth­er scripts that might want to requirethis as a mod­ule. Then I use the Test2::V0 bun­dlefrom Test2::Suitesince the embed­ded test­ing code uses many of its func­tions. This also has the side effect of enabling the strict, warn­ings, and utf8prag­mas, so there’s no need to explic­it­ly usethem here.

    (Why Test2instead of Test::Moreand its deriv­a­tives and add-​ons? Both are main­tained by the same author, who rec­om­mends the for­mer. I’m see­ing more and more mod­ules using it, so I thought this would be a great oppor­tu­ni­ty to learn.)

    I then declare all the new-​ish Perl fea­tures I’d like to use that need to be explic­it­ly enabled so as not to sac­ri­fice back­ward com­pat­i­bil­i­tywith old­er ver­sions of Perl 5. As of this writ­ing, some of these fea­tures (the isaclass instance oper­a­tor, named argu­ment sub­rou­tine sig­na­tures, and try/​catchexcep­tion han­dlingsyn­tax) are con­sid­ered experimental, with the lat­ter enabled in old­er ver­sions of Perl via the Feature::Compat::Trymod­ule. The friend­lier post­fix deref­er­enc­ingsyn­tax was main­lined in Perl ver­sion 5.24, but ver­sions 5.20 and 5.22 still need it exper­i­men­tal. Finally, I use Syntax::Constructto announce the /rflag for non-​destructive reg­u­lar expres­sion text sub­sti­tu­tions intro­duced in ver­sion 5.14.

    Next, I bring in the afore­men­tioned FOAAS Perl API with­out import­ing any of its func­tions, Package::Stashto make metapro­gram­mingeas­i­er, and a cou­ple of excep­tion class­esso that the com­mand line func­tion and oth­er con­sumers might bet­ter tell what caused a fail­ure. In prepa­ra­tion for the meth­ods below dynam­i­cal­ly dis­cov­er­ing what func­tions are pro­vid­ed by WebService::FOAAS, I gath­er upits sym­bol table (or stash) into the $foaasvariable.

    The next block deter­mines how, if at all, I’m going to run the code as a script. If the CPANTESTenvi­ron­ment vari­able is set, I’ll call the testclass method sub, but if there’s no sub­rou­tine call­ingme I’ll exe­cute the runclass method. Either will receive the com­mand line argu­ments from @ARGV. If nei­ther of these con­di­tions is true, do noth­ing; the rest of the code is method declarations.

    Modulino methods, metaprogramming, and exceptions

    The first of these is the runmethod. It’s a thin wrap­per around the call_methodclass method detailed below, either out­putting its result or dieing with an appro­pri­ate error depend­ing on the class of excep­tion thrown. Although I chose not to write tests for this out­put, future tests might call this method and catch these rethrown excep­tions to match against them. The mes­sages end with a \nnew­line char­ac­ter so dieknows not to append the cur­rent script line number.

    Next is a util­i­ty method called methodsthat uses Package::Stash’s list_all_symbolsto retrieve the names of all named CODEblocks (i.e., subs) from WebService::FOAAS’s sym­bol table. Reading from right to left, these are then fil­tered with grepto only find those begin­ning in foaas_and then trans­formed with mapto remove that pre­fix. The list is then sorted and stored in a statevari­able and returned so it need not be ini­tial­ized again.

    (As an aside, although perlcriticstern­ly warns against it I’ve cho­sen the expres­sion forms of grepand maphere over their block formsfor sim­plic­i­ty’s sake. It’s OK to bend the rulesif you have a good reason.)

    sub call_methodis where the real action takes place. Its para­me­ters are the class that called it, the name of a FOAAS $method(default­ed to the emp­ty string), and an array of option­al argu­ments in @args. I build a hash or asso­cia­tive array from the ear­li­er methodsmethod which I then use to see if the passed method name is one I know about. If not, I throw a NoMethodExceptionusing the throw_no_methodalias func­tion cre­at­ed when I used Exception::Classat the begin­ning. Using a func­tion instead of NoMethodException->throw()means that it’s checked at com­pile time rather than run­time, catch­ing typos.

    I get the sub­rou­tine (denot­ed by a &sig­il) named by $methodfrom the $foaasstash and pass it any fur­ther received argu­ments from @args. If that WebService::FOAAS sub­rou­tine throws an excep­tion it’ll be caught and re-​thrown as a ServiceException; oth­er­wise call_methodreturns the result. It’s up to the caller to deter­mine what, if any­thing, to do with that result or any thrown exceptions.

    Testing the modulino with mocks

    This is where I start using those Test2::Suite toolsI men­tioned at the begin­ning. The testclass method starts by build­ing a fil­tered list of all subs begin­ning with _test_in the cur­rent class, much like methodsdid above with WebService::FOAAS. I then loop through that list of subs, run­ning each as a subtestcon­tain­ing a class method with any excep­tions report­ed as diag­nos­tics.

    The rest of the mod­uli­no is sub­test meth­ods, start­ing with a sim­ple _test_cansan­i­ty check for the pub­lic meth­ods in the class. Following that is _test_methods, which starts by mocking the WebService::FOAAS pack­age and telling Test2::Mock I want to trackany added, over­rid­den, or set subs. I then loop through all the method names returned by the methodsclass method, overrideing each one to return a sim­ple true val­ue. I then test pass­ing those names to call_methodand use the hash ref­er­ence returned by sub_trackingto check that the over­rid­den subwas called. This seems a lot sim­pler than the Test::Builder-based mock­ing libraries I’ve tried like Test::MockModuleand Test::MockObject.

    _test_service_failureacts in much the same way, check­ing that call_methodcor­rect­ly throws ServiceExceptions if the wrapped WebService::FOAAS func­tion dies. The main dif­fer­ence is that the mocked WebService::FOAAS subs are now over­rid­den with a code ref­er­ence (sub { die 'mocked' }), which call_methoduses to pop­u­late the rethrown ServiceException​’s errorfield.

    Wrapping up

    With luck, this arti­cle has giv­en you some ideas, whether it’s in mak­ing scripts (per­haps lega­cy code) testable to improve them, or writ­ing bet­ter unit tests that mock depen­den­cies, or delv­ing a lit­tle into metapro­gram­ming so you can dynam­i­cal­ly sup­port and test new fea­tures of said depen­den­cies. I hope you haven’t come away too offend­ed, at least. Let me know in the com­ments what you think.

  • Better Perl: Four list processing best practices with map, grep, and more

    Better Perl: Four list processing best practices with map, grep, and more

    Six months ago I gave an overview of Perl’s list pro­cess­ing fun­da­men­tals, briefly describ­ing what lists are and then intro­duc­ing the built-​in mapand grepfunc­tions for trans­form­ing and fil­ter­ing them. Later on, I com­piled a list (how appro­pri­ate) of list pro­cess­ing mod­ules avail­able via CPAN, not­ing there’s some con­fus­ing dupli­ca­tion of effort. But you’re a busy devel­op­er, and you just want to know the Right Thing To Do™ when faced with a list pro­cess­ing challenge.

    First, some cred­it is due: these are all restate­ments of sev­er­al Perl::Critic poli­cieswhich in turn cod­i­fy stan­dards described in Damian Conway’s Perl Best Practices(2005). I’ve repeat­ed­ly rec­om­mend­edthe lat­ter as a start­ing point for higher-​quality Perl devel­op­ment. Over the years these prac­tices con­tin­ue to be re-​evaluated (includ­ing by the author him­self) and var­i­ous authors release new pol­i­cy mod­ules, but perlcriticremains a great tool for ensur­ing you (and your team or oth­er con­trib­u­tors) main­tain a con­sis­tent high stan­dard in your code.

    With that said, on to the recommendations!

    Don’t use grepto check if anylist elements match

    It might sound weird to lead off by rec­om­mend­ing notto use grep, but some­times it’s not the right tool for the job. If you’ve got a list and want to deter­mine if a con­di­tion match­es any item in it, you might try:

    if (grep { some_condition($_) } @my_list) {
        ... # don't do this!
    }

    Yes, this works because (in scalar con­text) grepreturns the num­ber of match­es found, but it’s waste­ful, check­ing every ele­ment of @my_list(which could be lengthy) before final­ly pro­vid­ing a result. Use the stan­dard List::Utilmodule’s anyfunc­tion, which imme­di­ate­ly returns (“short-​circuits”) on the first match:

    use List::Util 1.33 qw(any);

    if (any { some_condition($_) } @my_list) {
    ... # do something
    }

    Perl has includ­ed the req­ui­site ver­sion of this mod­ule since ver­sion 5.20in 2014; for ear­li­er releas­es, you’ll need to update from CPAN. List::Util has many oth­er great list-​reduction, key/​value pair, and oth­er relat­ed func­tionsyou can import into your code, so check it out before you attempt to re-​invent any wheels.

    As a side note for web devel­op­ers, the Perl Dancer frame­workalso includes an anykey­wordfor declar­ing mul­ti­ple HTTP routes, so if you’re mix­ing List::Util in there don’t import it. Instead, call it explic­it­ly like this or you’ll get an error about a rede­fined function:

    use List::Util 1.33;

    if (List::Util::any { some_condition($_) } @my_list) {
    ... # do something
    }

    This rec­om­men­da­tion is cod­i­fied in the BuiltinFunctions::ProhibitBooleanGrepPerl::Critic pol­i­cy, comes direct­ly from Perl Best Practices, and is rec­om­mend­edby the Software Engineering Institute Computer Emergency Response Team (SEI CERT)’s Perl Coding Standard.

    Don’t change $_in mapor grep

    I men­tioned this back in March, but it bears repeat­ing: mapand grepare intend­ed as pure func­tions, not muta­torswith side effects. This means that the orig­i­nal list should remain unchanged. Yes, each ele­ment alias­es in turn to the $_spe­cial vari­able, but that’s for speed and can have sur­pris­ing results if changed even if it’s tech­ni­cal­ly allowed. If you need to mod­i­fy an array in-​place use some­thing like:

    for (@my_array) {
    $_ = ...; # make your changes here
    }

    If you want some­thing that lookslike mapbut won’t change the orig­i­nal list (and don’t mind a few CPAN depen­den­cies), con­sid­er List::SomeUtils’ applyfunction:

    use List::SomeUtils qw(apply);
    
    my @doubled_array = apply {$_ *= 2} @old_array;

    Lastly, side effects also include things like manip­u­lat­ing oth­er vari­ables or doing input and out­put. Don’t use mapor grepin a void con­text (i.e., with­out a result­ing array or list); do some­thing with the results or use a foror foreachloop:

    map { print foo($_) } @my_array; # don't do this
    print map { foo($_) } @my_array; # do this instead

    map { push @new_array, foo($_) } @my_array; # don't do this
    @new_array = map { foo($_) } @my_array; # do this instead

    This rec­om­men­da­tion is cod­i­fied by the BuiltinFunctions::ProhibitVoidGrep, BuiltinFunctions::ProhibitVoidMap, and ControlStructures::ProhibitMutatingListFunctionsPerl::Critic poli­cies. The lat­ter comes from Perl Best Practicesand is an SEI CERT Perl Coding Standard rule.

    Use blocks with mapand grep, not expressions

    You can call mapor greplike this (paren­the­ses are option­alaround built-​in functions):

    my @new_array  = map foo($_), @old_array; # don't do this
    my @new_array2 = grep !/^#/, @old_array; # don't do this

    Or like this:

    my @new_array  = map { foo($_) } @old_array;
    my @new_array2 = grep {!/^#/} @old_array;

    Do it the sec­ond way. It’s eas­i­er to read, espe­cial­ly if you’re pass­ing in a lit­er­al list or mul­ti­ple arrays, and the expres­sion forms can con­ceal bugs. This rec­om­men­da­tion is cod­i­fied by the BuiltinFunctions::RequireBlockGrepand BuiltinFunctions::RequireBlockMapPerl::Critic poli­cies and comes from Perl Best Practices.

    Refactor multi-​statement maps, greps, and other list functions

    map, grep, and friends should fol­low the Unix phi­los­o­phy of ​“Do One Thing and Do It Well.”Your read­abil­i­ty and main­tain­abil­i­ty drop with every state­ment you place inside one of their blocks. Consider junior devel­op­ers and future main­tain­ers (this includes you!) and refac­tor any­thing with more than one state­ment into a sep­a­rate sub­rou­tine or at least a forloop. This goes for list pro­cess­ing func­tions (like the afore­men­tioned any) import­ed from oth­er mod­ules, too.

    This rec­om­men­da­tion is cod­i­fied by the Perl Best Practices-inspired BuiltinFunctions::ProhibitComplexMappingsand BuiltinFunctions::RequireSimpleSortBlockPerl::Critic poli­cies, although those only cov­er mapand sortfunc­tions, respectively.


    Do you have any oth­er sug­ges­tions for list pro­cess­ing best prac­tices? Feel free to leave them in the com­ments or bet­ter yet, con­sid­er cre­at­ing new Perl::Critic poli­ciesfor them or con­tact­ing the Perl::Critic teamto devel­op them for your organization.

  • Everyone’s a (Perl) critic, and you can be too!

    Everyone’s a (Perl) critic, and you can be too!

    The perlcritictool is often your first defense against ​“awk­ward, hard to read, error-​prone, or uncon­ven­tion­al con­structs in your code,” per its descrip­tion. It’s part of a class of pro­grams his­tor­i­cal­ly known as lin­ters, so-​called because like a clothes dry­er machine’s lint trap, they ​“detect small errors with big effects.” (Another such lin­ter is perltidy, which I’ve ref­er­encedin the past.)

    You can use perlcritic at the com­mand line, inte­grat­ed with your edi­tor, as a gitpre-​commit hook, or (my pref­er­ence) as part of your author tests. It’s dri­ven by poli­cies, indi­vid­ual mod­ules that check your code against a par­tic­u­lar rec­om­men­da­tion, many of them from Damian Conway’s Perl Best Practices(2005). Those poli­cies, in turn, are enabled by PPI, a library that trans­forms Perl code into doc­u­ments that can be pro­gram­mat­i­cal­ly exam­ined and manip­u­lat­ed much like the Document Object Model (DOM)is used to pro­gram­mat­i­cal­ly access web pages.

    perlcriticenables the fol­low­ing poli­cies by default unless you cus­tomize its con­fig­u­ra­tionor install more. These are just the ​“gen­tle” (sever­i­tylev­el 5) poli­cies, so con­sid­er them the bare min­i­mum in detect­ing bad prac­tices. The full set of includ­ed poli­ciesgoes much deep­er, ratch­et­ing up the sever­i­ty to ​“stern,” ​“harsh,” ​“cru­el,” and ​“bru­tal.” They’re fur­ther orga­nized accord­ing to themesso that you might selec­tive­ly review your code against issues like secu­ri­ty, main­te­nance, com­plex­i­ty, and bug prevention.

    My favorite above is prob­a­bly ProhibitEvilModules. Aside from the col­or­ful name, a devel­op­ment team can use it to steer peo­ple towards an organization’s favored solu­tions rather than ​“dep­re­cat­ed, bug­gy, unsup­port­ed, or inse­cure” ones. By default, it pro­hibits Class::ISA, Pod::Plainer, Shell, and Switch, but you should curate and con­fig­ure a list with­in your team.

    Speaking of work­ing with­in a team, although perlcriticis meant to be a vital tool to ensure good prac­tices, it’s no sub­sti­tute for man­u­al peer code review. Those reviews can lead to the cre­ation or adop­tion of new auto­mat­ed poli­cies to save time and set­tle argu­ments, but such work should be done col­lab­o­ra­tive­ly after achiev­ing some kind of con­sen­sus. This is true whether you’re a team of employ­ees work­ing on pro­pri­etary soft­ware or a group of vol­un­teers devel­op­ing open source.

    Of course, rea­son­able peo­ple can and do dis­agree over any of the includ­ed poli­cies, but as a rea­son­able per­son, you should havegoodrea­sons to dis­agree before you either con­fig­ure perlcriticappro­pri­ate­ly or selec­tive­ly and know­ing­ly bend the ruleswhere required. Other CPAN authors have even pro­vid­ed their own addi­tions to perlcritic, so it’s worth search­ing CPAN under ​“Perl::Critic::Policy::”for more exam­ples. In par­tic­u­lar, these community-​inspired poli­ciesgroup a num­ber of rec­om­men­da­tions from Perl devel­op­ers on Internet Relay Chat (IRC).

    Personally, although I adhere to my employer’s stan­dard­ized con­fig­u­ra­tion when test­ing and review­ing code, I like to run perlcriticon the ​“bru­tal” set­ting before com­mit­ting my own. What do you pre­fer? Let me know in the com­ments below.