Oneliners? In my crontab?


You can neatly put all your logic into a signle class, and then have a nice little factory that looks at @ARGV.

If your class has prod configs as defaults, then your crontab looks like this:

* * * * * perl -MMyApp::Script::CleanupExpiredEntries \
                -E'MyApp::Script::CleanupExpiredEntries->new_from_args->run'

Because you don't have any code in a bin/run-me script, you can neatly write tests for all your functions by either sub-classing your ::Script to replace your database access logic or by by straight-up replacing the method for the duration of your sub-test with

{
    local *MyApp::Script::CleanupExpiredEntries::fetch_from_db = sub  { ...}
    ...
}

The most notable downside is that some day someone might introduce some code that uses Log::Log4perl, and a config config that references $0:

log4perl.appender.LOGFILE.filename=sub {
    my $name = ( map s{ [.]pl $ }{}xr, split m{/}, $0 )[-1];
    "/var/log/$name/$name.log" }

which means you'll get a mail a minute saying:

 Can't sysopen /var/log/-e/-e.log (No such file or directory)
    at /usr/share/perl5/Log/Log4perl/Appender/File.pm line 140.

which might not be the kind of thing you want to see after taking a couple of days off.

I like perls scoping


TL;DR: I think it's chill that perl has both lexical and dynamic scoping.

for my $thing (@things) {
    local $ThingFinder::LogLevel = 9;

    print "I have $thing";
    if (my $thing = $thing->get_more_specific_things()) { 
        print "I have found this thing: $thing";
    }
}

Lexical variables!

Variables who are only declared / visible within their scope.

my $item = Thing->new();               # <- declare a lexical variable
                                       #    and shove an object in there
                                       #
for my $thing ($item->fetch_things) {  # <- $thing only exists within the loop
                                       #
    my $item = $thing>get_item();      # <- this $item masks the $item above
    $item->do_stuff();                 # <- do_stuff can't see either $item
                                       #    (though the inner one will be "self" in the call)
                                       #
}                                      # <- inner $item is DESTROYed here.

Lexicals are the power house of the closure:

sub thing_maker {
    my $thing = shift;                  # <- $thing will live past the end of the
                                        #    call to thing_maker
    return sub {                        # <- return a code-ref
        "I made this thing: $thing"     # <- This reference here keeps $thing alive.
    }
}

my $code = thing_maker("very good thing here");
print $code->()                         # "I made this thing: very good thing here"

Globals or Package variables!

These are the kind of variables you get if you don't use strict 'vars'.

#!perl
$half = $ARGV[1] / 2;            # <- $half isn't declared with my/our/state
                                 #    so it's ours 
print "Half of that is $half\n"  # "Half of that is 5"  (or whatever)

These are kind of pesky because the stuff you assign to them is only DESTROYed when the variable is assigned over or the interpreter shuts down.

You can see them from outside the package

You have a variable in a package:

package ThingFinder;
our $LogLevel = 4;
1

... and you can see the values in it:

use ThingFinder;

sub show_loglevel {
   say "It's $ThingFinder::LogLevel"; # It's 4
}

... sadly anyone can write to it too:

# Set the value for everyone forever:
$ThingFinder::LogLevel = 'just any old garbage'; 

These variables are super helpful for configuration when your package exports functions.

You can override the value for those called inside a block with local

$ThingFinder::LogLevel = 4;             # <- Set the value for everyone forever
ThingFinder->show_loglevel()            # "It's 4"

{
    local $ThingFinder::LogLevel = 9;   # <- Set the value until the end of the scope
    ThingFinder->show_loglevel()        # "It's 9"
}

local works on other stuff, like the symbol table, or just regular old hashes, which is also chill.

That's it.

I just think that's neat.

[(a,4),(b,3),(c,2),(a,1)]


Re: "an interview question":

Write a function that takes 'aaaabbbcca' and returns [('a', 4), ('b', 3), ('c', 2), ('a', 1)]

I'm not sure why an interviewer would hate someone enough to ask a question like this, but this seems like a fair response:

% echo aaaabbbcca | perl -nlE '
    s/((.)\2*)/push @things,sprintf "(%s,%s)", $2,length $1 /ge;
    $"=","; say "[@things]"
'
[(a,4),(b,3),(c,2),(a,1)]

I mean, it'd be easier if perl had tuples, but that's what you get for answering a python question in perl when nobody asked you to

Standard perl-golf disclaimer

Please don't do this kind of thing in a production code base