<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Nicholas Hubbard</title>
    <description>The latest articles on Forem by Nicholas Hubbard (@nicholasbhubbard).</description>
    <link>https://forem.com/nicholasbhubbard</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F902978%2F4ec4221f-89a9-4058-8c16-c198fc1ca07e.jpeg</url>
      <title>Forem: Nicholas Hubbard</title>
      <link>https://forem.com/nicholasbhubbard</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/nicholasbhubbard"/>
    <language>en</language>
    <item>
      <title>How I used a named pipe to save memory and prevent crashes (in Perl)</title>
      <dc:creator>Nicholas Hubbard</dc:creator>
      <pubDate>Wed, 15 Jan 2025 16:13:45 +0000</pubDate>
      <link>https://forem.com/nicholasbhubbard/how-i-used-a-named-pipe-to-save-memory-and-prevent-crashes-in-perl-41g9</link>
      <guid>https://forem.com/nicholasbhubbard/how-i-used-a-named-pipe-to-save-memory-and-prevent-crashes-in-perl-41g9</guid>
      <description>&lt;p&gt;I recently ran into an interesting bug in my Slackware package manager &lt;a href="https://github.com/NicholasBHubbard/sbozyp" rel="noopener noreferrer"&gt;sbozyp&lt;/a&gt;. In this post I will detail the bug and my solution.&lt;/p&gt;

&lt;p&gt;Disclaimer: The code snippets in this post do not deal with every edge case and are only meant to convey the ideas relevant to this blog post. All important edge cases are dealt with in the actual code for sbozyp.&lt;/p&gt;

&lt;p&gt;Sbozyp is a package manager for &lt;a href="https://www.slackbuilds.org/" rel="noopener noreferrer"&gt;SlackBuilds.org&lt;/a&gt;, a repository of build scripts for Slackware packages. There is a very important subroutine in sbozyp named &lt;code&gt;build_slackware_pkg()&lt;/code&gt; that (basically) takes the name of a package, builds it into a Slackware package, and returns the path to the built package. To build the package we must execute the packages SlackBuild script. A SlackBuild script always has the general form: { basic setup -&amp;gt; perform build procedure -&amp;gt; conglomerate built parts into a Slackware package }. The last step is always performed by a Slackware-specific tool called &lt;a href="http://www.slackware.com/config/packages.php" rel="noopener noreferrer"&gt;makepkg&lt;/a&gt;. Unfortunately there is no way (that I know of) to be able to determine the name of the Slackware package before executing the SlackBuild script. For this reason sbozyp must inspect the &lt;a href="https://en.wikipedia.org/wiki/Standard_streams" rel="noopener noreferrer"&gt;stdout&lt;/a&gt; of the SlackBuild script to look for a line that makepkg always outputs that looks like &lt;code&gt;Slackware package $PATH created&lt;/code&gt;. It is also important of course that the user can see the output of the SlackBuild script as it may contain vital information. This means that both my program and the user needs to examine the output of the SlackBuild script. (See &lt;a href="https://www.slackwiki.com/SlackBuild_Scripts" rel="noopener noreferrer"&gt;here&lt;/a&gt; for more information on SlackBuild scripts)&lt;/p&gt;

&lt;p&gt;With the problem description out of the way we can now focus on the solution.&lt;/p&gt;

&lt;p&gt;My original solution was an obvious one but had an interesting bug. I simply would use Perl's &lt;a href="https://perldoc.perl.org/functions/system" rel="noopener noreferrer"&gt;system&lt;/a&gt; command to execute the SlackBuild script with a shell, where I would pipe stdout to &lt;a href="https://en.wikipedia.org/wiki/Tee_(command)" rel="noopener noreferrer"&gt;tee&lt;/a&gt;, writing the stdout to a temporary file. After the SlackBuild would execute I would read the temporary file looking for the &lt;code&gt;Slackware package $PATH created&lt;/code&gt; line. This solved the problem of allowing both the user and sbozyp to read the stdout of the SlackBuild script. For 99% of builds this worked fine ... but then there was &lt;a href="https://www.qemu.org/" rel="noopener noreferrer"&gt;qemu&lt;/a&gt;. Qemu is a massive project that requires a huge compilation. My system uses a small 4GB tmpfs mounted at /tmp, and the temporary file that was being teed to ended up getting so large from all the qemu compilation output that tee (and thus sbozyp) crashed for "device out of space".&lt;/p&gt;

&lt;p&gt;Here is a basic (not actually realistic to sbozyp) outline of that code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;build_slackware_pkg&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$pkg_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;@_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$slackbuild_script&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;find_slackbuild_script&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$pkg_name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$tmp_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;make_temp_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;DIR&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/tmp&lt;/span&gt;&lt;span class="p"&gt;');&lt;/span&gt;
    &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;system&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="s2"&gt;set -o pipefail; &lt;/span&gt;&lt;span class="si"&gt;$slackbuild_script&lt;/span&gt;&lt;span class="s2"&gt; | tee &lt;/span&gt;&lt;span class="si"&gt;$tmp_file&lt;/span&gt;&lt;span class="p"&gt;")&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;die&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;open&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="nv"&gt;$tmp_file&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;die&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$slackware_pkg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$stdout_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;$tmp_file&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$slackware_pkg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$stdout_line&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/^Slackware package (.+) created$/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$slackware_pkg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To solve the problem I create a &lt;a href="https://en.wikipedia.org/wiki/Named_pipe" rel="noopener noreferrer"&gt;named pipe&lt;/a&gt;, fork, and use the child process to execute the SlackBuild script, teeing stdout to the named pipe. From the parent I read the named pipe looking for the magic &lt;code&gt;Slackware package $PATH created&lt;/code&gt; line. Here is a (also not realistic to sbozyp) outline of this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;POSIX&lt;/span&gt; &lt;span class="sx"&gt;qw(mkfifo WNOHANG)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;build_slackware_pkg&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$pkg_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;@_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$slackbuild_script&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;find_slackbuild_script&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$pkg_name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$tmp_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;make_temp_dir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;DIR&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/tmp&lt;/span&gt;&lt;span class="p"&gt;');&lt;/span&gt;
    &lt;span class="nv"&gt;mkfifo&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="si"&gt;$tmp_dir&lt;/span&gt;&lt;span class="s2"&gt;/fifo&lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt; &lt;span class="mo"&gt;0700&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;fork&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$pid&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;# child&lt;/span&gt;
        &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;system&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="s2"&gt;set -o pipefail; &lt;/span&gt;&lt;span class="si"&gt;$slackbuild_script&lt;/span&gt;&lt;span class="s2"&gt; | tee &lt;/span&gt;&lt;span class="si"&gt;$fifo&lt;/span&gt;&lt;span class="p"&gt;")&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;die&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;# parent&lt;/span&gt;
        &lt;span class="nb"&gt;open&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$fifo_r_fh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="nv"&gt;$fifo&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;die&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$slackware_pkg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;waitpid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;WNOHANG&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$stdout_line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;$fifo_r_fh&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$slackware_pkg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$stdout_line&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nv"&gt;$stdout_line&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/^Slackware package (.+) created$/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nb"&gt;die&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vg"&gt;$?&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# $? has exit status of child&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$slackware_pkg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This implementation saves disk space as the data is being teed to a named pipe instead of a regular file in /tmp. As data is written to the pipe it is immediately being read, throwing away all the data that sbozyp doesn't need.&lt;/p&gt;

&lt;p&gt;Problem solved :)&lt;/p&gt;

&lt;p&gt;(Thanks to thrig on the #perl Libera IRC channel for helping lead me to this solution)&lt;/p&gt;

&lt;h1&gt;
  
  
  EDIT
&lt;/h1&gt;

&lt;p&gt;I got some great feedback from u/gorkish on reddit with a much simpler way to solve the problem by running the SlackBuild script with &lt;a href="https://perldoc.perl.org/functions/open#Opening-a-filehandle-into-a-command" rel="noopener noreferrer"&gt;open&lt;/a&gt; instead of system. Here is the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;build_slackware_pkg&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$pkg_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;@_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$slackbuild_script&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;find_slackbuild_script&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$pkg_name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$cmd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-|&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="nv"&gt;$slackbuild_script&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;die&lt;/span&gt; &lt;span class="vg"&gt;$!&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$slackware_pkg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;$cmd&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$slackware_pkg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$line&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/^Slackware package (.+) created$/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="nv"&gt;$line&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nb"&gt;close&lt;/span&gt; &lt;span class="nv"&gt;$cmd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;die&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vg"&gt;$?&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$slackware_pkg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>perl</category>
      <category>linux</category>
    </item>
    <item>
      <title>4 More Unrelated Perl Tidbits</title>
      <dc:creator>Nicholas Hubbard</dc:creator>
      <pubDate>Tue, 11 Apr 2023 14:39:40 +0000</pubDate>
      <link>https://forem.com/nicholasbhubbard/4-more-unrelated-perl-tidbits-ijm</link>
      <guid>https://forem.com/nicholasbhubbard/4-more-unrelated-perl-tidbits-ijm</guid>
      <description>&lt;p&gt;Last year I wrote an article titled &lt;a href="https://dev.to/nicholasbhubbard/4-unrelated-perl-tidbits-2766"&gt;4 Unrelated Perl Tidbits&lt;/a&gt;, where I talked about some random Perl facts I learned about from reading &lt;a href="https://www.oreilly.com/library/view/programming-perl-4th/9781449321451/"&gt;Programming Perl&lt;/a&gt;. In this article I will talk about 4 more random and interesting Perl features I have learned about since.&lt;/p&gt;

&lt;h3&gt;
  
  
  Built-Ins Can Be Overridden with Lexical Subroutines
&lt;/h3&gt;

&lt;p&gt;Perl version 5.18 introduced &lt;a href="https://perldoc.perl.org/perlsub#Lexical-Subroutines"&gt;lexical subroutines&lt;/a&gt;, which are often sometimes referred to as "my subs". An interesting characteristic of lexical subs is that unlike regular subroutines, they can override built-ins.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;v5&lt;/span&gt;&lt;span class="mf"&gt;.18&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;die&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;printing is banned&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, World!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;

&lt;span class="cp"&gt;__END__

$ perl tmp.pl
printing is banned
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If anybody has seen a use of this feature then please comment below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Recursive Anonymous Subroutines With __SUB__
&lt;/h3&gt;

&lt;p&gt;Perl version 5.16 introduced the &lt;a href="https://perldoc.perl.org/functions/__SUB__"&gt;__SUB__&lt;/a&gt; special token that holds a reference to the current subroutine. You can use &lt;code&gt;__SUB__&lt;/code&gt; to make a recursive call in an anonymous subroutine.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;v5&lt;/span&gt;&lt;span class="mf"&gt;.16&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;higher_order_subroutine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;         &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nv"&gt;__SUB__&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$n&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Goto Searches For Labels In The Dynamic Scope
&lt;/h3&gt;

&lt;p&gt;The following example shows that &lt;a href="https://perldoc.perl.org/functions/goto"&gt;goto&lt;/a&gt; searches for its label argument from within the current &lt;a href="https://en.wikipedia.org/wiki/Scope_(computer_science)#Dynamic_scope"&gt;dynamic scope&lt;/a&gt;. Note that this program just goes on forever printing &lt;code&gt;hello from after LABEL&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;bar&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;goto&lt;/span&gt; &lt;span class="nv"&gt;LABEL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;baz&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;LABEL:&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello from after LABEL&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
    &lt;span class="nv"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;baz&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="cp"&gt;__END__

$ perl tmp.pl
hello from after LABEL
hello from after LABEL
hello from after LABEL
...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is another feature that you should leave a comment about if you have seen a usage of it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Regex Modifier For Only Portions Of The Regex
&lt;/h3&gt;

&lt;p&gt;You can use the &lt;code&gt;(?M:)&lt;/code&gt; pattern in a regex to turn on the modifier specified by &lt;code&gt;M&lt;/code&gt;, only inside the parentheses. For example, the following two regexs are the same:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="sr"&gt;/foo/i&lt;/span&gt;
&lt;span class="sr"&gt;/(?i:foo)/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also turn a modifier off with &lt;code&gt;(?-M:)&lt;/code&gt;, which is shown in this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;('&lt;/span&gt;&lt;span class="s1"&gt;FOO&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/(?-i:foo)/i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;matches&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;does not match&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cp"&gt;__END__

$ perl tmp.pl
does not match
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This feature is useful if you want to turn a modifier on/off for only a portion of the regex:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;('&lt;/span&gt;&lt;span class="s1"&gt;fooBAR&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/(?-i:foo)bar/i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;matches&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;does not match&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cp"&gt;__END__

$ perl tmp.pl
matches
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>perl</category>
    </item>
    <item>
      <title>An Interesting Perl Pattern That Doesn't Work</title>
      <dc:creator>Nicholas Hubbard</dc:creator>
      <pubDate>Thu, 23 Mar 2023 18:24:00 +0000</pubDate>
      <link>https://forem.com/nicholasbhubbard/an-interesting-perl-pattern-that-doesnt-work-41mf</link>
      <guid>https://forem.com/nicholasbhubbard/an-interesting-perl-pattern-that-doesnt-work-41mf</guid>
      <description>&lt;p&gt;I recently came up with a pattern that is supposed to use a closure to protect a configuration hash from being mutated by its callers. Unfortunately this pattern has a terrible flaw.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;%config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;%config&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;%config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;%config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;create_config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;%config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;config()&lt;/code&gt; subroutine is a lexical closure over the &lt;code&gt;%config&lt;/code&gt; hash. No other code in a program would be able to access the &lt;code&gt;%config&lt;/code&gt; variable, as everything is defined in its own &lt;a href="https://perldoc.perl.org/perlsyn#Basic-BLOCKs"&gt;block&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As an aside, this pattern could just as easily be written with a &lt;a href="https://perldoc.perl.org/functions/state"&gt;state variable&lt;/a&gt;, but I find it harder to explain the pattern when done this way.&lt;/p&gt;

&lt;h1&gt;
  
  
  Blocks
&lt;/h1&gt;

&lt;p&gt;To understand this pattern we first have to understand how blocks work. Here is a code example that shows how blocks work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$var&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;from inside the block where &lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;var is defined &lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;var = &lt;/span&gt;&lt;span class="si"&gt;$var&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;

    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;from the most inner block &lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;var = &lt;/span&gt;&lt;span class="si"&gt;$var&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;from outside the block &lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;var = &lt;/span&gt;&lt;span class="si"&gt;$var&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;

&lt;span class="cp"&gt;__END__

$ perl tmp.pl
from inside the block where $var is defined $var = foo
from the most inner block $var = foo
from outside the block $var = 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code shows that a block introduces a lexical scope. Variables defined in a lexical scope are only available in its defining scope, and scopes nested inside their defining scope. The program output shows that the &lt;code&gt;$var&lt;/code&gt; variable is available in the scope it is defined in, and from the scope nested in its defining scope. However, outside of its defining scope, &lt;code&gt;$var&lt;/code&gt; is not defined.&lt;/p&gt;

&lt;p&gt;If we turn on &lt;code&gt;strict&lt;/code&gt; we get a fatal compilation error for trying to use &lt;code&gt;$var&lt;/code&gt; from outside its defining scope:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Global symbol "$var" requires explicit package name (did you forget to declare "my $var"?) at tmp.pl line 14.
Execution of tmp.pl aborted due to compilation errors.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may be wondering if the &lt;code&gt;config()&lt;/code&gt; subroutine is accessible from outside the block it was defined in. The answer is that it is indeed available, because subroutine declarations are always global to the current package. This code example shows this fact:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;strict&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;foo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello from foo!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="cp"&gt;__END__

$ perl tmp.pl
hello from foo!
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Closures
&lt;/h1&gt;

&lt;p&gt;Now that we understand blocks we can understand closures. In Perl, a closure is a subroutine that has access to the lexical environment that it was defined in. Here is the classic example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;strict&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        

    &lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;increment&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;decrement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;increment() -&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="nv"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;increment() -&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="nv"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;decrement() -&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="nv"&gt;decrement&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;increment() -&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="nv"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;increment() -&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="nv"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;decrement() -&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="nv"&gt;decrement&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;

&lt;span class="cp"&gt;__END__

$ perl tmp.pl
increment() -&amp;gt; 1
increment() -&amp;gt; 2
decrement() -&amp;gt; 1
increment() -&amp;gt; 2
increment() -&amp;gt; 3
decrement() -&amp;gt; 2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;increment()&lt;/code&gt; and &lt;code&gt;decrement()&lt;/code&gt; subroutines are both able to access the &lt;code&gt;$n&lt;/code&gt; variable, though no other subroutines in a larger program would be able to, due to the outer block. For this reason the &lt;code&gt;increment()&lt;/code&gt; and &lt;code&gt;decrement()&lt;/code&gt; subroutines are closures over &lt;code&gt;$n&lt;/code&gt;;&lt;/p&gt;

&lt;h1&gt;
  
  
  The Problem
&lt;/h1&gt;

&lt;p&gt;We should now have all the knowledge needed to understand the pattern that this article is about.&lt;/p&gt;

&lt;p&gt;The idea of the pattern is that if the &lt;code&gt;%config&lt;/code&gt; variable has already been set then we just return it, and otherwise we set its value before returning it. This means that &lt;code&gt;%config&lt;/code&gt; will only be set the first time that we call &lt;code&gt;config()&lt;/code&gt;, and on all subsequent calls it will simply be returned. Therefore &lt;code&gt;config()&lt;/code&gt; can be thought of as a function constant ... right?&lt;/p&gt;

&lt;p&gt;Here is a code example where our pattern works as expected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;strict&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;%config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;%config&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;%config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;%config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;create_config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;%config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;create_config&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hello from create_config()&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;%config1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nv"&gt;$config1&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1004&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;%config2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;%config2's foo key = &lt;/span&gt;&lt;span class="si"&gt;$config2&lt;/span&gt;&lt;span class="s2"&gt;{foo}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;

&lt;span class="cp"&gt;__END__

$ perl tmp.pl
hello from create_config()
%config2's foo key = 12
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This output displays a couple of important points. First, we know that the &lt;code&gt;create_config()&lt;/code&gt; subroutine was only invoked a single time, even though we invoked &lt;code&gt;config()&lt;/code&gt; twice. We know this because the "hello from create_config()" message is only printed a single time. The other important thing to note is that because we got the output "%config2's foo key = 12", we know that our modification of &lt;code&gt;%config1&lt;/code&gt;'s &lt;code&gt;foo&lt;/code&gt; key (which we set to 1004), did not effect the &lt;code&gt;%config&lt;/code&gt; variable that our &lt;code&gt;config()&lt;/code&gt; subroutine closes over. If it had, then &lt;code&gt;%config2&lt;/code&gt;'s &lt;code&gt;foo&lt;/code&gt; key would associate to &lt;code&gt;1004&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So what is the problem? Well ... everything falls apart when the &lt;code&gt;%config&lt;/code&gt; variable is set to a multi-dimensional data structure. The following code encapsulates the fundamental problem with our pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;strict&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;%config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;%config&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;%config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;%config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;create_config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;%config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;create_config&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;foo&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;%config1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nv"&gt;$config1&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1004&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;%config2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;config&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;%config2's foo key = [&lt;/span&gt;&lt;span class="p"&gt;",&lt;/span&gt; &lt;span class="nb"&gt;join&lt;/span&gt;&lt;span class="p"&gt;('&lt;/span&gt;&lt;span class="s1"&gt;, &lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="nv"&gt;@&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$config2&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;}}),&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;]&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;

&lt;span class="cp"&gt;__END__

$ perl tmp.pl
%config2's foo key = [1004, 2, 3]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Uh oh! We were able to mutate the &lt;code&gt;%config&lt;/code&gt; variable that &lt;code&gt;config()&lt;/code&gt; closes over, which means that &lt;code&gt;config()&lt;/code&gt; is not actually a constant function. Now we come to the fundamental problem of our pattern. Because in Perl multi-dimensional data structures are made up of references, and perl does not perform &lt;a href="https://en.wikipedia.org/wiki/Object_copying#Deep_copy"&gt;deep-copying&lt;/a&gt; by default, we are able to mutate the underlying references of multi-dimensional data structures.&lt;/p&gt;

&lt;p&gt;Here is a code example that shows that Perl does not perform deep-copying:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;strict&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@array1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@array1 contents:&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$elem&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@array1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="si"&gt;$elem&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# copy @array1 to @array2&lt;/span&gt;
&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@array2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;@array1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@array2 contents:&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$elem&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@array2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="si"&gt;$elem&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cp"&gt;__END__

$ perl tmp.pl
@array1 contents:
    ARRAY(0x13875e8)
    ARRAY(0x13d1ef8)
    ARRAY(0x13d1fe8)
@array2 contents:
    ARRAY(0x13875e8)
    ARRAY(0x13d1ef8)
    ARRAY(0x13d1fe8)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this programs output we can see that &lt;code&gt;@array1&lt;/code&gt; and &lt;code&gt;@array2&lt;/code&gt; contain the exact same references, which means that Perl does not perform deep-copying. If Perl did perform deep-copying, then when we copied &lt;code&gt;@array1&lt;/code&gt; into &lt;code&gt;@array2&lt;/code&gt;, Perl would have made (recursive) copies of all the references in &lt;code&gt;@array1&lt;/code&gt; into new refererences. Perl's lack of deep-copying is the fundamental flaw of our pattern, as it means that we can modify &lt;code&gt;%config&lt;/code&gt;'s references from its copies that are returned by &lt;code&gt;config()&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Solutions
&lt;/h1&gt;

&lt;p&gt;There are many ways we can solve this problem. First, we could use &lt;a href="https://perldoc.perl.org/Hash::Util#lock_hash_recurse"&gt;lock_hash_recurse&lt;/a&gt; from the core &lt;a href="https://perldoc.perl.org/Hash::Util"&gt;Hash::Util&lt;/a&gt; module to lock &lt;code&gt;%config&lt;/code&gt;. After locking &lt;code&gt;%config&lt;/code&gt;, we would get an error if we tried to mutate any of its values.&lt;/p&gt;

&lt;p&gt;We could also use &lt;a href="https://metacpan.org/pod/Const::Fast"&gt;Const::Fast&lt;/a&gt; from CPAN to make &lt;code&gt;%config&lt;/code&gt; an actual read-only hash. Similarly to locking the hash, we would get an error if we tried to mutate &lt;code&gt;%config&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, we could use &lt;a href="https://metacpan.org/pod/Clone"&gt;Clone&lt;/a&gt; from CPAN to return a deep-copy of &lt;code&gt;%config&lt;/code&gt; from the &lt;code&gt;config()&lt;/code&gt; subroutine. Unlike the other solutions, our code could freely modify copies of &lt;code&gt;%config&lt;/code&gt; without getting any errors, but these modifications would not affect the actual &lt;code&gt;%config&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>perl</category>
    </item>
    <item>
      <title>Use Dist::Zilla to Create a Perl Distribution</title>
      <dc:creator>Nicholas Hubbard</dc:creator>
      <pubDate>Sun, 23 Oct 2022 14:29:26 +0000</pubDate>
      <link>https://forem.com/nicholasbhubbard/use-distzilla-to-create-a-perl-distribution-2c5i</link>
      <guid>https://forem.com/nicholasbhubbard/use-distzilla-to-create-a-perl-distribution-2c5i</guid>
      <description>&lt;p&gt;&lt;a href="https://dzil.org/"&gt;Dist::Zilla&lt;/a&gt; (dzil) is a program for creating Perl distributions. While the documentation for dzil is complete, it is not geared towards a beginner that has never created a Perl distribution before. This article provides a brief introduction to Dist::Zilla geared towards users that know little about Perl distributions in general.&lt;/p&gt;

&lt;p&gt;&lt;a id="orgafbbf0c"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  What is a Perl distribution?
&lt;/h1&gt;

&lt;p&gt;A Perl distribution is an archive of files that includes a Perl module. There are no official rules on what non-module files must be included in a distribution, but they often include (among other things) test scripts, a Makefile.PL, documentation, and the license. These distributions are commonly uploaded to &lt;a href="https://metacpan.org/"&gt;CPAN&lt;/a&gt;, which is a place for Perl programmers to upload their Perl distributions for the purpose of sharing their code.&lt;/p&gt;

&lt;p&gt;&lt;a id="orgcabe74a"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Why Dist::Zilla?
&lt;/h1&gt;

&lt;p&gt;You may think that bundling together a Perl module with some other files is simple, but there are many things that need to be accounted for, and are prone to human error. There are also many possibilities for what somebody may want to include in a distribution, and how they want to include it. Dist::Zilla exists to be a one-stop solution to every possible problem involved in creating a Perl distribution.&lt;/p&gt;

&lt;p&gt;&lt;a id="org29a19e9"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Using Dist::Zilla
&lt;/h1&gt;

&lt;p&gt;When you install Dist::Zilla, you will be provided with an executable named &lt;code&gt;dzil&lt;/code&gt;. The most important command that &lt;code&gt;dzil&lt;/code&gt; provides is &lt;code&gt;build&lt;/code&gt;, which - when run in the projects root directory - outputs a distribution tarball. Other commands such as &lt;code&gt;test&lt;/code&gt; and &lt;code&gt;release&lt;/code&gt; are also provided, but when getting started with Dist::Zilla you will only need the &lt;code&gt;build&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;&lt;a id="orge0178c3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  The "dist.ini" File
&lt;/h1&gt;

&lt;p&gt;Dist::Zilla is configured on a per-project basis through a file named &lt;code&gt;dist.ini&lt;/code&gt;, which should be located at the root of the project's directory tree.&lt;/p&gt;

&lt;p&gt;The beginning of a &lt;code&gt;dist.ini&lt;/code&gt; file specifies required settings that every distribution should have. These settings include &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;version&lt;/code&gt;, &lt;code&gt;abstract&lt;/code&gt;, &lt;code&gt;copyright_holder&lt;/code&gt;, and &lt;code&gt;license&lt;/code&gt;. (There is also &lt;code&gt;author&lt;/code&gt;, which isn't required but you probably want to add it as well.)&lt;/p&gt;

&lt;p&gt;Here is an example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name = App-Foo
version = 1.0
author = Jane Doe
copyright_holder = Jane Doe
license = Perl_5
abstract = the best software ever
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After you specify these required settings, you can then configure your distribution by specifying what plugins you wish to use. Plugins are the mechanism that Dist::Zilla uses for providing features to your Perl distribution. If you have a &lt;code&gt;dist.ini&lt;/code&gt; that doesn't specify any plugins, Dist::Zilla will produce an empty distribution with no files.&lt;/p&gt;

&lt;p&gt;Let's look at example of the plugins that a simple distribution might use, then go over what a few of the plugins actually do:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[MetaResources]
homepage       = https://github.com/JaneDoe/App-Foo
bugtracker.web = https://github.com/JaneDoe/App-Foo/issues
repository.url = https://github.com/JaneDoe/App-Foo.git

[GatherDir]
[PruneCruft]
[ManifestSkip]
[MetaYAML]
[License]
[ExecDir]
[MakeMaker]
[Manifest]
[AutoPrereqs]
[TestRelease]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::MetaResources"&gt;MetaResources&lt;/a&gt; plugin adds resource entries to the distribution's metadata. &lt;a href="https://metacpan.org/"&gt;MetaCPAN&lt;/a&gt; can use this information to provide useful links to the distribution's page.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::GatherDir"&gt;GatherDir&lt;/a&gt; and &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::PruneCruft"&gt;PruneCruft&lt;/a&gt; plugins tell Dist::Zilla that you want to include all the files in your project's directory into the distribution, excluding the ones you certainly don't want. The files you certainly don't want include build artifacts introduced by recent invocations of Dist::Zilla. The combination of these two plugins is used in almost every Dist::Zilla project.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::MakeMaker"&gt;MakeMaker&lt;/a&gt; plugin will tell Dist::Zilla to produce an &lt;a href="https://metacpan.org/pod/ExtUtils::MakeMaker"&gt;ExtUtils::MakeMaker&lt;/a&gt;-powered Makefile.PL. Dist::Zilla will deal with everything required to create a proper Makefile.PL, so you do not need to know anything about ExtUtils::MakeMaker. Unless you are doing something special, you almost certainly want to use this plugin.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::UploadToCPAN"&gt;UploadToCPAN&lt;/a&gt; plugin will allow you to use the &lt;code&gt;dzil release&lt;/code&gt; command to upload your distribution to CPAN.&lt;/p&gt;

&lt;p&gt;It is important to note that each plugin takes effect in the order the plugins are specified in your dist.ini.&lt;/p&gt;

&lt;p&gt;There are &lt;strong&gt;many&lt;/strong&gt; plugins available for Dist::Zilla - over 1,200 thus far - so you will probably find one that can do just about anything you could possibly need for creating a distribution. &lt;a href="https://metacpan.org/search?size=20&amp;amp;q=Dist%3A%3AZilla%3A%3APlugin"&gt;Here&lt;/a&gt; is a link for a metacpan query for "Dist::Zilla::Plugin", that can be used to explore the Dist::Zilla plugin ecosystem.&lt;/p&gt;

&lt;p&gt;Here are links to the documentation for the plugins in the example &lt;code&gt;dist.ini&lt;/code&gt; that I did not explain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::ManifestSkip"&gt;ManifestSkip&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::MetaYAML"&gt;MetaYAML&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::License"&gt;License&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::ExecDir"&gt;ExecDir&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::Manifest"&gt;Manifest&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::AutoPrereqs"&gt;AutoPrereqs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::TestRelease"&gt;TestRelease&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a id="org23f3c96"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Synopsis
&lt;/h1&gt;

&lt;p&gt;Dist::Zilla can seem daunting at first, but it is actually quite straightforward and easy to use once you figure it out. The only difficult thing is figuring out what plugins you want to use.&lt;/p&gt;

</description>
      <category>perl</category>
    </item>
    <item>
      <title>How I use Yabsm to Manage my Btrfs Snapshots</title>
      <dc:creator>Nicholas Hubbard</dc:creator>
      <pubDate>Thu, 06 Oct 2022 23:02:57 +0000</pubDate>
      <link>https://forem.com/nicholasbhubbard/how-i-use-yabsm-to-manage-my-btrfs-snapshots-19a3</link>
      <guid>https://forem.com/nicholasbhubbard/how-i-use-yabsm-to-manage-my-btrfs-snapshots-19a3</guid>
      <description>&lt;p&gt;YABSM IS DEPRECATED. CONSIDER USING ALTERNATIVES SUCH AS BTRBK OR SNAPPER.&lt;/p&gt;

&lt;p&gt;I am the author of &lt;a href="https://github.com/NicholasBHubbard/yabsm" rel="noopener noreferrer"&gt;Yabsm (yet another btrfs snapshot manager)&lt;/a&gt;, and I will explain how I use it to manage my Btrfs snapshots.&lt;/p&gt;

&lt;p&gt;This article is meant to supplement the official documentation, and assumes a basic understanding of Linux's &lt;a href="https://en.wikipedia.org/wiki/Btrfs" rel="noopener noreferrer"&gt;Btrfs&lt;/a&gt; filesystem.&lt;/p&gt;

&lt;p&gt;Please note that Yabsm can be configured to suit many different use cases other than the one described here.&lt;/p&gt;

&lt;p&gt;&lt;a id="orgfe91a36"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Snapshots vs Backups
&lt;/h1&gt;

&lt;p&gt;Before we go on, let's clear up the difference between a snapshot and a backup.&lt;/p&gt;

&lt;p&gt;A snapshot is a read-only nested &lt;a href="https://btrfs.readthedocs.io/en/latest/Subvolumes.html" rel="noopener noreferrer"&gt;subvolume&lt;/a&gt; created with a command such as &lt;code&gt;btrfs subvolume snapshot -r $SUBVOLUME $DEST&lt;/code&gt;. &lt;strong&gt;SNAPSHOTS ARE NOT RELIABLE BACKUPS!&lt;/strong&gt; If a subvolume is corrupted then all snapshots of that subvolume may also be corrupted.&lt;/p&gt;

&lt;p&gt;A backup is an &lt;a href="https://btrfs.wiki.kernel.org/index.php/Incremental_Backup" rel="noopener noreferrer"&gt;incremental backup&lt;/a&gt; sent to some location via Btrfs's &lt;a href="https://btrfs.readthedocs.io/en/latest/Send-receive.html" rel="noopener noreferrer"&gt;send/receive&lt;/a&gt; commands. These backups will not be corrupted if the subvolume being backed up is corrupted.&lt;/p&gt;

&lt;p&gt;&lt;a id="org449a345"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  My Btrfs Filesystem
&lt;/h1&gt;

&lt;p&gt;I like to have just one top-level Btrfs subvolume mounted at &lt;code&gt;/&lt;/code&gt;. This allows me to snapshot my entire system (excluding nested subvolumes) by running &lt;code&gt;btrfs subvolume snapshot -r / $DEST&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a id="org028bea9"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  My Yabsm Configuration
&lt;/h1&gt;

&lt;p&gt;My configuration is based on the philosophy that because snapshots are both valuable and cheap, it makes sense to take a lot of snapshots.&lt;/p&gt;

&lt;p&gt;Here is my &lt;code&gt;/etc/yabsm.conf&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yabsm_dir=/.snapshots/yabsm

subvol root_subvol {
    mountpoint=/
}

snap root {
    subvol=root_subvol

    timeframes=5minute,hourly,daily
    5minute_keep=36
    hourly_keep=72
    daily_times=15:00,23:59
    daily_keep=62
}

ssh_backup slackmac {
    subvol=root_subvol
    ssh_dest=slackmac
    dir=/.snapshots/yabsm-slacktop

    timeframes=daily
    daily_times=23:59
    daily_keep=365
}

local_backup easystore {
    subvol=root_subvol
    dir=/mnt/easystore/backups/yabsm-slacktop

    timeframes=daily
    daily_times=23:59
    daily_keep=365
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a id="orga0d51da"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Yabsm Dir
&lt;/h3&gt;

&lt;p&gt;I use the traditional &lt;code&gt;/.snapshots/yabsm&lt;/code&gt; directory as my &lt;code&gt;yabsm_dir&lt;/code&gt;, which is the location that my snapshots will reside. Yabsm will also use this directory for storing data necessary for performing SSH and local backups.&lt;/p&gt;

&lt;p&gt;&lt;a id="org40ab1c1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Subvol
&lt;/h3&gt;

&lt;p&gt;As I mentioned earlier, I only have one top-level Btrfs subvolume, so I only need to define one &lt;code&gt;subvol&lt;/code&gt; in my Yabsm config, which I name &lt;code&gt;root_subvol&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a id="org77c9f84"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Snap
&lt;/h3&gt;

&lt;p&gt;I define one &lt;a href="https://metacpan.org/dist/App-Yabsm/view/bin/yabsm#Snaps" rel="noopener noreferrer"&gt;snap&lt;/a&gt; named &lt;em&gt;root&lt;/em&gt; that tells Yabsm I want to take snapshots of &lt;code&gt;root_subvol&lt;/code&gt; in the &lt;em&gt;5minute&lt;/em&gt;, &lt;em&gt;hourly&lt;/em&gt;, and &lt;em&gt;daily&lt;/em&gt; &lt;a href="https://metacpan.org/dist/App-Yabsm/view/bin/yabsm#Timeframes" rel="noopener noreferrer"&gt;timeframe categories&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the &lt;em&gt;5minute&lt;/em&gt; timeframe category I keep 36 snapshots. This lets me go to any state of my machine in the last 3 hours in 5 minute increments. I use the &lt;em&gt;5minute&lt;/em&gt; category because it gives me a valuable safety net. How many times have you broken your code that was working 20 minutes ago? If you take &lt;em&gt;5minute&lt;/em&gt; snapshots then you can easily go back to the state of that code 20 minutes ago.&lt;/p&gt;

&lt;p&gt;In the &lt;em&gt;hourly&lt;/em&gt; timeframe I keep 72 snapshots, which allows me to go back 3 days in hourly increments. How many times have you broken code that was working 2 days ago? If you take &lt;em&gt;hourly&lt;/em&gt; snapshots (and keep enough of them), you can go back through the state of your machine from 2 days ago, in 1 hour increments.&lt;/p&gt;

&lt;p&gt;In the &lt;em&gt;daily&lt;/em&gt; timeframe category I keep 62 snapshots taken at midnight (23:59) and midafternoon (15:00). This gives me two snapshots per day in the last month.&lt;/p&gt;

&lt;p&gt;Please note that there is also a &lt;code&gt;weekly&lt;/code&gt; and &lt;code&gt;monthly&lt;/code&gt; timeframe category.&lt;/p&gt;

&lt;p&gt;&lt;a id="org41e4eb4"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  SSH Backup
&lt;/h3&gt;

&lt;p&gt;I define one &lt;a href="https://metacpan.org/dist/App-Yabsm/view/bin/yabsm#SSH-Backups" rel="noopener noreferrer"&gt;ssh_backup&lt;/a&gt; named &lt;em&gt;slackmac&lt;/em&gt; that backs up my system to my old MacBook running Slackware.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;ssh_dest&lt;/em&gt; value is set to &lt;em&gt;slackmac&lt;/em&gt;, which is a host defined in the &lt;em&gt;yabsm&lt;/em&gt; user's &lt;code&gt;$HOME/.ssh/config&lt;/code&gt; file. (Yabsm runs as a daemon process, using the special username &lt;code&gt;yabsm&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;dir&lt;/em&gt; value is set to the directory on &lt;em&gt;slackmac&lt;/em&gt; where the backups will be located.&lt;/p&gt;

&lt;p&gt;I perform this &lt;em&gt;ssh_backup&lt;/em&gt; only in the &lt;em&gt;daily&lt;/em&gt; timeframe category, backing up every night at midnight. I keep 365 of these backups so I can go back an entire year.&lt;/p&gt;

&lt;p&gt;&lt;a id="orgc5909cb"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Local Backup
&lt;/h3&gt;

&lt;p&gt;I define one &lt;a href="https://metacpan.org/dist/App-Yabsm/view/bin/yabsm#Local-Backups" rel="noopener noreferrer"&gt;local_backup&lt;/a&gt; named &lt;code&gt;easystore&lt;/code&gt; that backs up my system to my EasyStore external hard drive.&lt;/p&gt;

&lt;p&gt;The hard drive is mounted at &lt;code&gt;/mnt/easystore&lt;/code&gt;, and I keep my backups in the &lt;code&gt;/backups/yabsm-slacktop&lt;/code&gt; directory on the hard drive.&lt;/p&gt;

&lt;p&gt;Just like my &lt;code&gt;slackmac&lt;/code&gt; &lt;em&gt;ssh_backup&lt;/em&gt;, I perform my &lt;em&gt;local_backup&lt;/em&gt; only in the &lt;code&gt;daily&lt;/code&gt; timeframe category, every night at midnight.&lt;/p&gt;

&lt;p&gt;&lt;a id="orgb9f813e"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Finding Snapshots
&lt;/h1&gt;

&lt;p&gt;Yabsm provides the &lt;a href="https://metacpan.org/dist/App-Yabsm/view/bin/yabsm#Finding-Snapshots" rel="noopener noreferrer"&gt;find&lt;/a&gt; command that I use to jump around to different snapshots and backups. The &lt;em&gt;find&lt;/em&gt; command takes two arguments, the first is the name of any of your &lt;em&gt;snaps&lt;/em&gt;, &lt;em&gt;ssh_backups&lt;/em&gt;, or &lt;em&gt;local_backups&lt;/em&gt;. The second argument is a query. The different kinds of queries are all documented in the link above.&lt;/p&gt;

&lt;p&gt;Instead of repeating the documentation, let's break down a practical example of the &lt;em&gt;find&lt;/em&gt; command's usage.&lt;/p&gt;

&lt;p&gt;How many times have you broken code that worked 30 minutes ago? Because I take &lt;em&gt;5minute&lt;/em&gt; snapshots I can easily get back the state of the code 30 minutes ago.&lt;/p&gt;

&lt;p&gt;An example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ diff "$(yabsm find root back-30-mins)/$HOME/projects/foo/script.sh" $HOME/projects/foo/foo.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This command will show the &lt;code&gt;diff&lt;/code&gt; output of the &lt;code&gt;$HOME/projects/foo/foo.sh&lt;/code&gt; file with this same file that was snapshotted 30 minutes ago. We can use this output to help figure out what we messed up.&lt;/p&gt;

&lt;p&gt;The command &lt;code&gt;yabsm find root back-30-mins&lt;/code&gt; will output the path to a snapshot for the &lt;em&gt;snap&lt;/em&gt; named &lt;em&gt;root&lt;/em&gt; that was taken 30 minutes ago. In the example we use our shell's &lt;a href="https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html" rel="noopener noreferrer"&gt;parameter expansion&lt;/a&gt; feature to create a string that appends the path to &lt;code&gt;foo.sh&lt;/code&gt; to the output of the &lt;code&gt;yabsm find&lt;/code&gt; command. This is a powerful pattern!&lt;/p&gt;

&lt;p&gt;The find command can do more than find a snapshot taken N units ago, it can also:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Find the newest or oldest snapshot/backup.&lt;/li&gt;
&lt;li&gt;  Find a snapshot/backup taken on a specific day and time.&lt;/li&gt;
&lt;li&gt;  Find all the snapshots/backups taken before or after a certain time.&lt;/li&gt;
&lt;li&gt;  Find all the snapshots/backups taken between two times.&lt;/li&gt;
&lt;li&gt;  Find all snapshots/backups.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The output of &lt;code&gt;yabsm find --help&lt;/code&gt; shows some examples:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;usage: yabsm &amp;lt;find|f&amp;gt; [--help] [&amp;lt;SNAP|SSH_BACKUP|LOCAL_BACKUP&amp;gt; &amp;lt;QUERY&amp;gt;]

see the section "Finding Snapshots" in 'man yabsm' for a detailed explanation on
how to find snapshots and backups.

examples:
    yabsm find home_snap back-10-hours
    yabsm f root_ssh_backup newest
    yabsm f home_local_backup oldest
    yabsm f home_snap 'between b-10-mins 15:45'
    yabsm f root_snap 'after back-2-days'
    yabsm f root_local_backup 'before b-14-d'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a id="orgdac6334"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Synopsis
&lt;/h1&gt;

&lt;p&gt;Yabsm is a powerful tool for managing your Btrfs snapshots. If you are interested in using Yabsm, then I recommend you consult the official documentation.&lt;/p&gt;

</description>
      <category>btrfs</category>
    </item>
    <item>
      <title>Create a Lock File in Perl with File::Temp</title>
      <dc:creator>Nicholas Hubbard</dc:creator>
      <pubDate>Thu, 29 Sep 2022 20:17:37 +0000</pubDate>
      <link>https://forem.com/nicholasbhubbard/create-a-lock-file-in-perl-with-filetemp-h68</link>
      <guid>https://forem.com/nicholasbhubbard/create-a-lock-file-in-perl-with-filetemp-h68</guid>
      <description>&lt;p&gt;A &lt;a href="https://en.wikipedia.org/wiki/Lock_(computer_science)"&gt;lock&lt;/a&gt; can serve many purposes in regards to avoiding &lt;a href="https://en.wikipedia.org/wiki/Race_condition"&gt;race conditions&lt;/a&gt;. In this article we will explore how to implement a lock using Perl's built-in &lt;a href="https://perldoc.perl.org/File::Temp"&gt;File::Temp&lt;/a&gt; module.&lt;/p&gt;

&lt;p&gt;&lt;a id="org43fe6db"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  The Problem
&lt;/h1&gt;

&lt;p&gt;We will write a program called "duckduckperl" that has the following usage:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;usage: duckduckperl [retrieve] [print]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;retrieve&lt;/code&gt; command retrieves the HTML of a DuckDuckGo search for the word "perl", and writes it to &lt;code&gt;$HOME/duckduckperl.html&lt;/code&gt;, overwriting this file if it already exists.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;print&lt;/code&gt; command prints the content of &lt;code&gt;$HOME/duckduckperl.html&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is a version of the program that has a potential race condition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env perl&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;strict&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;warnings&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$OUTPUT_FILE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$ENV&lt;/span&gt;&lt;span class="s2"&gt;{HOME}/duckduckperl.html&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;

&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$USAGE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;usage: duckduckperl [retrieve] [print]&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@ARGV&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;die&lt;/span&gt; &lt;span class="nv"&gt;$USAGE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$ARG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$ARGV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$ARG&lt;/span&gt; &lt;span class="ow"&gt;eq&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;retrieve&lt;/span&gt;&lt;span class="p"&gt;')&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;retrieve_html&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;elsif&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$ARG&lt;/span&gt; &lt;span class="ow"&gt;eq&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;print&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt;   &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;print_html&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;                       &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;die&lt;/span&gt; &lt;span class="nv"&gt;$USAGE&lt;/span&gt;      &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;retrieve_html&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="sb"&gt;curl --silent https://duckduckgo.com/?q=perl&lt;/span&gt;&lt;span class="p"&gt;`;&lt;/span&gt;

    &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;$?&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;die&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;duckduckperl: curl command exited with status $?&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nb"&gt;open&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="nv"&gt;$OUTPUT_FILE&lt;/span&gt;
      &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;die&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;duckduckperl: error: cannot open &lt;/span&gt;&lt;span class="si"&gt;$OUTPUT_FILE&lt;/span&gt;&lt;span class="s2"&gt;: $!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;

    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt; &lt;span class="nv"&gt;$html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nb"&gt;close&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;print_html&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt; &lt;span class="nv"&gt;$OUTPUT_FILE&lt;/span&gt;
      &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;die&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;duckduckperl: error: cannot find file &lt;/span&gt;&lt;span class="si"&gt;$OUTPUT_FILE&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;

    &lt;span class="nb"&gt;open&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="nv"&gt;$OUTPUT_FILE&lt;/span&gt;
      &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;die&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;duckduckperl: error: cannot open &lt;/span&gt;&lt;span class="si"&gt;$OUTPUT_FILE&lt;/span&gt;&lt;span class="s2"&gt;: $!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;

    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;$fh&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nb"&gt;close&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="nv"&gt;$html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only part of this code that is important to understand is the &lt;code&gt;&amp;amp;retrieve_html&lt;/code&gt; subroutine, because this is where the potential race condition comes from. This subroutine &lt;code&gt;curl&lt;/code&gt;'s the URL that represents a DuckDuckGo search of the word "perl", and dies if it fails. If the &lt;code&gt;curl&lt;/code&gt; command succeeds it writes the outputted HTML &lt;code&gt;$HOME/duckduckperl.html&lt;/code&gt;, overwriting any data already in the file.&lt;/p&gt;

&lt;p&gt;Imagine if we call &lt;code&gt;duckduckperl retrieve&lt;/code&gt; twice, and for whatever (network related) reason the second instance finishes first. When we go to call &lt;code&gt;duckduckperl print&lt;/code&gt;, we will get the output of the first call instead of the second call, which probably is not expected.&lt;/p&gt;

&lt;p&gt;&lt;a id="orgbeeef69"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  The Solution
&lt;/h1&gt;

&lt;p&gt;To avoid this problem we will write &lt;code&gt;&amp;amp;retrieve_html&lt;/code&gt; to first check for the existence of a lock file, and if it exists waits for it to be deleted before continuing. If the lock file doesn't exist then it creates it before retrieving and writing the HTML, and deletes it afterwards. This guarantees that multiple&lt;br&gt;
instances of &lt;code&gt;duckduckperl retrieve&lt;/code&gt; terminate in the order they were called.&lt;/p&gt;

&lt;p&gt;Perl's built-in &lt;a href="https://perldoc.perl.org/File::Temp"&gt;File::Temp&lt;/a&gt; module provides useful features for creating a lock file. The most important feature that we will use is automatic deletion of the lock file when the File::Temp object is destroyed (garbage collected). This feature is available if we use &lt;a href="https://perldoc.perl.org/File::Temp#OBJECT-ORIENTED-INTERFACE"&gt;File::Temp's OO interface&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here is the updated version of &lt;code&gt;&amp;amp;retrieve_html&lt;/code&gt; that uses a lock file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;File::&lt;/span&gt;&lt;span class="nv"&gt;Temp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;retrieve_html&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$seconds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="sr"&gt;/DUCKDUCKPERLLOCK$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;('&lt;/span&gt;&lt;span class="s1"&gt;/tmp/*&lt;/span&gt;&lt;span class="p"&gt;'))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$seconds&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nb"&gt;die&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;duckduckperl: error: aborting after waiting 2 minutes for lock file to be deleted&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nb"&gt;sleep&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$seconds&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$lock_fh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;File::&lt;/span&gt;&lt;span class="nv"&gt;Temp&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;DIR&lt;/span&gt;      &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/tmp&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;
        &lt;span class="s"&gt;TEMPLATE&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;XXXX&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;
        &lt;span class="s"&gt;SUFFIX&lt;/span&gt;   &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.DUCKDUCKPERLLOCK&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;
        &lt;span class="s"&gt;UNLINK&lt;/span&gt;   &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nb"&gt;open&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="nv"&gt;$OUTPUT_FILE&lt;/span&gt;
      &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;die&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;duckduckperl: error: cannot open &lt;/span&gt;&lt;span class="si"&gt;$OUTPUT_FILE&lt;/span&gt;&lt;span class="s2"&gt;: $!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;

    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$html&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="sb"&gt;curl --silent https://duckduckgo.com/?q=perl&lt;/span&gt;&lt;span class="p"&gt;`;&lt;/span&gt;

    &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;$?&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;die&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;duckduckperl: curl command exited with status $?&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt; &lt;span class="nv"&gt;$html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nb"&gt;close&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first part of the subroutine checks for the lock file, which is a file in the &lt;code&gt;/tmp&lt;/code&gt; directory matching the regex &lt;code&gt;/DUCKDUCKPERLLOCK$/&lt;/code&gt;. If this file exists, we check every second for the next 2 minutes to see if it is deleted, before giving up and exiting the program. If the lock file does not exist, then we create it using &lt;a href="https://perldoc.perl.org/File::Temp#new"&gt;File::Temp::new&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We configure our File::Temp object with 4 options. The &lt;code&gt;DIR&lt;/code&gt; option specifies the directory that we want to place the file in. The &lt;code&gt;TEMPLATE&lt;/code&gt; option specifies the template to be used for naming the file. The &lt;code&gt;X&lt;/code&gt;'s represents random characters that File::Temp will fill in to guarantee the file it creates has a unique name. The &lt;code&gt;SUFFIX&lt;/code&gt; option gives the file name a suffix, which we set to &lt;code&gt;.DUCKDUCKPERLLOCK&lt;/code&gt;. We use this suffix to identify the lock file when checking for its existence. Finally, the &lt;code&gt;UNLINK&lt;/code&gt; option specifies that we want to delete the file when the File::Temp object is destroyed (garbage collected). Conveniently, even if the &lt;code&gt;curl&lt;/code&gt; command fails and we make the program die, the File::Temp object is still destroyed, and the lock file is deleted.&lt;/p&gt;

&lt;p&gt;Using this version of &lt;code&gt;&amp;amp;retrieve_html&lt;/code&gt;, we can rest assured knowing that multiple instances of &lt;code&gt;duckduckperl retrieve&lt;/code&gt; will terminate in the order they were invoked.&lt;/p&gt;

</description>
      <category>perl</category>
    </item>
    <item>
      <title>Named Subroutine Arguments in Perl</title>
      <dc:creator>Nicholas Hubbard</dc:creator>
      <pubDate>Thu, 22 Sep 2022 01:13:39 +0000</pubDate>
      <link>https://forem.com/nicholasbhubbard/named-subroutine-arguments-in-perl-2a3h</link>
      <guid>https://forem.com/nicholasbhubbard/named-subroutine-arguments-in-perl-2a3h</guid>
      <description>&lt;p&gt;Naming your subroutine arguments has benefits around increasing the readability of your code. Lets look at an example of code that can benefit from named arguments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;safe_open&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;shift&lt;/span&gt; &lt;span class="nv"&gt;@_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;shift&lt;/span&gt; &lt;span class="nv"&gt;@_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$die_on_failure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;shift&lt;/span&gt; &lt;span class="nv"&gt;@_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nv"&gt;$success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nv"&gt;$die_on_failure&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;die&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error: failed to open '&lt;/span&gt;&lt;span class="si"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;': $!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the following examples we can see that the third argument allows us to control if we should kill the program if the file cannot be opened:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;safe_open&lt;/span&gt;&lt;span class="p"&gt;('&lt;/span&gt;&lt;span class="s1"&gt;/file/that/doesnt/exist&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, World!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;

&lt;span class="c1"&gt;# OUTPUT:&lt;/span&gt;
&lt;span class="c1"&gt;# error: failed to open '/file/that/doesnt/exist': No such file or directory&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;safe_open&lt;/span&gt;&lt;span class="p"&gt;('&lt;/span&gt;&lt;span class="s1"&gt;/file/that/doesnt/exist&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, World!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;

&lt;span class="c1"&gt;# OUTPUT:&lt;/span&gt;
&lt;span class="c1"&gt;# print() on closed filehandle $fh at ./scratch.pl line 22.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Imagine if somebody who has never worked with this code before comes across these calls to &lt;code&gt;&amp;amp;safe_open&lt;/code&gt;. It will be impossible for them to know what the third argument stands for unless they go and look at the actual code of the subroutine.&lt;/p&gt;

&lt;p&gt;To make it easier for people to understand the meaning of the arguments, we can name them!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;safe_open&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;%args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;FILE&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;'',&lt;/span&gt;
        &lt;span class="s"&gt;MODE&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;'',&lt;/span&gt;
        &lt;span class="s"&gt;DIE_ON_FAILURE&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;FILE&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;die&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error: missing FILE arg in call to &amp;amp;safe_open&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
    &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;MODE&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;die&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error: missing MODE arg in call to &amp;amp;safe_open&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;

    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;MODE&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;FILE&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nv"&gt;$success&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;DIE_ON_FAILURE&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;die&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error: failed to open '&lt;/span&gt;&lt;span class="si"&gt;$args&lt;/span&gt;&lt;span class="s2"&gt;{FILE}': $!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lets look at some examples of calling this subroutine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;safe_open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;FILE&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/file/that/doesnt/exist&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="s"&gt;MODE&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="s"&gt;DIE_ON_FAILURE&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, World!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;

&lt;span class="c1"&gt;# OUTPUT:&lt;/span&gt;
&lt;span class="c1"&gt;# error: failed to open '/file/that/doesnt/exist': No such file or directory&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;safe_open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;FILE&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/file/that/doesnt/exist&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="s"&gt;MODE&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;');&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, World!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;

&lt;span class="c1"&gt;# OUTPUT:&lt;/span&gt;
&lt;span class="c1"&gt;# error: failed to open '/file/that/doesnt/exist': No such file or directory&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;safe_open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;DIE_ON_FAILURE&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;FILE&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/file/that/doesnt/exist&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="s"&gt;MODE&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;');&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello, World!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;

&lt;span class="c1"&gt;# OUTPUT:&lt;/span&gt;
&lt;span class="c1"&gt;# print() on closed filehandle $fh at ./scratch.pl line 25.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are a few things to note from these examples.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The arguments must be explicitly named using &lt;code&gt;ARG =&amp;gt; value&lt;/code&gt; syntax.&lt;/li&gt;
&lt;li&gt;  The argument order does not matter.&lt;/li&gt;
&lt;li&gt;  The &lt;code&gt;DIE_ON_FAILURE&lt;/code&gt; argument is optional and defaults to true.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our &lt;code&gt;&amp;amp;safe_open&lt;/code&gt; subroutine has these features because of the strategy used for constructing the &lt;code&gt;%args&lt;/code&gt; hash.&lt;/p&gt;

&lt;p&gt;The reason the argument order doesn't matter is because hashes are unordered and in the end we are constructing a hash out of the argument list.&lt;/p&gt;

&lt;p&gt;An array can be used to construct a hash as long as it has an even number of elements. We leverage this to use the &lt;code&gt;@_&lt;/code&gt; array to construct the &lt;code&gt;%args&lt;/code&gt; hash. Here is an example of this behavior:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;('&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;%hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;@array&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;hash{'foo'} = &lt;/span&gt;&lt;span class="si"&gt;$hash&lt;/span&gt;&lt;span class="s2"&gt;{'foo'}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;hash{'bar'} = &lt;/span&gt;&lt;span class="si"&gt;$hash&lt;/span&gt;&lt;span class="s2"&gt;{'bar'}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;

&lt;span class="c1"&gt;# OUTPUT:&lt;/span&gt;
&lt;span class="c1"&gt;# $hash{'foo'} = 12&lt;/span&gt;
&lt;span class="c1"&gt;# $hash{'bar'} = 13&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are able to give default argument values because of the fact that, if a hash definition defines the same key multiple times, then the last definition is used. If the user leaves off an argument, then it is not redefined and stays set to the default. Consider this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;%hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;FOO&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;FOO&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;13&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;hash{'FOO'} = &lt;/span&gt;&lt;span class="si"&gt;$hash&lt;/span&gt;&lt;span class="s2"&gt;{'FOO'}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;

&lt;span class="c1"&gt;# OUTPUT:&lt;/span&gt;
&lt;span class="c1"&gt;# $hash{'FOO'} = 13&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a id="orgae697ad"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Synopsis
&lt;/h1&gt;

&lt;p&gt;We can use the subroutines argument array (&lt;code&gt;@_&lt;/code&gt;) to construct a hash, which can give us significant benefits in terms of code readability. By constructing a hash from the argument array, all calls to the subroutine must explicitly name their arguments the argument order becomes irrelevant, and arguments can be given default values.&lt;/p&gt;

</description>
      <category>perl</category>
    </item>
    <item>
      <title>Create a Daemon in Perl with Schedule::Cron</title>
      <dc:creator>Nicholas Hubbard</dc:creator>
      <pubDate>Thu, 08 Sep 2022 01:20:36 +0000</pubDate>
      <link>https://forem.com/nicholasbhubbard/create-a-daemon-in-perl-with-schedulecron-4pb6</link>
      <guid>https://forem.com/nicholasbhubbard/create-a-daemon-in-perl-with-schedulecron-4pb6</guid>
      <description>&lt;p&gt;A &lt;a href="https://en.wikipedia.org/wiki/Daemon_(computing)"&gt;daemon&lt;/a&gt; is a program that runs in the background for an indefinite period of time.&lt;/p&gt;

&lt;p&gt;An important daemon on Unix-like operating systems is the &lt;a href="https://en.wikipedia.org/wiki/Cron"&gt;cron scheduler&lt;/a&gt; that can be configured to perform tasks periodically. Though there are many different types of daemons, we will explore how to create a cron daemon.&lt;/p&gt;

&lt;p&gt;My favorite CPAN module for creating a daemon is &lt;a href="https://metacpan.org/pod/Schedule::Cron"&gt;Schedule::Cron&lt;/a&gt;, which allows us to create a daemon that dispatches Perl subroutines at preconfigured intervals. The reason I like &lt;a href="https://metacpan.org/pod/Schedule::Cron"&gt;Schedule::Cron&lt;/a&gt; is that it is easy to learn, easy to understand, and it works.&lt;/p&gt;

&lt;p&gt;This article is not a complete overview of everything that &lt;a href="https://metacpan.org/pod/Schedule::Cron"&gt;Schedule::Cron&lt;/a&gt; can do, so be sure to read the official documentation afterwards.&lt;/p&gt;

&lt;p&gt;&lt;a id="orga259ded"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  A Simple Daemon
&lt;/h1&gt;

&lt;p&gt;Let's write a simple (and useless) daemon that logs the current time every 5 minutes, and rotates the log file every hour, keeping at most 4 old logs. The current logfile will be named &lt;code&gt;$HOME/times.txt&lt;/code&gt;, and the old log files will be named &lt;code&gt;$HOME/times.txt.{1,2,3,4}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First we need a function to write the time to the current log file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;append_time&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$logfile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$ENV&lt;/span&gt;&lt;span class="s2"&gt;{HOME}/times.txt&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
    &lt;span class="nb"&gt;open&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="nv"&gt;$logfile&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;die&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cannot open file '&lt;/span&gt;&lt;span class="si"&gt;$logfile&lt;/span&gt;&lt;span class="s2"&gt;': $!&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;localtime&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$time&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
    &lt;span class="nb"&gt;close&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we need a function to rotate the old log files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;File::&lt;/span&gt;&lt;span class="nv"&gt;Copy&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;move&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;rotate_time_log&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$logfile&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$ENV&lt;/span&gt;&lt;span class="s2"&gt;{HOME}/times.txt&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;@old_logfiles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="sr"&gt;/^$ENV{HOME}\/times\.txt\.\d+$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;glob&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$ENV&lt;/span&gt;&lt;span class="s2"&gt;{HOME}/*&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
    &lt;span class="c1"&gt;# We don't need to rotate unless we have more than 4 old logfiles&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;@old_logfiles&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nb"&gt;unlink&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$logfile&lt;/span&gt;&lt;span class="s2"&gt;.4&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;move&lt;/span&gt; &lt;span class="nv"&gt;$old_logfiles&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;$logfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nv"&gt;move&lt;/span&gt; &lt;span class="nv"&gt;$logfile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$logfile&lt;/span&gt;&lt;span class="s2"&gt;.1&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Understanding how these functions work is not important for learning about &lt;a href="https://metacpan.org/pod/Schedule::Cron"&gt;Schedule::Cron&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now that we have our time logging functions, let's initialize our daemon object. To initialize the daemon object we will use the &lt;a href="https://metacpan.org/pod/Schedule::Cron#%24cron-=-new-Schedule::Cron(%24dispatcher,%5Bextra-args%5D)"&gt;Schedule::Cron::new&lt;/a&gt; function.&lt;/p&gt;

&lt;p&gt;The first argument to &lt;a href="https://metacpan.org/pod/Schedule::Cron#%24cron-=-new-Schedule::Cron(%24dispatcher,%5Bextra-args%5D)"&gt;Schedule::Cron::new&lt;/a&gt; must be a reference to a subroutine that will be used as a default if we add a cron entry without specifying the function we want to run. This is only useful if there is only one function we want our daemon to run. We won't be using this feature, so we just set it to a function that kills the program.&lt;/p&gt;

&lt;p&gt;There are many options we can pass to &lt;a href="https://metacpan.org/pod/Schedule::Cron#%24cron-=-new-Schedule::Cron(%24dispatcher,%5Bextra-args%5D)"&gt;Schedule::Cron::new&lt;/a&gt;, the only one we will use is &lt;a href="https://metacpan.org/pod/Schedule::Cron#processprefix-=%3E-%3Cname%3E"&gt;processprefix&lt;/a&gt; which is used to give a prefix to the name of our daemon process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Schedule::&lt;/span&gt;&lt;span class="nv"&gt;Cron&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$cron_daemon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Schedule::&lt;/span&gt;&lt;span class="nv"&gt;Cron&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;die&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;time-daemon: error: default Schedule::Cron function was called&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="s"&gt;processprefix&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;time-daemon&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The most important &lt;a href="https://metacpan.org/pod/Schedule::Cron"&gt;Schedule::Cron&lt;/a&gt; method is &lt;a href="https://metacpan.org/pod/Schedule::Cron#%24cron-%3Eadd_entry(%24timespec,%5Barguments%5D)"&gt;add_entry&lt;/a&gt;, which takes a cron string and a coderef. When we eventually run the daemon it will schedule the coderef to be run at the interval specified by the cron string.&lt;/p&gt;

&lt;p&gt;Personally I can never remember the syntax for cron strings. I use the website &lt;a href="https://crontab.guru/"&gt;crontab.guru&lt;/a&gt; for getting an English translation of what my cron string means, which makes it easy to build my cron strings.&lt;/p&gt;

&lt;p&gt;Lets schedule our &lt;code&gt;&amp;amp;append_time&lt;/code&gt; subroutine to be run every 5 minutes, and our &lt;code&gt;&amp;amp;rotate_time_log&lt;/code&gt; subroutine to be run every hour.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nv"&gt;$cron_daemon&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;add_entry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*/5 * * * *&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;
    &lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="nv"&gt;&amp;amp;append_time&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$cron_daemon&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;add_entry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0 */1 * * *&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;
    &lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="nv"&gt;&amp;amp;rotate_time_log&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are now ready to start up the daemon using the &lt;a href="https://metacpan.org/pod/Schedule::Cron#%24cron-%3Erun(%5Boptions%5D)"&gt;Schedule::Cron::run&lt;/a&gt; method. This method takes many options but the only one we will use is &lt;a href="https://metacpan.org/pod/Schedule::Cron#detach"&gt;detach&lt;/a&gt;, which will cause daemon process to detach itself from the current process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$cron_daemon&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;detach&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;started the time-daemon as pid &lt;/span&gt;&lt;span class="si"&gt;$pid&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's all there is to it! The basic recipe to follow is: initialize a &lt;a href="https://metacpan.org/pod/Schedule::Cron"&gt;Schedule::Cron&lt;/a&gt; object, schedule subroutines to be run with &lt;a href="https://metacpan.org/pod/Schedule::Cron#%24cron-%3Eadd_entry(%24timespec,%5Barguments%5D)"&gt;add_entry&lt;/a&gt;, then start the daemon with the &lt;a href="https://metacpan.org/pod/Schedule::Cron#%24cron-%3Erun(%5Boptions%5D)"&gt;run&lt;/a&gt; method.&lt;/p&gt;

</description>
      <category>perl</category>
    </item>
    <item>
      <title>Perl Project Management with App::plx</title>
      <dc:creator>Nicholas Hubbard</dc:creator>
      <pubDate>Sat, 03 Sep 2022 00:09:10 +0000</pubDate>
      <link>https://forem.com/nicholasbhubbard/segregate-perl-projects-with-appplx-7oj</link>
      <guid>https://forem.com/nicholasbhubbard/segregate-perl-projects-with-appplx-7oj</guid>
      <description>&lt;p&gt;&lt;a href="https://metacpan.org/pod/App::plx"&gt;App::plx&lt;/a&gt; (Plx) is a tool for configuring per-project Perl development environments.&lt;/p&gt;

&lt;p&gt;Plx has good documentation, so in this post I will give a general overview of some of the problems that it solves and how to get started using it.&lt;/p&gt;

&lt;p&gt;This is not a complete overview on everything that Plx can do.&lt;/p&gt;

&lt;p&gt;&lt;a id="orgbd602ea"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Why Plx?
&lt;/h1&gt;

&lt;p&gt;Imagine you have a project that depends on a Perl version greater than that of the Perl you have available. You will need to install the correct version of Perl and figure out how to get your project to use this Perl instead of the system's Perl.&lt;/p&gt;

&lt;p&gt;Next imagine a scenario where you are working on two different Perl projects that depend on a different version of the same CPAN module. You will need to figure out how to install both versions into different locations, and then you will need to figure out how to locate the correct version from the two different projects.&lt;/p&gt;

&lt;p&gt;You also may want to install all of your CPAN modules into your projects root directory so it can have its own private collection of modules that you know the project owns. Plx allows you to do this through simple integration with &lt;a href="https://metacpan.org/pod/local::lib"&gt;local::lib&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Plx also allows you to override your users perl through use of shell configuration. Personally I dont like touching my shell like this, but its still an option.&lt;/p&gt;

&lt;p&gt;These are some important problems that Plx solves.&lt;/p&gt;

&lt;p&gt;&lt;a id="org87e7c16"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Installation
&lt;/h1&gt;

&lt;p&gt;Before you can use Plx you must install Plx.&lt;/p&gt;

&lt;p&gt;If you already have a CPAN installer, such as &lt;a href="https://metacpan.org/pod/App::cpanminus"&gt;cpanminus&lt;/a&gt;, then you should probably just use that to install Plx.&lt;/p&gt;

&lt;p&gt;Plx can also be bootstrapped into a self contained script like so:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ mkdir "$HOME/bin"
$ wget https://raw.githubusercontent.com/shadowcat-mst/plx/master/bin/plx-packed -O "$HOME/bin/plx"
$ chmod +x "$HOME/bin/plx"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This is my favorite way to install plx because I get a single executable that just works.&lt;/p&gt;

&lt;p&gt;You can install Plx into any directory, I just chose "$HOME/bin" for simplicity. Just make sure you pick a directory in your $PATH.&lt;/p&gt;

&lt;p&gt;&lt;a id="orgd968283"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Initialization
&lt;/h1&gt;

&lt;p&gt;If you want to use Plx for your Perl project, you must first initialize the project to use Plx. To do this we must &lt;code&gt;cd&lt;/code&gt; into the root directory of the project and then execute Plx with the &lt;code&gt;--init&lt;/code&gt; flag.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;--init&lt;/code&gt; flag behaves differently depending on its argument.&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;--init&lt;/code&gt; is called with a file path, it assumes it is a path to a Perl interpreter and sets up Plx to use it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ plx --init /path/to/some/perl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;When called with &lt;code&gt;perl&lt;/code&gt; as the argument it sets up Plx to use the first Perl in your &lt;a href="https://en.wikipedia.org/wiki/PATH_(variable)"&gt;PATH&lt;/a&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ plx --init perl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The final and most exciting way to call &lt;code&gt;--init&lt;/code&gt; is with a Perl version number. When called with a version number, Plx will look for a Perl of the given version first in your &lt;a href="https://en.wikipedia.org/wiki/PATH_(variable)"&gt;PATH&lt;/a&gt; and otherwise via &lt;a href="https://perlbrew.pl/"&gt;Perlbrew&lt;/a&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ plx --init 5.36.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After initializing Plx you can execute your project code with a command like &lt;code&gt;$ plx /path/to/project/script.pl&lt;/code&gt;, and Plx will execute the script with the Perl interpreter you specified with the &lt;code&gt;plx --init&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;This is how Plx solves the problem of needing to use a different Perl than your systems built-in Perl.&lt;/p&gt;

&lt;p&gt;&lt;a id="org124c9de"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Installing CPAN Modules
&lt;/h1&gt;

&lt;p&gt;My favorite feature of Plx is that it allows you to install modules off of CPAN into a &lt;a href="https://metacpan.org/pod/local::lib"&gt;local::lib&lt;/a&gt; using &lt;a href="https://metacpan.org/pod/App::cpanminus"&gt;cpanminus&lt;/a&gt;. This allows you to segregate your CPAN modules dependencies on a per-project basis.&lt;/p&gt;

&lt;p&gt;To do this we must &lt;code&gt;cd&lt;/code&gt; into the root directory of our project and run the following command.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ plx --cpanm -Llocal Some::Module
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This will install &lt;code&gt;Some::Module&lt;/code&gt; into a project-local library located in a directory named &lt;code&gt;local/lib&lt;/code&gt; at the root of the project.&lt;/p&gt;

&lt;p&gt;This solves the problem of two projects requiring different versions of the same CPAN module. If both projects use Plx they can simply install their desired version into a &lt;a href="https://metacpan.org/pod/local::lib"&gt;local::lib&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a id="org9b2111c"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Userstrap
&lt;/h1&gt;

&lt;p&gt;What if you want to use your own Perl interpreter and a &lt;a href="https://metacpan.org/pod/local::lib"&gt;local::lib&lt;/a&gt; when you are working outside of a dedicated Plx project?&lt;/p&gt;

&lt;p&gt;Plx has a &lt;code&gt;--userstrap&lt;/code&gt; flag that will set this up for you automatically.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ plx --userstrap /path/to/some/perl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Calling &lt;code&gt;--userstrap&lt;/code&gt; essentially sets up your &lt;code&gt;$HOME&lt;/code&gt; to be a Plx project and sets up a &lt;a href="https://metacpan.org/pod/local::lib"&gt;local::lib&lt;/a&gt; in &lt;code&gt;$HOME/perl5&lt;/code&gt;, installs &lt;a href="https://metacpan.org/pod/App::plx"&gt;App::plx&lt;/a&gt; and &lt;a href="https://metacpan.org/pod/App::cpanminus"&gt;App::cpanminus&lt;/a&gt; into the local::lib, and adds a line to your &lt;code&gt;$HOME/.bashrc&lt;/code&gt; that sets up Plx for your Bash shell.&lt;/p&gt;

&lt;p&gt;Now when you run Plx from outside a dedicated Plx project it will use &lt;code&gt;$HOME&lt;/code&gt; as a sort of default Plx project. You can use &lt;code&gt;--userstrap&lt;/code&gt; to prevent needing to use your system Perl, so you and can instead always use Plx.&lt;/p&gt;

&lt;p&gt;Note that &lt;code&gt;--userstrap&lt;/code&gt; requires that you use a Bash shell.&lt;/p&gt;

&lt;p&gt;&lt;a id="org285989d"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Plx is For Everybody
&lt;/h1&gt;

&lt;p&gt;Plx is designed to not only provide a nice experience for Perl developers, but also to be usable by a sysadmin that isn't a Perl expert. Therefore Plx is configured through simple text files that can be manipulated by hand, and allows multiple commands to be run in a single Plx invocation via the &lt;code&gt;--multi&lt;/code&gt; flag, which makes scripting Plx cleaner.&lt;/p&gt;

&lt;p&gt;&lt;a id="orgdee387b"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Synopsis
&lt;/h1&gt;

&lt;p&gt;Plx is a tool for creating per-project virtual Perl environments. Plx lets us avoid a lot of headaches that come with developing multiple Perl projects on the same system.&lt;/p&gt;

&lt;p&gt;A lot of what Plx does can be done by combining features of other CPAN modules, but Plx brings together these functionalities in a way that is easy to use and understand.&lt;/p&gt;

&lt;p&gt;This blog post is only a brief introduction to Plx. Please go on to read the manual for more a more detailed overview of its features.&lt;/p&gt;

&lt;p&gt;&lt;a id="orgef3ab18"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Bonus Tip for Emacs Users
&lt;/h1&gt;

&lt;p&gt;If you lint your Perl code with the Perl interpreter using Flycheck, you will need to determine if the buffer is part of a Plx project so it runs the Perl interpreter through Plx (otherwise you will have @INC-related errors).&lt;/p&gt;

&lt;p&gt;Use the following code to do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="ss"&gt;'flycheck&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="ss"&gt;'projectile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;add-hook&lt;/span&gt; &lt;span class="ss"&gt;'cperl-mode-hook&lt;/span&gt; &lt;span class="ss"&gt;'flycheck-mode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;add-hook&lt;/span&gt; &lt;span class="ss"&gt;'cperl-mode-hook&lt;/span&gt; &lt;span class="ss"&gt;'my/cperl-select-correct-flycheck-checker&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;flycheck-define-checker&lt;/span&gt; &lt;span class="nv"&gt;my/perl-plx&lt;/span&gt;
  &lt;span class="s"&gt;""&lt;/span&gt;
  &lt;span class="ss"&gt;:command&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"plx"&lt;/span&gt; &lt;span class="s"&gt;"-w"&lt;/span&gt; &lt;span class="s"&gt;"-c"&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;option-list&lt;/span&gt; &lt;span class="s"&gt;"-I"&lt;/span&gt; &lt;span class="nv"&gt;flycheck-perl-include-path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;option-list&lt;/span&gt; &lt;span class="s"&gt;"-M"&lt;/span&gt; &lt;span class="nv"&gt;flycheck-perl-module-list&lt;/span&gt; &lt;span class="nv"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="ss"&gt;:standard-input&lt;/span&gt; &lt;span class="no"&gt;t&lt;/span&gt;
  &lt;span class="ss"&gt;:error-patterns&lt;/span&gt;
  &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nb"&gt;error&lt;/span&gt; &lt;span class="nv"&gt;line-start&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;minimal-match&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;message&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
          &lt;span class="s"&gt;" at - line "&lt;/span&gt; &lt;span class="nv"&gt;line&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;or&lt;/span&gt; &lt;span class="s"&gt;"."&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;and&lt;/span&gt; &lt;span class="s"&gt;", "&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;zero-or-more&lt;/span&gt; &lt;span class="nv"&gt;not-newline&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="nv"&gt;line-end&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="ss"&gt;:modes&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;perl-mode&lt;/span&gt; &lt;span class="nv"&gt;cperl-mode&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;defun&lt;/span&gt; &lt;span class="nv"&gt;my/cperl-select-correct-flycheck-checker&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="s"&gt;"If the current buffer is part of a plx project then use the `my/perl-plx'
checker, otherwise use the `perl' checker."&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;proj-root&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;projectile-project-root&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;string-remove-suffix&lt;/span&gt; &lt;span class="s"&gt;"/"&lt;/span&gt; &lt;span class="nv"&gt;default-directory&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;and&lt;/span&gt; &lt;span class="nv"&gt;proj-root&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;file-directory-p&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;concat&lt;/span&gt; &lt;span class="nv"&gt;proj-root&lt;/span&gt; &lt;span class="s"&gt;".plx"&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;flycheck-select-checker&lt;/span&gt; &lt;span class="ss"&gt;'my/perl-plx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;flycheck-select-checker&lt;/span&gt; &lt;span class="ss"&gt;'perl&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>perl</category>
    </item>
    <item>
      <title>How I use Emacs to write Perl</title>
      <dc:creator>Nicholas Hubbard</dc:creator>
      <pubDate>Wed, 24 Aug 2022 23:42:00 +0000</pubDate>
      <link>https://forem.com/nicholasbhubbard/how-i-use-emacs-to-write-perl-40e6</link>
      <guid>https://forem.com/nicholasbhubbard/how-i-use-emacs-to-write-perl-40e6</guid>
      <description>&lt;p&gt;This post is about how I use Emacs to write Perl. I do not claim to have the best Perl setup of all time or anything like that. The features I need to write Perl effectively are syntax highlighting, auto-indentation, linting, and code navigation.&lt;/p&gt;

&lt;p&gt;I personally like to build my own IDE by bringing together unrelated packages, which is in contrast to full blown IDE packages, such as &lt;a href="https://metacpan.org/pod/Devel::PerlySense"&gt;Devel::PerlySense&lt;/a&gt; or &lt;a href="https://metacpan.org/pod/Perl::LanguageServer"&gt;Perl::LanguageServer&lt;/a&gt;. These packages just aren't for me.&lt;/p&gt;

&lt;p&gt;&lt;a id="orga25e1f5"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Basics
&lt;/h1&gt;

&lt;p&gt;By default Emacs uses perl-mode instead of the more advanced cperl-mode. Both packages are built-in, so to use cperl-mode instead of perl-mode all you have to do is add the following line to your config.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;fset&lt;/span&gt; &lt;span class="ss"&gt;'perl-mode&lt;/span&gt; &lt;span class="ss"&gt;'cperl-mode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The cperl-mode that was released with Emacs 28 improved the syntax highlighting for regular expressions and heredocs, and fixed a few other annoying bugs. &lt;/p&gt;

&lt;p&gt;If you are using an Emacs version less than 28 then I would recommend downloading the &lt;a href="https://github.com/emacs-mirror/emacs/blob/emacs-28/lisp/progmodes/cperl-mode.el"&gt;cperl-mode off the Emacs 28 (at least) branch&lt;/a&gt;. I personally place this file in &lt;code&gt;~/.emacs.d/cperl-mode/cperl-mode.el&lt;/code&gt;, then I load it with the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;add-to-list&lt;/span&gt; &lt;span class="ss"&gt;'load-path&lt;/span&gt; &lt;span class="s"&gt;"~/.emacs.d/cperl-mode"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="ss"&gt;'cperl-mode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default cperl-mode replaces trailing whitespace with underscores. You can automatically delete this with &lt;a href="https://github.com/purcell/whitespace-cleanup-mode"&gt;whitespace-cleanup-mode&lt;/a&gt;, or you can use this elisp:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;setq&lt;/span&gt; &lt;span class="nv"&gt;cperl-invalid-face&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;cperl-mode defaults to indenting blocks by 2 spaces. You can modify this by setting the &lt;code&gt;cperl-indent-level&lt;/code&gt; to some value other than 2.&lt;/p&gt;

&lt;p&gt;You probably want multi-line statements wrapped in parens to be indented like a block. By default cperl-mode indents this hash declaration in a strange way (to me):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;%hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;baz&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
           &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To instead indent like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;%hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;baz&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add this to your config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;setq&lt;/span&gt; &lt;span class="nv"&gt;cperl-indent-parens-as-block&lt;/span&gt; &lt;span class="no"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;setq&lt;/span&gt; &lt;span class="nv"&gt;cperl-close-paren-offset&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;cperl-indent-level&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a id="org3c40091"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Linting
&lt;/h1&gt;

&lt;p&gt;Linting Perl code helps to quickly find bugs caused by typos or little errors. My favorite Emacs linting package is &lt;a href="https://www.flycheck.org/en/latest/"&gt;Flycheck&lt;/a&gt;, which comes with built-in support for Perl.&lt;/p&gt;

&lt;p&gt;By default Flycheck checks your code with the Perl interpreter, but it also comes with integration with &lt;a href="https://metacpan.org/pod/Perl::Critic"&gt;Perl::Critic&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;I like to lint the file everytime I save, and I like to display any errors immediately. Here is how I accomplish this with Flycheck.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="ss"&gt;'flycheck&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;setq&lt;/span&gt; &lt;span class="nv"&gt;flycheck-check-syntax-automatically&lt;/span&gt; &lt;span class="o"&gt;'&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;mode-enabled&lt;/span&gt; &lt;span class="nv"&gt;save&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;setq&lt;/span&gt; &lt;span class="nv"&gt;flycheck-display-errors-delay&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To enable flycheck mode in cperl-mode, simply turn it on with a hook.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(add-hook 'cperl-mode-hook 'flycheck-mode)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now Emacs will underline any syntax errors, and you can view the message in the echo area by placing your cursor on the erroneus code.&lt;/p&gt;

&lt;p&gt;I cannot tell you how many simple errors you will catch just by using Flycheck!&lt;/p&gt;

&lt;p&gt;&lt;a id="org063479d"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Code Navigation
&lt;/h1&gt;

&lt;p&gt;For jumping between function definitions I use &lt;a href="https://github.com/jacktasia/dumb-jump"&gt;dumb-jump&lt;/a&gt;, which usually &lt;strong&gt;just works&lt;/strong&gt;. I configure dumb-jump to use &lt;a href="https://github.com/ggreer/the_silver_searcher"&gt;ag&lt;/a&gt; for its searching which makes it work very quickly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="ss"&gt;'dumb-jump&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;setq&lt;/span&gt; &lt;span class="nv"&gt;dumb-jump-force-searcher&lt;/span&gt; &lt;span class="ss"&gt;'ag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;add-hook&lt;/span&gt; &lt;span class="ss"&gt;'xref-backend-functions&lt;/span&gt; &lt;span class="nf"&gt;#'&lt;/span&gt;&lt;span class="nv"&gt;dumb-jump-xref-activate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I can then use dumb-jump by calling the &lt;code&gt;xref-find-definitions&lt;/code&gt; function while my cursor is on the symbol I want to search for. This function is bound to &lt;code&gt;M-.&lt;/code&gt; by default.&lt;/p&gt;

&lt;p&gt;&lt;a id="orgde68f03"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Shell
&lt;/h1&gt;

&lt;p&gt;A lot of people use &lt;code&gt;M-x compile&lt;/code&gt; to run their code, and one of the various debugger packages to run the Perl debugger. Personally I just use plain old &lt;a href="https://www.gnu.org/software/bash/"&gt;Bash&lt;/a&gt; with the built-in &lt;code&gt;M-x shell&lt;/code&gt;. This makes my work flow when it comes to running and debugging quite similar to that of a classic Perl vimmer who does all their work in a terminal.&lt;/p&gt;

&lt;p&gt;I use the wonderful &lt;a href="https://github.com/riscy/shx-for-emacs"&gt;shx&lt;/a&gt; package for making &lt;code&gt;M-x shell&lt;/code&gt; a more usable shell interface, and I use &lt;a href="https://github.com/kyagi/shell-pop-el"&gt;shell-pop&lt;/a&gt; for popping up shell buffers that are automatically cd'd to the current files directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(require 'shx)
(add-hook 'shell-mode-hook 'shx-mode)

(require 'shell-pop)
(setq shell-pop-autocd-to-working-dir t)
(global-set-key (kbd "M-SPC") 'shell-pop)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a id="org3936e96"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Closing Thoughts
&lt;/h1&gt;

&lt;p&gt;Every 3rd-party package I described in this post is useful not only for Perl, but for programming in any language. This gives a uniform experience across different programming languages. If I instead used one of the Perl IDE packages then I wouldn't get the same uniform experience when using other languages.&lt;/p&gt;

&lt;p&gt;&lt;a id="orgd51f8f0"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  See Also
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://www.emacswiki.org/emacs/CPerlMode"&gt;CPerl Documentation&lt;/a&gt;  - Offical documentation for cperl-mode&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://metacpan.org/pod/Perl::LanguageServer"&gt;Perl::LanguageServer&lt;/a&gt; - Language server for Perl&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://metacpan.org/pod/Devel::PerlySense"&gt;Devel::PerlySense&lt;/a&gt;    - Perl IDE features for Emacs&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://metacpan.org/pod/Emacs::PDE"&gt;Emacs::PDE&lt;/a&gt;           - Elisp extensions for Perl development&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>perl</category>
      <category>emacs</category>
    </item>
    <item>
      <title>Make Perl Count Arguments</title>
      <dc:creator>Nicholas Hubbard</dc:creator>
      <pubDate>Wed, 17 Aug 2022 19:28:00 +0000</pubDate>
      <link>https://forem.com/nicholasbhubbard/make-perl-count-arguments-3bdj</link>
      <guid>https://forem.com/nicholasbhubbard/make-perl-count-arguments-3bdj</guid>
      <description>&lt;p&gt;Unlike many programming languages, Perl doesn't check that functions are called with the correct number of arguments. This is because Perl subroutines are variadic by default, which makes a lot of programming tasks really easy. The downside is that a lot of the time functions only make sense if they are called with a certain number of arguments.&lt;/p&gt;

&lt;p&gt;Most of the time if a subroutine is called with an incorrect number of arguments it is because the programmer made a simple typo. To make our lives as programmers easier, it would be nice if we could detect this situation and give a clear error message about what went wrong.&lt;/p&gt;

&lt;p&gt;We will explore a solution to this problem.&lt;/p&gt;

&lt;p&gt;WARNING: The examples in this artical call Perl from the command line. If you don't understand Perl command line syntax, only pay attention to what comes after the &lt;code&gt;-E&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Lets look at an example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nb"&gt;package&lt;/span&gt; &lt;span class="nv"&gt;T&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;num_diff&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$n1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$n2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$n1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$n2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When called with two arguments our function behaves as expected.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ perl -W -I. -MT -E 'say T::num_diff(7, 17)'
10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;But what if we call &lt;code&gt;num_diff&lt;/code&gt; with more than two arguments?&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ perl -W -I. -MT -E 'say T::num_diff(23, 21, 48)'
2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Perl has no issue if we call this function with 3 arguments, and happily returns us the difference between the first two arguments. This is bad! The difference between 3 numbers is certainly not the difference between the first 2.&lt;/p&gt;

&lt;p&gt;A nice way to deal with this problem is to use &lt;a href="https://perldoc.perl.org/perlsub#Signatures"&gt;signatures&lt;/a&gt;, which provides syntax for declaring a subroutines arguments. Lets rewrite &lt;code&gt;num_diff&lt;/code&gt; using signatures.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nb"&gt;package&lt;/span&gt; &lt;span class="nv"&gt;T&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;v5&lt;/span&gt;&lt;span class="mf"&gt;.20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;feature&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;signatures&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;num_diff&lt;/span&gt;&lt;span class="p"&gt;($n1, $n2) {&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$n1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$n2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lets see what happens when we call &lt;code&gt;num_diff&lt;/code&gt; with more than 2 arguments.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ perl -I. -MT -E 'say T::num_diff(22, 33, 8)'
Too many arguments for subroutine 'T::num_diff' (got 3; expected 2) at -e line 1.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Awesome, our problem is solved! With signatures Perl can count our subroutine arguments and give us error diagnositics when we mess up.&lt;/p&gt;

&lt;p&gt;Unfortunately though there are some downsides to signatures. First off signatures didn't exist until Perl version 5.20, so if you're use an old Perl signatures are not an option. The other downside is that signatures were experimental until Perl version 5.36, which is why the &lt;code&gt;use feature 'signatures'&lt;/code&gt; statement is necessary.&lt;/p&gt;

&lt;p&gt;I have been working on a Perl project that uses Perl version 5.16.3, so I cannot use signatures. To count arguments I wrote a function that I call as the first statement in subroutines that kills the program if it did not receive the correct number of arguments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;Carp&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;confess&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;arg_count_or_die&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;# Carp::Confess unless $num_args is in range $lower-$upper&lt;/span&gt;

    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$lower&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$upper&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$num_args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;@_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$lower&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$upper&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$upper&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$lower&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$lower&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$upper&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$lower&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nv"&gt;$num_args&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$num_args&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nv"&gt;$upper&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$caller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nb"&gt;caller&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$expected_plural&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$lower&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;'':&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;s&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$got_plural&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$num_args&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;''&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;s&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
        &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$arg_range_msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$lower&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nv"&gt;$upper&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$lower&lt;/span&gt;&lt;span class="s2"&gt; arg&lt;/span&gt;&lt;span class="si"&gt;$expected_plural&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$lower&lt;/span&gt;&lt;span class="s2"&gt;-&lt;/span&gt;&lt;span class="si"&gt;$upper&lt;/span&gt;&lt;span class="s2"&gt; args&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
        &lt;span class="nv"&gt;confess&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="s2"&gt;yabsm: internal error: called '&lt;/span&gt;&lt;span class="si"&gt;$caller&lt;/span&gt;&lt;span class="s2"&gt;' with &lt;/span&gt;&lt;span class="si"&gt;$num_args&lt;/span&gt;&lt;span class="s2"&gt; arg&lt;/span&gt;&lt;span class="si"&gt;$got_plural&lt;/span&gt;&lt;span class="s2"&gt; but it expects &lt;/span&gt;&lt;span class="si"&gt;$arg_range_msg&lt;/span&gt;&lt;span class="p"&gt;");&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lets rewrite &lt;code&gt;num_diff&lt;/code&gt; to use this function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;num_diff&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nv"&gt;arg_count_or_die&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$n1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$n2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$n1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$n2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, lets call &lt;code&gt;num_diff&lt;/code&gt; with more than 2 arguments&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ perl -I. -MT -E 'say T::num_diff(22, 33, 8)'
my-program: internal error: call to 'T::num_diff' passed 3 args but expects 2 args at T.pm line 19.
        T::arg_count_or_die(2, 2, 22, 33, 8) called at T.pm line 27
        T::num_diff(22, 33, 8) called at -e line 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We can see that by using Carp::Confess we get an excellent error message that shows the call stack that lead to the to our erroneus subroutine call. By prefixing the error message with &lt;code&gt;my-program: internal error&lt;/code&gt;, if this error ever occurs our user knows that they found a bug and can send us the stack trace which will be very useful for debugging.&lt;/p&gt;

</description>
      <category>perl</category>
    </item>
    <item>
      <title>4 Unrelated Perl Tidbits</title>
      <dc:creator>Nicholas Hubbard</dc:creator>
      <pubDate>Wed, 10 Aug 2022 17:18:00 +0000</pubDate>
      <link>https://forem.com/nicholasbhubbard/4-unrelated-perl-tidbits-2766</link>
      <guid>https://forem.com/nicholasbhubbard/4-unrelated-perl-tidbits-2766</guid>
      <description>&lt;p&gt;I recently acquired a copy of &lt;a href="https://www.oreilly.com/library/view/programming-perl-4th/9781449321451/"&gt;Programming Perl&lt;/a&gt;, often referred to as "The Camel Book" in the Perl community. After reading the first 4 chapters I thought I would share a few Perl tidbits I found interesting.&lt;/p&gt;

&lt;p&gt;&lt;a id="org1d47756"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  While &amp;lt;&amp;gt; is True
&lt;/h1&gt;

&lt;p&gt;Say we have the following file named &lt;code&gt;logos.txt&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Onion
Camel

Raptor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And in the same directory we have the following program named &lt;code&gt;scratch.pl&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="nb"&gt;open&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;logos.txt&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nb"&gt;die&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$logo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;$fh&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="nv"&gt;$logo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;close&lt;/span&gt; &lt;span class="nv"&gt;$fh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As expected our program prints the contents of &lt;code&gt;logos.txt&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ perl ./scratch.pl
Onion
Camel

Raptor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Something I never really considered though, is why doesn't the loop exit when &lt;code&gt;&amp;lt;&amp;gt;&lt;/code&gt; reads the empty line in &lt;code&gt;logos.txt&lt;/code&gt;? Shouldn't &lt;code&gt;&amp;lt;&amp;gt;&lt;/code&gt; return an empty string which is a false value?&lt;/p&gt;

&lt;p&gt;According to Programming Perl, the reason why the loop doesn't exit is because &lt;code&gt;&amp;lt;&amp;gt;&lt;/code&gt; reads the newline at the end of the line so we actually get &lt;code&gt;"\n"&lt;/code&gt; which is a true value. Turns out this is a fib, and the actual reason is that &lt;code&gt;while (my $logo = &amp;lt;$fh&amp;gt;) ...&lt;/code&gt; expands into &lt;code&gt;while (defined (my $logo = &amp;lt;$fh&amp;gt;)) ...&lt;/code&gt;, and &lt;code&gt;"\n"&lt;/code&gt; is a defined value.&lt;/p&gt;

&lt;p&gt;We can show this by deparsing the code with &lt;a href="https://perldoc.perl.org/B::Deparse"&gt;B::Deparse&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ perl -MO=Deparse,-p,-sCi2 -ne 42
LINE: while (defined(($_ = readline(ARGV)))) {
  '???';
}
-e syntax OK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a id="org99a62c3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Heredocs Can Execute Shell Commands
&lt;/h1&gt;

&lt;p&gt;Most Perl programmers know that if you single quote a heredocs terminating string you prevent variable interpolation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$var&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;&amp;lt;'EOS';
Hello
$var = 12
EOS
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see in the programs output that &lt;code&gt;$var&lt;/code&gt; was not interpolated.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ perl ./scratch.pl
Hello
$var = 12
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;But did you know that if you backquote the terminating string then each line is executed as a shell command?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;`&lt;/span&gt;&lt;span class="sb"&gt;EOC&lt;/span&gt;&lt;span class="p"&gt;`;&lt;/span&gt;
&lt;span class="nv"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;this&lt;/span&gt; &lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="nv"&gt;a&lt;/span&gt; &lt;span class="nv"&gt;shell&lt;/span&gt; &lt;span class="nv"&gt;command&lt;/span&gt;
&lt;span class="nv"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;this&lt;/span&gt; &lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="nv"&gt;also&lt;/span&gt; &lt;span class="nv"&gt;a&lt;/span&gt; &lt;span class="nv"&gt;shell&lt;/span&gt; &lt;span class="nv"&gt;command&lt;/span&gt;
&lt;span class="nv"&gt;EOC&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we run this program we can see that the echo commands were executed.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ perl ./scratch.pl
this is a shell command
this is also a shell command
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a id="orgd568d68"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  The Comma Operator
&lt;/h1&gt;

&lt;p&gt;I always took commas for granted, never realizing they were actually an operator.&lt;/p&gt;

&lt;p&gt;Did you ever wonder why lists return their last element when evaluated in scalar context? Turns out it is due to the comma operator.&lt;/p&gt;

&lt;p&gt;In scalar context the comma operator "," ignores its first argument, and returns its second element evaluated in scalar context.&lt;/p&gt;

&lt;p&gt;This means that in scalar context the list &lt;code&gt;(11, 22, 33)&lt;/code&gt; will evaluate to 33. The first comma operator will throw away the 11 and then return &lt;code&gt;(22, 33)&lt;/code&gt; evaluated in scalar context, which will be evaluated by throwing away the 22 and returning 33.&lt;/p&gt;

&lt;p&gt;&lt;a id="org644e91b"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Auto-Incrementing Strings
&lt;/h1&gt;

&lt;p&gt;In perl you can not only auto-increment numbers, but also strings. To increment a string it must match the regex &lt;code&gt;/^[a-zA-Z]*[0-9]*\z/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Single alphabet character strings are incremented intuitively.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ perl -E 'my $v = "a"; say ++$v'
b
$ perl -E 'my $v = "B"; say ++$v'
C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;What happens though if we increment a non-alphanumeric char. Will it give the next ASCII character? Turns out non-alphanumeric characters are treated as 0's when incrementing. Fortunately if we use &lt;a href="https://perldoc.perl.org/warnings"&gt;warnings&lt;/a&gt; Perl will give us a heads up.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ perl -W -E 'my $v = "-"; say ++$v'
Argument "-" treated as 0 in increment (++) at -e line 1.
1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;What happens if we increment &lt;code&gt;z&lt;/code&gt;, which is at the end of the alphabet? Do we wrap back around to &lt;code&gt;a&lt;/code&gt;? This is where things get interesting. Perl increments the string just like you would in a regular number system. Just like &lt;code&gt;9 + 1 = 10&lt;/code&gt; in decimal &lt;code&gt;z + 1 = aa&lt;/code&gt; in … stringimal.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ perl -E 'my $v = "z"; say ++$v'
aa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here are some more examples to show you the magic of string auto-incrementing.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ perl -W -E 'my $v1 = "foo"; say ++$v1'
fop
$ perl -W -E 'my $v1 = "az"; say ++$v1'
ba
$ perl -W -E 'my $v1 = "a9"; say ++$v1'
b0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>perl</category>
    </item>
  </channel>
</rss>
