<?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>DEV Community: Mark Gardner</title>
    <description>The latest articles on DEV Community by Mark Gardner (@mjgardner).</description>
    <link>https://dev.to/mjgardner</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%2F510993%2Fd0e608ad-447b-4b66-96e7-1c37eeb08c7a.jpeg</url>
      <title>DEV Community: Mark Gardner</title>
      <link>https://dev.to/mjgardner</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mjgardner"/>
    <language>en</language>
    <item>
      <title>Porting from Perl to Go: Simplifying for Platform Engineering</title>
      <dc:creator>Mark Gardner</dc:creator>
      <pubDate>Wed, 15 Oct 2025 16:18:32 +0000</pubDate>
      <link>https://dev.to/mjgardner/porting-from-perl-to-go-simplifying-for-platform-engineering-301h</link>
      <guid>https://dev.to/mjgardner/porting-from-perl-to-go-simplifying-for-platform-engineering-301h</guid>
      <description>&lt;p&gt;&lt;strong&gt;Rewriting a script for the &lt;a href="https://brew.sh/" rel="noopener noreferrer"&gt;Homebrew package manager&lt;/a&gt; taught me how &lt;a href="https://go.dev/" rel="noopener noreferrer"&gt;Go&lt;/a&gt;’s design choices align with platform-ready tools.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with &lt;code&gt;brew upgrade&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;By default, the &lt;code&gt;brew upgrade&lt;/code&gt; command updates every &lt;a href="https://formulae.brew.sh/formula/" rel="noopener noreferrer"&gt;formula&lt;/a&gt; (terminal utility or library). It also updates every &lt;a href="https://formulae.brew.sh/cask/" rel="noopener noreferrer"&gt;cask&lt;/a&gt; (GUI application) it manages. All are upgraded to the latest version — major, minor, and patch. That’s convenient when you want the newest features, but disruptive when you only want quiet patch-level fixes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://phoenixtrap.com/2025/09/28/patch-perfect-homebrew/" rel="noopener noreferrer"&gt;Last week&lt;/a&gt; I solved this in &lt;a href="https://www.perl.org/" rel="noopener noreferrer"&gt;Perl&lt;/a&gt; with &lt;code&gt;brew-patch-upgrade.pl&lt;/code&gt;, a script that parsed &lt;code&gt;brew upgrade&lt;/code&gt;’s JSON output, compared &lt;a href="https://semver.org/" rel="noopener noreferrer"&gt;semantic versions&lt;/a&gt;, and upgraded only when the patch number changed. It worked, but it also reminded me how much Perl leans on implicit structures and runtime flexibility.&lt;/p&gt;

&lt;p&gt;This week I ported the script to &lt;a href="https://go.dev/" rel="noopener noreferrer"&gt;Go&lt;/a&gt;, the &lt;em&gt;lingua franca&lt;/em&gt; of &lt;a href="https://en.wikipedia.org/wiki/DevOps" rel="noopener noreferrer"&gt;DevOps&lt;/a&gt;. The goal wasn’t feature parity — it was to see how Go’s design choices map onto platform engineering concerns.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why port to Go?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Portfolio practice&lt;/strong&gt; : I’m building a body of work that demonstrates &lt;a href="https://platformengineering.org/blog/what-is-platform-engineering" rel="noopener noreferrer"&gt;platform engineering&lt;/a&gt; skills.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operational focus&lt;/strong&gt; : Go is widely used for tooling in infrastructure and cloud environments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learning by contrast&lt;/strong&gt; : Rewriting a working Perl script in Go forces me to confront differences in error handling, type safety, and distribution.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The journey
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Error handling philosophy
&lt;/h3&gt;

&lt;p&gt;Perl gave me &lt;a href="https://perldoc.perl.org/perlsyn#Try-Catch-Exception-Handling" rel="noopener noreferrer"&gt;&lt;code&gt;try&lt;/code&gt;/&lt;code&gt;catch&lt;/code&gt;&lt;/a&gt; (&lt;a href="https://perldoc.perl.org/perlexperiment#try/catch-control-structure" rel="noopener noreferrer"&gt;experimental&lt;/a&gt; in the Perl v5.34.1 that ships with macOS, but since &lt;a href="https://perldoc.perl.org/perl5400delta#try/catch-feature-is-no-longer-experimental" rel="noopener noreferrer"&gt;accepted into the language in v5.40&lt;/a&gt;). Go, famously, does not. Instead, every function returns an error explicitly.&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;.34&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;use&lt;/span&gt; &lt;span class="nv"&gt;experimental&lt;/span&gt; &lt;span class="sx"&gt;qw(try)&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;Carp&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;autodie&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="err"&gt;…&lt;/span&gt;

&lt;span class="nv"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;system&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nv"&gt;brew&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nv"&gt;upgrade&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nv"&gt;upgraded&lt;/span&gt;&lt;span class="err"&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;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nv"&gt;failed&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nv"&gt;carp&lt;/span&gt; &lt;span class="nv"&gt;$e&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;exec&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;
  &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="err"&gt;…&lt;/span&gt;

&lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;exec&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;brew&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;upgrade&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CombinedOutput&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="n"&gt;failed&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;upgrade&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;output&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 Go version is noisier, but it forces explicit decisions. That’s a feature in production tooling: no silent failures.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dependency management
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Perl&lt;/strong&gt; : &lt;code&gt;cpanfile&lt;/code&gt; + &lt;a href="https://www.cpan.org/modules/index.html" rel="noopener noreferrer"&gt;CPAN modules&lt;/a&gt;. Distribution means “&lt;a href="https://www.perl.org/get.html" rel="noopener noreferrer"&gt;install Perl&lt;/a&gt; (if it’s not already), install modules, run script.” Tools like &lt;code&gt;carton&lt;/code&gt; and the &lt;code&gt;cpan&lt;/code&gt; or &lt;code&gt;cpanm&lt;/code&gt; commands help automate this. Additionally, one can use further tooling like &lt;code&gt;fatpack&lt;/code&gt; and &lt;code&gt;pp&lt;/code&gt; to build more self-contained packages. But those are neither common nor (except for &lt;code&gt;cpan&lt;/code&gt;) distributed with Perl.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Go&lt;/strong&gt; : &lt;code&gt;go.mod&lt;/code&gt; + &lt;code&gt;go build&lt;/code&gt;. Distribution is a single (platform-specific) binary.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For operational tools, that’s a massive simplification. No runtime interpreter, no dependency dance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Type safety
&lt;/h3&gt;

&lt;p&gt;Perl let me &lt;a href="https://perldoc.perl.org/JSON::PP#decode_json" rel="noopener noreferrer"&gt;parse JSON into hashrefs&lt;/a&gt; and trust the keys exist. Go required a &lt;code&gt;struct&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Formula&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"name"`&lt;/span&gt;
  &lt;span class="n"&gt;CurrentVersion&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"current_version"`&lt;/span&gt;
  &lt;span class="n"&gt;InstalledVersions&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"installed_versions"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compiler enforces assumptions that Perl left implicit. That friction is valuable — it surfaces errors early.&lt;/p&gt;

&lt;h3&gt;
  
  
  Binary distribution
&lt;/h3&gt;

&lt;p&gt;This is where Go shines. Instead of telling colleagues “&lt;a href="https://www.perl.org/get.html" rel="noopener noreferrer"&gt;install Perl&lt;/a&gt; v5.34 and &lt;a href="https://www.cpan.org/modules/index.html" rel="noopener noreferrer"&gt;CPAN modules&lt;/a&gt;,” I can hand them a binary. No need to worry about scripting runtime environments — just grab the right file for your system.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;homebrew-semver-guard-darwin&lt;/code&gt; (&lt;a href="https://developer.apple.com/documentation/apple-silicon/building-a-universal-macos-binary" rel="noopener noreferrer"&gt;Universal Binary for macOS&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;homebrew-semver-guard-linux-amd64&lt;/code&gt; (&lt;a href="https://en.wikipedia.org/wiki/X86-64" rel="noopener noreferrer"&gt;Intel/AMD 64-bit&lt;/a&gt; binary for Linux)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;homebrew-semver-guard-linux-arm64&lt;/code&gt; (&lt;a href="https://en.wikipedia.org/wiki/AArch64" rel="noopener noreferrer"&gt;Arm 64-bit&lt;/a&gt; binary for Linux)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Available on the &lt;a href="https://codeberg.org/mjgardner/homebrew-semver-guard/releases/tag/v0.1.0" rel="noopener noreferrer"&gt;release page&lt;/a&gt;. Download, run, done.&lt;/p&gt;

&lt;h3&gt;
  
  
  Semantic versioning logic
&lt;/h3&gt;

&lt;p&gt;In Perl, I manually compared arrays of version numbers. In Go, I imported &lt;code&gt;golang.org/x/mod/semver&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;golang&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;org&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mod&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;semver&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="err"&gt;…&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;semver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MajorMinor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;toSemver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;formula&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InstalledVersions&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt;
  &lt;span class="n"&gt;semver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MajorMinor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;toSemver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;formula&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CurrentVersion&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;patch&lt;/span&gt; &lt;span class="n"&gt;upgrade&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;formula&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;skipped&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
  &lt;span class="k"&gt;continue&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cleaner, more legible, and less error-prone. The library encodes the convention, so I don’t have to.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deliberate simplification
&lt;/h3&gt;

&lt;p&gt;I didn’t port every feature. &lt;a href="https://metacpan.org/dist/Log-Any-Adapter-MacOS-OSLog" rel="noopener noreferrer"&gt;Logging adapters&lt;/a&gt;, &lt;a href="https://perldoc.perl.org/variables/%25SIG" rel="noopener noreferrer"&gt;signal&lt;/a&gt; handlers, and edge-case diagnostics remained in Perl. The Go version focuses on the core logic: parse JSON, compare versions, run upgrades. That restraint was intentional — I wanted to learn Go’s idioms, not replicate every Perl flourish.&lt;/p&gt;

&lt;h2&gt;
  
  
  Platform engineering insights
&lt;/h2&gt;

&lt;p&gt;Three lessons stood out:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Binary distribution matters.&lt;/strong&gt; Operational tools should be installable with a single copy step. Go makes that trivial.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://semver.org/" rel="noopener noreferrer"&gt;Semantic versioning&lt;/a&gt; is an operational practice.&lt;/strong&gt; It’s not just a convention for library authors — it’s a contract that tooling can enforce.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Go’s design aligns with platform needs.&lt;/strong&gt; Explicit errors, type safety, and static binaries all reduce surprises in production.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Bringing it home
&lt;/h2&gt;

&lt;p&gt;This isn’t a “Perl vs. Go” story. It’s a story about deliberate simplification, taking a working Perl script and recasting it in Go. The aim is to see how the language’s choices shape a solution to the same problem.&lt;/p&gt;

&lt;p&gt;The result is &lt;code&gt;homebrew-semver-guard&lt;/code&gt; &lt;a href="https://codeberg.org/mjgardner/homebrew-semver-guard/releases/tag/v0.1.0" rel="noopener noreferrer"&gt;v0.1.0&lt;/a&gt;, a small but sturdy tool. It’s not feature-finished, but it’s production-ready in the ways that matter.&lt;/p&gt;

&lt;p&gt;Next up: I’m considering more Go tools, maybe even Kubernetes for services on my home server. This port was a practice, an artifact demonstrating platform engineering in action.&lt;/p&gt;




&lt;h3&gt;
  
  
  Links
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Original Perl script: &lt;code&gt;brew-patch-upgrade.pl&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Go release: &lt;a href="https://codeberg.org/mjgardner/homebrew-semver-guard/releases/tag/v0.1.0" rel="noopener noreferrer"&gt;&lt;code&gt;homebrew-semver-guard&lt;/code&gt; v0.1.0&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Last week’s post: &lt;a href="https://phoenixtrap.com/2025/09/28/patch-perfect-homebrew/" rel="noopener noreferrer"&gt;Patch-​Perfect: Smarter Homebrew Upgrades on macOS&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>programming</category>
      <category>go</category>
      <category>perl</category>
      <category>devops</category>
    </item>
    <item>
      <title>Verifying my cryptographic key for Keyoxide</title>
      <dc:creator>Mark Gardner</dc:creator>
      <pubDate>Fri, 18 Nov 2022 22:54:38 +0000</pubDate>
      <link>https://dev.to/mjgardner/verifying-my-cryptographic-key-for-keyoxide-21f</link>
      <guid>https://dev.to/mjgardner/verifying-my-cryptographic-key-for-keyoxide-21f</guid>
      <description>&lt;p&gt;[Verifying my cryptographic key: openpgp4fpr:4dadfefe8e4ad0f92bcbbb8142f3ca898cb08a45]&lt;/p&gt;

</description>
      <category>keyoxide</category>
      <category>gnupg</category>
      <category>pgp</category>
      <category>cryptography</category>
    </item>
    <item>
      <title>Perl lightning talk: ”Don’t Fear map and grep”</title>
      <dc:creator>Mark Gardner</dc:creator>
      <pubDate>Fri, 24 Jun 2022 21:25:44 +0000</pubDate>
      <link>https://dev.to/mjgardner/perl-lightning-talk-dont-fear-map-and-grep-27gn</link>
      <guid>https://dev.to/mjgardner/perl-lightning-talk-dont-fear-map-and-grep-27gn</guid>
      <description>&lt;p&gt;This week’s &lt;a href="https://perlconference.us/tprc-2022-hou/" rel="noopener noreferrer"&gt;Perl and Raku Conference 2022&lt;/a&gt; in Houston was packed with &lt;a href="https://youtube.com/playlist?list=PLA9_Hq3zhoFyOpb-U3DMU7OT93dPUdtpE" rel="noopener noreferrer"&gt;great presentations&lt;/a&gt;, and I humbly added to them with a five-ish minute &lt;a href="https://perlconference.us/tprc-2022-hou/lightning-talks/" rel="noopener noreferrer"&gt;lightning talk&lt;/a&gt; on two of Perl’s more misunderstood functions: &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;grep&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/PHdq4QfSxrc"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Sorry about the ”um”s and ”ah”s…)&lt;/em&gt;&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://www.slideshare.net/slideshow/dont-fear-map-grep-list-processing-for-fun-and-profit/252056897" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.slidesharecdn.com%2Fss_thumbnails%2Fperlmapandgreplightningtalk-220625022517-88629ff1-thumbnail.jpg%3Fwidth%3D640%26height%3D640%26fit%3Dbounds" height="360" class="m-0" width="640"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://www.slideshare.net/slideshow/dont-fear-map-grep-list-processing-for-fun-and-profit/252056897" rel="noopener noreferrer" class="c-link"&gt;
            Don’t Fear map &amp;amp; grep: List processing for fun and profit | PPTX
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            The document discusses the use of 'map' and 'grep' in Perl for processing lists and arrays, highlighting their ability to simplify code and improve readability compared to traditional loops. It provides examples of how to transform and filter lists using these functions, emphasizing the importance of avoiding side effects. The author also suggests refactoring code for better clarity and efficiency when dealing with list processing. - Download as a PPTX, PDF or view online for free
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpublic.slidesharecdn.com%2F_next%2Fstatic%2Fmedia%2Ffavicon-v2.259c72c8.png" width="96" height="96"&gt;
          slideshare.net
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;I’ve written much about &lt;a href="https://phoenixtrap.com/tags/lists" rel="noopener noreferrer"&gt;list processing in Perl&lt;/a&gt;, and this talk was based on the following blog posts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://phoenixtrap.com/2021/03/16/perl_map_grep/" rel="noopener noreferrer"&gt;Better Perl: Using &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;grep&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://phoenixtrap.com/2021/10/26/better-perl-four-list-processing-best-practices-with-map-grep-and-more/" rel="noopener noreferrer"&gt;Better Perl: Four list processing best practices with &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;grep&lt;/code&gt;, and more&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://phoenixtrap.com/2022/02/10/perl-list-processing-is-for-hashes-too/" rel="noopener noreferrer"&gt;Perl list processing is for hashes, too&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://phoenixtrap.com/2021/05/18/a-list-of-perl-list-processing-modules/" rel="noopener noreferrer"&gt;A list of Perl list processing modules&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Overall I loved attending the conference, and it really invigorated my participation in the Perl community. Stay tuned as I resume regular posting!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Cover image: "&lt;a href="https://www.flickr.com/photos/52887415@N00/5863092970" rel="noopener noreferrer"&gt;shopping list&lt;/a&gt;" by &lt;a href="https://www.flickr.com/photos/52887415@N00" rel="noopener noreferrer"&gt;Ex-Smith&lt;/a&gt; is licensed under &lt;a href="https://creativecommons.org/licenses/by-sa/2.0/?ref=openverse" rel="noopener noreferrer"&gt;CC BY-SA 2.0&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>perl</category>
      <category>map</category>
      <category>grep</category>
      <category>video</category>
    </item>
    <item>
      <title>How much is that BLÅHAJ in the (terminal) window?</title>
      <dc:creator>Mark Gardner</dc:creator>
      <pubDate>Tue, 12 Apr 2022 14:00:00 +0000</pubDate>
      <link>https://dev.to/mjgardner/how-much-is-that-blahaj-in-the-terminal-window-2fh5</link>
      <guid>https://dev.to/mjgardner/how-much-is-that-blahaj-in-the-terminal-window-2fh5</guid>
      <description>&lt;p&gt;&lt;a href="https://www.ikea.com/us/en/p/blahaj-soft-toy-shark-90373590/" rel="noopener noreferrer"&gt;IKEA’s toy BLÅHAJ shark&lt;/a&gt; has become a &lt;a href="https://knowyourmeme.com/memes/subcultures/ikea-blahaj-shark" rel="noopener noreferrer"&gt;beloved Internet icon&lt;/a&gt; over the past several years. I thought it might be cute to write a little Perl to get info about it and even display a cuddly picture right in the terminal where I’m running the code. Maybe this will give you some ideas for your own quick web clients. Of course, you could accomplish all of these things using a pipeline of individual command-line utilities like &lt;a href="https://curl.se/" rel="noopener noreferrer"&gt;&lt;code&gt;curl&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://stedolan.github.io/jq/" rel="noopener noreferrer"&gt;&lt;code&gt;jq&lt;/code&gt;&lt;/a&gt;, and &lt;a href="http://www.gnu.org/software/coreutils/" rel="noopener noreferrer"&gt;GNU coreutils&lt;/a&gt;’ &lt;a href="https://www.gnu.org/software/coreutils/manual/html_node/base64-invocation.html" rel="noopener noreferrer"&gt;&lt;code&gt;base64&lt;/code&gt;&lt;/a&gt;. These examples focus on &lt;a href="https://perldoc.perl.org/perlglossary#glue-language" rel="noopener noreferrer"&gt;Perl as the glue&lt;/a&gt;, though.&lt;/p&gt;

&lt;h2&gt;
  
  
  Warning: dodgy API ahead
&lt;/h2&gt;

&lt;p&gt;I haven’t found a publicly-documented and ‑supported official API for querying IKEA product information but &lt;a href="https://towardsdatascience.com/a-single-line-of-python-code-scraping-dataset-from-webpages-c9d2a8805d61" rel="noopener noreferrer"&gt;others&lt;/a&gt; &lt;a href="https://pypi.org/project/ikea-api/" rel="noopener noreferrer"&gt;have&lt;/a&gt; deconstructed the company’s web site &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Guide/AJAX" rel="noopener noreferrer"&gt;AJAX&lt;/a&gt; requests so we can use that instead. The alternative would be to scrape the IKEA web site directly which, although possible, would be more tedious and prone to failure should their design change. An unofficial API is also unreliable but the simpler client code is easier to change should any errors surface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enter the &lt;a href="https://mojolicious.org/" rel="noopener noreferrer"&gt;Mojolicious&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;My original goal was to do this in a &lt;a href="https://perldoc.perl.org/perlglossary#one-liner" rel="noopener noreferrer"&gt;single line issued to the &lt;code&gt;perl&lt;/code&gt; command&lt;/a&gt;, and luckily the &lt;a href="https://docs.mojolicious.org/ojo" rel="noopener noreferrer"&gt;Mojolicious framework’s ojo module&lt;/a&gt; is tailor-made for such things. By adding a &lt;code&gt;-Mojo&lt;/code&gt; switch to the &lt;code&gt;perl&lt;/code&gt; command, you get over a dozen quick single-character functions for spinning up a quick web application or, in our case, making and interpreting web requests without a lot of ceremony. Here’s the start of my one-line request to the IKEA API for information on their BLÅHAJ product, using &lt;a href="https://docs.mojolicious.org/ojo#g" rel="noopener noreferrer"&gt;ojo’s &lt;code&gt;g&lt;/code&gt; function&lt;/a&gt; to perform an HTTP GET and displaying the &lt;a href="https://json.org" rel="noopener noreferrer"&gt;JSON&lt;/a&gt; from the response body to the terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;perl &lt;span class="nt"&gt;-Mojo&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'say g("https://sik.search.blue.cdtapps.com/us/en/search-result-page",
  form =&amp;gt; {types =&amp;gt; "PRODUCT", q =&amp;gt; "BLÅHAJ"})-&amp;gt;body'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This currently returns over 2,400 lines of data, so after reading it over I’ll convert the response body JSON to a &lt;a href="https://perldoc.perl.org/perldsc" rel="noopener noreferrer"&gt;Perl data structure&lt;/a&gt; and dump only the main product information using &lt;a href="https://metacpan.org/pod/ojo#r" rel="noopener noreferrer"&gt;ojo’s &lt;code&gt;r&lt;/code&gt; function&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;perl &lt;span class="nt"&gt;-Mojo&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'say r g("https://sik.search.blue.cdtapps.com/us/en/search-result-page",
  form =&amp;gt; {types =&amp;gt; "PRODUCT", q =&amp;gt; "BLÅHAJ"})
  -&amp;gt;json-&amp;gt;{searchResultPage}{products}{main}{items}[0]{product}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"availability"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"breathTaking"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;bless(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;do&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;\(my&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$o&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'JSON::PP::Boolean'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"colors"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"hex"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0058a3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"id"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10007&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"name"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"blue"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"hex"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ffffff"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"id"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10156&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"name"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"white"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"contextualImageUrl"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://www.ikea.com/us/en/images/products/blahaj-soft-toy-shark__0877371_pe633608_s5.jpg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"currencyCode"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"discount"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"features"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"gprDescription"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"numberOfVariants"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"variants"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"id"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;90373590&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"itemMeasureReferenceText"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"39 &lt;/span&gt;&lt;span class="se"&gt;\x&lt;/span&gt;&lt;span class="s2"&gt;{bc} &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"itemNo"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;90373590&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"itemNoGlobal"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30373588&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"itemType"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ART"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"lastChance"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$VAR&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"breathTaking"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"mainImageAlt"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BL&lt;/span&gt;&lt;span class="se"&gt;\x&lt;/span&gt;&lt;span class="s2"&gt;{c5}HAJ Soft toy, shark, 39 &lt;/span&gt;&lt;span class="se"&gt;\x&lt;/span&gt;&lt;span class="s2"&gt;{bc} &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"mainImageUrl"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://www.ikea.com/us/en/images/products/blahaj-soft-toy-shark__0710175_pe727378_s5.jpg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"name"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"BL&lt;/span&gt;&lt;span class="se"&gt;\x&lt;/span&gt;&lt;span class="s2"&gt;{c5}HAJ"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"onlineSellable"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;bless(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;do&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;\(my&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$o&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'JSON::PP::Boolean'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"pipUrl"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://www.ikea.com/us/en/p/blahaj-soft-toy-shark-90373590/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"price"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"decimals"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;99&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"isRegularCurrency"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$VAR&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"breathTaking"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"prefix"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\$&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"separator"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"suffix"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"wholeNumber"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"priceNumeral"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"19.99"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"quickFacts"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"tag"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NONE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="s2"&gt;"typeName"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Soft toy"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If I just want the price I can do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ perl -Mojo -E 'say g("https://sik.search.blue.cdtapps.com/us/en/search-result-page",
  form =&amp;gt; {types =&amp;gt; "PRODUCT", q =&amp;gt; "BLÅHAJ"})-&amp;gt;json
  -&amp;gt;{searchResultPage}{products}{main}{items}[0]{product}
  -&amp;gt;@{qw(currencyCode priceNumeral)}'
USD19.99
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;-&amp;gt;@{qw(currencyCode priceNumeral)}&lt;/code&gt; towards the end uses the &lt;a href="https://perldoc.perl.org/perlref#Postfix-Reference-Slicing" rel="noopener noreferrer"&gt;postfix reference slicing syntax&lt;/a&gt; introduced &lt;a href="https://perldoc.perl.org/perl5200delta#Experimental-Postfix-Dereferencing" rel="noopener noreferrer"&gt;experimentally in Perl v5.20&lt;/a&gt; and &lt;a href="https://perldoc.perl.org/perl5240delta#Postfix-dereferencing-is-no-longer-experimental" rel="noopener noreferrer"&gt;made official in v5.24&lt;/a&gt;. If you’re using an older &lt;code&gt;perl&lt;/code&gt;, you’d say:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ perl -Mojo -E 'say @{g("https://sik.search.blue.cdtapps.com/us/en/search-result-page",
  form =&amp;gt; {types =&amp;gt; "PRODUCT", q =&amp;gt; "BLÅHAJ"})-&amp;gt;json
  -&amp;gt;{searchResultPage}{products}{main}{items}[0]{product}}{qw(currencyCode priceNumeral)}'
USD19.99
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I prefer the former, though, because it’s easier to read left-to-right.&lt;/p&gt;

&lt;h2&gt;
  
  
  But I’m not in the United States! Where’s my native currency?
&lt;/h2&gt;

&lt;p&gt;You can either replace the ”&lt;code&gt;us/en&lt;/code&gt;” in the URL above or use the &lt;a href="https://perldoc.perl.org/I18N::LangTags::Detect" rel="noopener noreferrer"&gt;core I18N::LangTags::Detect module&lt;/a&gt; added in Perl v5.8.5 if you’re really determined to be portable across different users’ locales. This is really stretching &lt;a href="https://en.wikipedia.org/wiki/One-liner_program" rel="noopener noreferrer"&gt;the definition of ”one-liner,”&lt;/a&gt; though.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ LANG=de_DE.UTF-8 perl -Mojo -MI18N::LangTags::Detect \
  -E 'my @lang = (split /-/, I18N::LangTags::Detect::detect)[1,0];
  say g("https://sik.search.blue.cdtapps.com/"
  . join("/", @lang == 2 ? @lang : ("us", "en"))
  . "/search-result-page",
  form =&amp;gt; {types =&amp;gt; "PRODUCT", q =&amp;gt; "BLÅHAJ"})-&amp;gt;json
  -&amp;gt;{searchResultPage}{products}{main}{items}[0]{product}
  -&amp;gt;@{qw(currencyCode priceNumeral)}'
EUR27.99
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Window dressing
&lt;/h2&gt;

&lt;p&gt;It’s hard to envision cuddling a number, but luckily the product information returned above links to a JPEG file in the &lt;code&gt;mainImageUrl&lt;/code&gt; key. My favorite terminal app &lt;a href="https://iterm2.com/documentation-images.html" rel="noopener noreferrer"&gt;iTerm2 can display images inline&lt;/a&gt; from either a file or &lt;a href="https://en.wikipedia.org/wiki/Base64" rel="noopener noreferrer"&gt;Base64&lt;/a&gt; encoded data, so adding an extra HTTP request and &lt;a href="https://perldoc.perl.org/MIME::Base64#encode_base64(-%24bytes-)" rel="noopener noreferrer"&gt;encoding from the core MIME::Base64 module&lt;/a&gt; yields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;perl &lt;span class="nt"&gt;-Mojo&lt;/span&gt; &lt;span class="nt"&gt;-MMIME&lt;/span&gt;::Base64 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'say "\c[]1337;File=inline=1;width=100%:",
  encode_base64(g(g("https://sik.search.blue.cdtapps.com/us/en/search-result-page",
  form =&amp;gt; {types =&amp;gt; "PRODUCT", q =&amp;gt; "BLÅHAJ"})-&amp;gt;json
  -&amp;gt;{searchResultPage}{products}{main}{items}[0]{product}{mainImageUrl})-&amp;gt;body),
  "\cG"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz235mwlom3n9l7w4kggv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz235mwlom3n9l7w4kggv.png" alt="Terminal window with a perl one-liner that shows an IKEA BLÅHAJ toy shark" width="800" height="873"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(You could just send the image URL to &lt;a href="https://iterm2.com/documentation-utilities.html" rel="noopener noreferrer"&gt;iTerm2’s bundled &lt;code&gt;imgcat&lt;/code&gt; utility&lt;/a&gt;, but where’s the fun in that?)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;imgcat &lt;span class="nt"&gt;--url&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;perl &lt;span class="nt"&gt;-Mojo&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'print g("https://sik.search.blue.cdtapps.com/us/en/search-result-page",
  form =&amp;gt; {types =&amp;gt; "PRODUCT", q =&amp;gt; "BLÅHAJ"})-&amp;gt;json
  -&amp;gt;{searchResultPage}{products}{main}{items}[0]{product}{mainImageUrl}'&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  But I don’t have iTerm2 or a Mac!
&lt;/h2&gt;

&lt;p&gt;I got you. At the expense of a number of other dependencies, here’s a version that will work on any terminal that supports &lt;a href="https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit" rel="noopener noreferrer"&gt;256-color mode with ANSI codes&lt;/a&gt; using &lt;a href="https://metacpan.org/pod/Image::Term256Color" rel="noopener noreferrer"&gt;Image::Term256Color from CPAN&lt;/a&gt; and a Unicode font with &lt;a href="https://en.wikipedia.org/wiki/Block_Elements?wprov=sfti1" rel="noopener noreferrer"&gt;block characters&lt;/a&gt;. I’ll also use &lt;a href="https://metacpan.org/pod/Term::ReadKey" rel="noopener noreferrer"&gt;Term::ReadKey&lt;/a&gt; to size the image for the width of your window. (Again, this stretches the definition of “one-liner.”)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;perl &lt;span class="nt"&gt;-Mojo&lt;/span&gt; &lt;span class="nt"&gt;-MImage&lt;/span&gt;::Term256Color &lt;span class="nt"&gt;-MTerm&lt;/span&gt;::ReadKey &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'say for Image::Term256Color::convert(g(g("https://sik.search.blue.cdtapps.com/us/en/search-result-page",
  form =&amp;gt; {types =&amp;gt; "PRODUCT", q =&amp;gt; "BLÅHAJ"})-&amp;gt;json
  -&amp;gt;{searchResultPage}{products}{main}{items}[0]{product}{mainImageUrl})-&amp;gt;body,
  {scale_x =&amp;gt; (GetTerminalSize)[0], utf8 =&amp;gt; 1})'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fexbeqcmm3hwlg0hpobj3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fexbeqcmm3hwlg0hpobj3.png" alt="Terminal window with a perl one-liner that shows an IKEA BLÅHAJ toy shark as jaggy ANSI graphics" width="800" height="929"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  I hate Mojolicious! Can’t you just use core modules?
&lt;/h2&gt;

&lt;p&gt;Fine. Here’s retrieving the product price using &lt;a href="https://perldoc.perl.org/HTTP::Tiny" rel="noopener noreferrer"&gt;HTTP::Tiny&lt;/a&gt; and the pure-Perl JSON parser &lt;a href="https://perldoc.perl.org/JSON::PP" rel="noopener noreferrer"&gt;JSON::PP&lt;/a&gt;, which were &lt;a href="https://perldoc.perl.org/perl5140delta#New-Modules-and-Pragmata" rel="noopener noreferrer"&gt;added to core in version 5.14&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 -MHTTP::Tiny -MJSON::PP \
  -E 'say @{decode_json(HTTP::Tiny-&amp;gt;new-&amp;gt;get("https://sik.search.blue.cdtapps.com/us/en/search-result-page?types=PRODUCT&amp;amp;q=BLÅHAJ")
  -&amp;gt;{content})
  -&amp;gt;{searchResultPage}{products}{main}{items}[0]{product}}{qw(currencyCode priceNumeral)}'
USD19.99
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fetching and displaying a picture of the huggable shark using MIME::Base64 or Image::Term256Color as above is left as an exercise to the reader.&lt;/p&gt;

</description>
      <category>perl</category>
      <category>webdev</category>
      <category>api</category>
      <category>mojolicious</category>
    </item>
    <item>
      <title>Perl list processing is for hashes, too</title>
      <dc:creator>Mark Gardner</dc:creator>
      <pubDate>Thu, 10 Feb 2022 15:00:00 +0000</pubDate>
      <link>https://dev.to/mjgardner/perl-list-processing-is-for-hashes-too-2ol8</link>
      <guid>https://dev.to/mjgardner/perl-list-processing-is-for-hashes-too-2ol8</guid>
      <description>&lt;p&gt;This month I started a new job at &lt;a href="https://www.alertlogic.com/" rel="noopener noreferrer"&gt;Alert Logic&lt;/a&gt;, a cybersecurity provider with Perl (among many other things) at its beating heart. I’ve been learning a lot, and part of the process has been understanding the APIs in the code base. To that end, I’ve been writing small test scripts to tease apart data structures, using Perl &lt;a href="https://perldoc.perl.org/perlfunc#Functions-for-real-@ARRAYs" rel="noopener noreferrer"&gt;array-processing&lt;/a&gt;, &lt;a href="https://perldoc.perl.org/perlfunc#Functions-for-list-data" rel="noopener noreferrer"&gt;list-processing&lt;/a&gt;, and &lt;a href="https://perldoc.perl.org/perlfunc#Functions-for-real-%25HASHes" rel="noopener noreferrer"&gt;hash- (i.e., associative array)-processing functions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I’ve covered &lt;code&gt;map&lt;/code&gt;, &lt;code&gt;grep&lt;/code&gt;, and friends a &lt;a href="https://phoenixtrap.com/2021/03/16/perl_map_grep/" rel="noopener noreferrer"&gt;couple&lt;/a&gt; &lt;a href="https://phoenixtrap.com/2021/10/26/better-perl-four-list-processing-best-practices-with-map-grep-and-more/" rel="noopener noreferrer"&gt;times&lt;/a&gt; before. &lt;a href="https://phoenixtrap.com/2021/10/26/better-perl-four-list-processing-best-practices-with-map-grep-and-more/" rel="noopener noreferrer"&gt;Most recently&lt;/a&gt;, I described using &lt;a href="https://perldoc.perl.org/List::Util#any" rel="noopener noreferrer"&gt;List::Util’s &lt;code&gt;any&lt;/code&gt; function&lt;/a&gt; to check if a condition is true for any item in a list. In the simplest case, you can use it to check to see if a given value is in the list at all:&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;feature&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;say&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;List::&lt;/span&gt;&lt;span class="nv"&gt;Util&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;any&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;@colors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="sx"&gt;qw(red orange yellow green blue indigo violet)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;matched&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;any&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="sr"&gt;/^red$/&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;@colors&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, if you’re going to be doing this a lot with arbitrary strings, &lt;a href="https://perldoc.perl.org/perlfaq4#How-can-I-tell-whether-a-certain-element-is-contained-in-a-list-or-array?" rel="noopener noreferrer"&gt;Perl FAQ section 4 advises&lt;/a&gt; turning the array into the keys of a hash and then checking for membership there. For example, here’s a simple script to check if the colors input (either from the keyboard or from files passed as arguments) are in the rainbow:&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;v5&lt;/span&gt;&lt;span class="mf"&gt;.22&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# introduced &amp;lt;&amp;lt;&amp;gt;&amp;gt; for safe opening of arguments&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;%in_colors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="vg"&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="sx"&gt;qw(red orange yellow green blue indigo violet)&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="o"&gt;&amp;lt;&amp;lt;&amp;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="nb"&gt;chomp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$_&lt;/span&gt;&lt;span class="s2"&gt; is in the rainbow&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;$in_colors&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="vg"&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;List::Util has a &lt;a href="https://perldoc.perl.org/List::Util#KEY/VALUE-PAIR-LIST-FUNCTIONS" rel="noopener noreferrer"&gt;bunch of functions for processing lists of pairs&lt;/a&gt; that I’ve found useful when pawing through hashes. &lt;code&gt;pairgrep&lt;/code&gt;, for example, acts just like &lt;code&gt;grep&lt;/code&gt; but instead assigns &lt;code&gt;$a&lt;/code&gt; and &lt;code&gt;$b&lt;/code&gt; to each key and value passed in and returns the resulting pairs that match. I’ve used it as a quick way to search for hash entries matching certain value conditions:&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;List::&lt;/span&gt;&lt;span class="nv"&gt;Util&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pairgrep&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;%numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;zero&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;one&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="s"&gt;two&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="s"&gt;three&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;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;%odds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;pairgrep&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$b&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;%numbers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sure, you could do this by invoking a mix of plain &lt;code&gt;grep&lt;/code&gt;, &lt;code&gt;keys&lt;/code&gt;, and a &lt;a href="https://perldoc.perl.org/perldata#Key/Value-Hash-Slices" rel="noopener noreferrer"&gt;hash slice&lt;/a&gt;, but it’s noisier and more repetitive:&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;.20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# for key/value hash slice &lt;/span&gt;
&lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;%odds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;%numbers&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$numbers&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nb"&gt;keys&lt;/span&gt; &lt;span class="nv"&gt;%numbers&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;pairgrep&lt;/code&gt;’s compiled C‑based &lt;a href="https://perldoc.perl.org/perlxs" rel="noopener noreferrer"&gt;XS&lt;/a&gt; code can also be faster, as evidenced by this &lt;a href="https://perldoc.perl.org/Benchmark" rel="noopener noreferrer"&gt;Benchmark&lt;/a&gt; script that works through a hash made of the &lt;a href="https://en.wikipedia.org/wiki/Words_(Unix)" rel="noopener noreferrer"&gt;Unix &lt;code&gt;words&lt;/code&gt; file&lt;/a&gt; (479,828 entries on my machine):&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;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;warnings&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;List::&lt;/span&gt;&lt;span class="nv"&gt;Util&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pairgrep&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;Benchmark&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cmpthese&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;%words&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$count&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="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/usr/share/dict/words&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;can't open words: $!&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="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="nb"&gt;chomp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nv"&gt;$words&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$count&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="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="nv"&gt;cmpthese&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="s"&gt;grep&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;%odds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;%words&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$words&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nb"&gt;keys&lt;/span&gt; &lt;span class="nv"&gt;%words&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="s"&gt;pairgrep&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;%odds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;pairgrep&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$b&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;%words&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;p&gt;Benchmark output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;           Rate     grep pairgrep
grep     1.47/s       --     -20%
pairgrep 1.84/s      25%       --
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;In general, I urge you to work through the &lt;a href="https://phoenixtrap.com/2021/10/12/read-the-fantastic-manual-how-to-get-the-most-out-of-perl-documentation/" rel="noopener noreferrer"&gt;Perl documentation&lt;/a&gt;’s tutorials on &lt;a href="https://perldoc.perl.org/perlreftut" rel="noopener noreferrer"&gt;references&lt;/a&gt;, &lt;a href="https://perldoc.perl.org/perllol" rel="noopener noreferrer"&gt;lists of lists&lt;/a&gt;, the &lt;a href="https://perldoc.perl.org/perldsc" rel="noopener noreferrer"&gt;data structures cookbook&lt;/a&gt;, and the FAQs on &lt;a href="https://perldoc.perl.org/perlfaq4#Data:-Arrays" rel="noopener noreferrer"&gt;array&lt;/a&gt; and &lt;a href="https://perldoc.perl.org/perlfaq4#Data:-Hashes-(Associative-Arrays)" rel="noopener noreferrer"&gt;hash manipulation&lt;/a&gt;. Then dip into the various &lt;a href="https://phoenixtrap.com/2021/05/18/a-list-of-perl-list-processing-modules/" rel="noopener noreferrer"&gt;list-processing modules&lt;/a&gt; (especially the included &lt;a href="https://perldoc.perl.org/List::Util" rel="noopener noreferrer"&gt;List::Util&lt;/a&gt; and CPAN’s &lt;a href="https://metacpan.org/pod/List::SomeUtils" rel="noopener noreferrer"&gt;List::SomeUtils&lt;/a&gt;) for ready-made functions for common operations. You’ll find a wealth of techniques for creating, managing, and processing the data structures that your programs need.&lt;/p&gt;

</description>
      <category>perl</category>
      <category>lists</category>
      <category>hashes</category>
      <category>map</category>
    </item>
    <item>
      <title>Get out early with Perl statement modifiers</title>
      <dc:creator>Mark Gardner</dc:creator>
      <pubDate>Wed, 19 Jan 2022 15:00:00 +0000</pubDate>
      <link>https://dev.to/mjgardner/get-out-early-with-perl-statement-modifiers-db1</link>
      <guid>https://dev.to/mjgardner/get-out-early-with-perl-statement-modifiers-db1</guid>
      <description>&lt;p&gt;When I first started writing Perl in my early 20’s, I tended to follow a lot of the &lt;a href="https://en.wikipedia.org/wiki/Structured_programming" rel="noopener noreferrer"&gt;structured programming&lt;/a&gt; conventions I had learned in school through &lt;a href="https://en.wikipedia.org/wiki/Pascal_(programming_language)" rel="noopener noreferrer"&gt;Pascal&lt;/a&gt;, especially the notion that every function has a &lt;a href="https://wiki.c2.com/?SingleFunctionExitPoint" rel="noopener noreferrer"&gt;single point of exit&lt;/a&gt;. For 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;sub &lt;/span&gt;&lt;span class="nf"&gt;double_even_number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;# not using signatures, this is mid-1990's code&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$number&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="ow"&gt;not&lt;/span&gt; &lt;span class="nv"&gt;$number&lt;/span&gt; &lt;span class="o"&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="nv"&gt;$number&lt;/span&gt; &lt;span class="o"&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="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$number&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 could get pretty convoluted, especially if I was doing something like validating multiple arguments. And at the time I didn’t yet grok how to handle &lt;a href="https://phoenixtrap.com/2021/02/22/exceptional-perl-failure-is-an-option/" rel="noopener noreferrer"&gt;exceptions&lt;/a&gt; with &lt;a href="https://perldoc.perl.org/functions/eval" rel="noopener noreferrer"&gt;&lt;code&gt;eval&lt;/code&gt;&lt;/a&gt; and &lt;code&gt;die&lt;/code&gt;, so I’d end up with code like:&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;print_postal_address&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;# too many arguments, I know&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;$name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$street1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$street2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$zip&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="c1"&gt;# also this notion of addresses is naive and US-centric&lt;/span&gt;

    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$error&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="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no name&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="si"&gt;$name&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$street1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no street&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="si"&gt;$street1&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$street2&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="si"&gt;$street2&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$city&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nv"&gt;$error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no city&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="si"&gt;$city&lt;/span&gt;&lt;span class="s2"&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="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nv"&gt;$error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no state&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="si"&gt;$state&lt;/span&gt;&lt;span class="s2"&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="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$zip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nv"&gt;$error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no ZIP code&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="si"&gt;$zip&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="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;return&lt;/span&gt; &lt;span class="nv"&gt;$error&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;What a mess. Want to count all those braces to make sure they’re balanced? This is sometimes called the &lt;a href="https://wiki.c2.com/?ArrowAntiPattern" rel="noopener noreferrer"&gt;arrow anti-pattern&lt;/a&gt;, with the arrowhead(s) being the most nested statement. The default &lt;a href="https://metacpan.org/pod/Perl::Critic::Policy::ControlStructures::ProhibitDeepNests" rel="noopener noreferrer"&gt;ProhibitDeepNests &lt;code&gt;perlcritic&lt;/code&gt; policy&lt;/a&gt; is meant to keep you from doing that.&lt;/p&gt;

&lt;p&gt;The way out (literally) is &lt;a href="https://wiki.c2.com/?GuardClause" rel="noopener noreferrer"&gt;guard clauses&lt;/a&gt;: checking early if something is valid and bailing out quickly if not. The above example could be written:&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;print_postal_address&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;$name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$street1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$street2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$zip&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$name&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="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no name&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="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$street1&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="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no street1&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="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$city&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="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no city&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="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$state&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="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no state&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="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$zip&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="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no zip&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="nb"&gt;join&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="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nv"&gt;$street1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nv"&gt;$street2&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nv"&gt;$street2&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;$city&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="si"&gt;$state&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;$zip&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With Perl’s &lt;a href="https://perldoc.perl.org/perlsyn#Statement-Modifiers" rel="noopener noreferrer"&gt;statement modifiers&lt;/a&gt; (sometimes called postfix controls) we can do even better:&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="o"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no name&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$name&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="s1"&gt;no street1&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$street1&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="s1"&gt;no city&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$city&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="s1"&gt;no state&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt;   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$state&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="s1"&gt;no zip&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt;     &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$zip&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Why &lt;code&gt;if&lt;/code&gt; instead of &lt;code&gt;unless&lt;/code&gt;? Because the latter &lt;a href="https://metacpan.org/pod/Perl::Critic::Policy::ControlStructures::ProhibitUnlessBlocks" rel="noopener noreferrer"&gt;can be confusing with double-negatives&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;Guard clauses aren’t limited to the beginnings of functions or even exiting functions entirely. Often you’ll want to skip or even exit early conditions in a loop, like this example that processes files from standard input or the command line:&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;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&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;next&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sr"&gt;/^SKIP THIS LINE: /&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;last&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sr"&gt;/^END THINGS HERE$/&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, if you are validating function arguments, you should consider using actual &lt;a href="https://perldoc.perl.org/perlsub#Signatures" rel="noopener noreferrer"&gt;subroutine signatures&lt;/a&gt; if you have a Perl newer than v5.20 (released in 2014), or one of the &lt;a href="https://phoenixtrap.com/2021/01/27/better-perl-with-subroutine-signatures-and-type-validation/" rel="noopener noreferrer"&gt;other type validation solutions&lt;/a&gt; if not. Today I would write that postal function like this, using &lt;a href="https://metacpan.org/pod/Type::Params" rel="noopener noreferrer"&gt;Type::Params&lt;/a&gt; for validation and 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;use&lt;/span&gt; &lt;span class="nv"&gt;feature&lt;/span&gt; &lt;span class="sx"&gt;qw(say state)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Types::&lt;/span&gt;&lt;span class="nv"&gt;Standard&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Str&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Type::&lt;/span&gt;&lt;span class="nv"&gt;Params&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;compile_named&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_postal_address&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;state&lt;/span&gt; &lt;span class="nv"&gt;$check&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;compile_named&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;name&lt;/span&gt;    &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;street1&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;street2&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;optional&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="s"&gt;city&lt;/span&gt;    &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;state&lt;/span&gt;   &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;zip&lt;/span&gt;     &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;Str&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;$arg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$check&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&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;say&lt;/span&gt; &lt;span class="nb"&gt;join&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="nv"&gt;$arg&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;name&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="nv"&gt;$arg&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;street1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="nv"&gt;$arg&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;street2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nv"&gt;$arg&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;street2&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="si"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;-&amp;gt;{city}, &lt;/span&gt;&lt;span class="si"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;-&amp;gt;{state} &lt;/span&gt;&lt;span class="si"&gt;$arg&lt;/span&gt;&lt;span class="s2"&gt;-&amp;gt;{zip}&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="p"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;print_postal_address&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;name&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;J. Random Hacker&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;
    &lt;span class="s"&gt;street1&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;123 Any Street&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;
    &lt;span class="s"&gt;city&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;Somewhereville&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;
    &lt;span class="s"&gt;state&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;TX&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;
    &lt;span class="s"&gt;zip&lt;/span&gt;     &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;12345&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;Note that was this part of a larger program, I’d wrap that &lt;code&gt;print_postal_address&lt;/code&gt; call in a &lt;a href="https://perldoc.perl.org/perlsyn#Try-Catch-Exception-Handling" rel="noopener noreferrer"&gt;&lt;code&gt;try&lt;/code&gt;&lt;/a&gt; block and &lt;code&gt;catch&lt;/code&gt; exceptions such as those thrown by the code reference &lt;code&gt;$check&lt;/code&gt; generated by &lt;a href="https://metacpan.org/pod/Type::Params#compile_named(@spec)" rel="noopener noreferrer"&gt;&lt;code&gt;compile_named&lt;/code&gt;&lt;/a&gt;. This highlights one concern of guard clauses and other &lt;a href="https://medium.com/swlh/return-early-pattern-3d18a41bba8" rel="noopener noreferrer"&gt;“return early” patterns&lt;/a&gt;: depending on how much has already occurred in your program, you may have to perform some resource cleanup either in a &lt;code&gt;catch&lt;/code&gt; block or something like &lt;a href="https://metacpan.org/pod/Syntax::Keyword::Try#finally" rel="noopener noreferrer"&gt;Syntax::Keyword::Try’s &lt;code&gt;finally&lt;/code&gt;&lt;/a&gt; block if you need to tidy up after both success and failure.&lt;/p&gt;

</description>
      <category>perl</category>
      <category>exceptions</category>
      <category>patterns</category>
      <category>antipatterns</category>
    </item>
    <item>
      <title>Highlighting members of the Perl family</title>
      <dc:creator>Mark Gardner</dc:creator>
      <pubDate>Tue, 11 Jan 2022 15:00:00 +0000</pubDate>
      <link>https://dev.to/mjgardner/highlighting-members-of-the-perl-family-1kgi</link>
      <guid>https://dev.to/mjgardner/highlighting-members-of-the-perl-family-1kgi</guid>
      <description>&lt;p&gt;This past year of &lt;a href="https://phoenixtrap.com/tag/perl" rel="noopener noreferrer"&gt;blogging&lt;/a&gt; has introduced me to a wide variety of people in the &lt;a href="https://www.perl.org/community.html" rel="noopener noreferrer"&gt;Perl community&lt;/a&gt;. Some I’ve admired from afar for years due to their published work, and even more I’ve “met” interacting on social media and other forums. So this will be the first in an occasional series highlighting not just the code, but the people that make up the Perl family.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="http://www.leonerd.org.uk/" rel="noopener noreferrer"&gt;Paul “LeoNerd” Evans&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I first came across Paul’s work during his series last year on &lt;a href="https://phoenixtrap.com/2021/02/01/paul-evans-writing-a-core-perl-feature/" rel="noopener noreferrer"&gt;writing a core Perl feature&lt;/a&gt;; he’s responsible for &lt;a href="https://perldoc.perl.org/perl5320delta#The-isa-Operator" rel="noopener noreferrer"&gt;Perl v5.32’s &lt;code&gt;isa&lt;/code&gt; operator&lt;/a&gt; and &lt;a href="https://perldoc.perl.org/perl5340delta#Experimental-Try/Catch-Syntax" rel="noopener noreferrer"&gt;v5.34’s experimental &lt;code&gt;try&lt;/code&gt;/&lt;code&gt;catch&lt;/code&gt; exception handling syntax&lt;/a&gt;. I &lt;a href="https://www.perl.com/article/interview-trying-to-catch-paul-leonerd-evans/" rel="noopener noreferrer"&gt;interviewed him about the latter&lt;/a&gt; for Perl.com in March 2021. He’s been &lt;a href="https://metacpan.org/author/PEVANS" rel="noopener noreferrer"&gt;active on CPAN&lt;/a&gt; for so much longer, though, and &lt;a href="https://www.nntp.perl.org/group/perl.perl5.porters/2021/07/msg260858.html" rel="noopener noreferrer"&gt;joined the Perl Steering Council in July&lt;/a&gt;. He’s also often a helpful voice on &lt;a href="https://web.libera.chat/#perl" rel="noopener noreferrer"&gt;IRC&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.urbanguitarlegend.com/" rel="noopener noreferrer"&gt;Elliot Holden&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Renowned author and trainer &lt;a href="http://www.stonehenge.com/merlyn/" rel="noopener noreferrer"&gt;Randal L. “merlyn” Schwartz&lt;/a&gt; linked over the weekend in a private Facebook group to Elliot’s impassioned &lt;a href="https://youtu.be/FQXjLG0DjPo" rel="noopener noreferrer"&gt;YouTube video about his day job as a Perl web application developer&lt;/a&gt;. Through his alter ego &lt;a href="https://www.urbanguitarlegend.com/" rel="noopener noreferrer"&gt;Urban Guitar Legend&lt;/a&gt; Elliot is also a passionate musician; besides gigging and recording he’s been &lt;a href="https://youtube.com/c/Urbanguitarlegend" rel="noopener noreferrer"&gt;posting videos for nine years&lt;/a&gt;. (I’m a bit envious since I took a break from &lt;a href="https://phoenixtrap.com/music/" rel="noopener noreferrer"&gt;music&lt;/a&gt; almost twenty years ago and haven’t managed to recapture it.) Elliot seems like the quintessential needs-to-get-shit-done developer, and Perl is perfect for that.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://szabgab.com" rel="noopener noreferrer"&gt;Gábor Szabó&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Gábor is a polyglot (both in human and computer languages) trainer, consultant, and author, writing about programming and devops on his &lt;a href="https://code-maven.com/" rel="noopener noreferrer"&gt;Code Maven&lt;/a&gt; and &lt;a href="https://perlmaven.com/" rel="noopener noreferrer"&gt;Perl Maven&lt;/a&gt; websites. He’s also the founder and co-editor of &lt;a href="https://perlweekly.com/" rel="noopener noreferrer"&gt;Perl Weekly&lt;/a&gt; and recipient of a &lt;a href="https://www.perl.org/advocacy/white_camel/2008.html" rel="noopener noreferrer"&gt;Perl White Camel award in 2008&lt;/a&gt; thanks to his organizational and support contributions. Last year he &lt;a href="https://perlmaven.com/course-management-app-in-mojolicious" rel="noopener noreferrer"&gt;introduced me to the world of live pair programming&lt;/a&gt;, working on a web application using the &lt;a href="https://mojolicious.org/" rel="noopener noreferrer"&gt;Mojolicious framework&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;If you’re on Twitter and looking to connect with other Perl developers, please consider participating in &lt;a href="https://twitter.com/i/communities/1471579416216145924" rel="noopener noreferrer"&gt;the Perl community&lt;/a&gt; I’ve set up there. &lt;a href="https://help.twitter.com/en/using-twitter/communities" rel="noopener noreferrer"&gt;Twitter Communities&lt;/a&gt; are topic-specific moderated discussion groups, unlike the freewheeling &lt;a href="https://help.twitter.com/en/using-twitter/how-to-use-hashtags" rel="noopener noreferrer"&gt;#hashtags&lt;/a&gt; system that can be diluted by spam or topics that share the same name. Unfortunately, they’re still read-only on the &lt;a href="https://play.google.com/store/apps/details?id=com.twitter.android" rel="noopener noreferrer"&gt;Twitter Android app&lt;/a&gt;, but you can participate fully on &lt;a href="https://apps.apple.com/us/app/twitter/id333903271" rel="noopener noreferrer"&gt;iOS/iPadOS&lt;/a&gt; and &lt;a href="https://twitter.com" rel="noopener noreferrer"&gt;the website&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>perl</category>
      <category>community</category>
      <category>cpan</category>
      <category>twitter</category>
    </item>
    <item>
      <title>Perl warnings and the warn function</title>
      <dc:creator>Mark Gardner</dc:creator>
      <pubDate>Tue, 04 Jan 2022 15:00:00 +0000</pubDate>
      <link>https://dev.to/mjgardner/perl-warnings-and-the-warn-function-777</link>
      <guid>https://dev.to/mjgardner/perl-warnings-and-the-warn-function-777</guid>
      <description>&lt;p&gt;I mentioned in passing &lt;a href="https://phoenixtrap.com/2021/12/28/avoid-yoda-conditions-in-perl-you-should/" rel="noopener noreferrer"&gt;last week&lt;/a&gt; that the next major release of Perl, v5.36, is set to enable &lt;a href="https://perldoc.perl.org/warnings" rel="noopener noreferrer"&gt;&lt;code&gt;warnings&lt;/code&gt;&lt;/a&gt; by default &lt;a href="https://metacpan.org/release/NEILB/perl-5.35.7/view/pod/perl5353delta.pod#Core-Enhancements" rel="noopener noreferrer"&gt;for code that opts in to &lt;code&gt;use v5.35;&lt;/code&gt; or above&lt;/a&gt;. Commemorating Perl’s 34th birthday &lt;a href="https://phoenixtrap.com/2021/12/21/34-at-34-for-v5-34-modern-perl-features-for-perls-birthday/" rel="noopener noreferrer"&gt;the week before that&lt;/a&gt;, I noted that the &lt;a href="https://phoenixtrap.com/2021/12/21/34-at-34-for-v5-34-modern-perl-features-for-perls-birthday/" rel="noopener noreferrer"&gt;warnings system has been getting ever finer-grained&lt;/a&gt; since its introduction in 2000. And fellow Perl blogger and &lt;a href="https://metacpan.org/author/WYANT" rel="noopener noreferrer"&gt;CPAN author Tom Wyant&lt;/a&gt; has been cataloging his favorites over the past several months—the latest as of this writing was &lt;a href="http://blogs.perl.org/users/tom_wyant/2021/12/my-favorite-warnings-ambiguous.html" rel="noopener noreferrer"&gt;on the “ambiguous” category of warnings&lt;/a&gt;, and you can find links to previous entries in his series at the bottom of that post.&lt;/p&gt;

&lt;p&gt;It occurred to me afterward that there may be some confusion between the &lt;code&gt;warnings&lt;/code&gt; pragma and the related &lt;a href="https://perldoc.perl.org/functions/warn" rel="noopener noreferrer"&gt;&lt;code&gt;warn&lt;/code&gt; function&lt;/a&gt; for reporting arbitrary runtime errors. &lt;code&gt;warn&lt;/code&gt; outputs its arguments to the &lt;a href="https://perldoc.perl.org/perlglossary#standard-error" rel="noopener noreferrer"&gt;standard error (&lt;code&gt;STDERR&lt;/code&gt;) stream&lt;/a&gt;, or if it’s not given any then you get a string with any exception from &lt;code&gt;$@&lt;/code&gt; (&lt;code&gt;$EVAL_ERROR&lt;/code&gt; under &lt;code&gt;use English&lt;/code&gt;) followed by a tab and then “&lt;code&gt;...caught at &amp;lt;file&amp;gt; line x.&lt;/code&gt;” If that’s empty too, a plain &lt;code&gt;warn&lt;/code&gt; just says, “&lt;code&gt;Warning: something's wrong at &amp;lt;file&amp;gt; line x.&lt;/code&gt;”, which isn’t exactly helpful, but then again you didn’t give it much to go on.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;warn&lt;/code&gt; output doesn’t have to go to &lt;code&gt;STDERR&lt;/code&gt;, and this is where the relation to the warnings pragma comes in because both are governed by the &lt;code&gt;__WARN__&lt;/code&gt; signal handler in the &lt;a href="https://perldoc.perl.org/variables/%25SIG" rel="noopener noreferrer"&gt;&lt;code&gt;%SIG&lt;/code&gt; hash&lt;/a&gt;. Normally, you might opt to only display runtime warnings if a debugging flag is set, like so:&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;$DEBUG&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="nv"&gt;$SIG&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="bp"&gt;__WARN__&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&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;warn&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$DEBUG&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nb"&gt;warn&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;shhh&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt; &lt;span class="c1"&gt;# silenced&lt;/span&gt;

&lt;span class="nv"&gt;$DEBUG&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="nb"&gt;warn&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello warnings&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But if you set that signal handler in a &lt;code&gt;BEGIN&lt;/code&gt; block, it catches compile-time warnings too, in which case flipping a flag after the fact has no effect—the compiler’s already run:&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;$DEBUG&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;BEGIN&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$SIG&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="bp"&gt;__WARN__&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&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;warn&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$DEBUG&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;$foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&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;$foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;world&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt; &lt;span class="c1"&gt;# no warning issued here&lt;/span&gt;

&lt;span class="nv"&gt;$DEBUG&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;my&lt;/span&gt; &lt;span class="nv"&gt;$foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;howdy&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt; &lt;span class="c1"&gt;# still nothing&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By the way, both &lt;code&gt;__WARN__&lt;/code&gt; and &lt;code&gt;__DIE__&lt;/code&gt; hooks are also used by the &lt;a href="https://perldoc.perl.org/Carp" rel="noopener noreferrer"&gt;Carp module&lt;/a&gt; and its friends, so you can use the same technique with their enhanced output:&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;use&lt;/span&gt; &lt;span class="nv"&gt;Carp&lt;/span&gt; &lt;span class="sx"&gt;qw(carp cluck)&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;$DEBUG&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;BEGIN&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$SIG&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="bp"&gt;__WARN__&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&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;warn&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$DEBUG&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&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;quiet fish&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;

&lt;span class="nv"&gt;$DEBUG&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="nv"&gt;loud_chicken&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;loud_chicken&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;cluck&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;here comes a stack trace&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;You &lt;em&gt;could&lt;/em&gt; use these as stepping stones towards a debug log for larger applications, but at that point, I’d suggest looking into one of the logging modules on CPAN like &lt;a href="https://metacpan.org/pod/Log::Log4perl" rel="noopener noreferrer"&gt;Log::Log4perl&lt;/a&gt; (not to be confused with that &lt;a href="https://phoenixtrap.com/2021/12/14/a-brief-note-on-log4perl/" rel="noopener noreferrer"&gt;lately-problematic Java library&lt;/a&gt;), &lt;a href="https://metacpan.org/pod/Log::Dispatch" rel="noopener noreferrer"&gt;Log::Dispatch&lt;/a&gt; (which can be &lt;a href="https://metacpan.org/pod/Log::Log4perl#Additional-Appenders-via-Log::Dispatch" rel="noopener noreferrer"&gt;wired into Log4perl&lt;/a&gt;), or &lt;a href="https://metacpan.org/pod/Task::Kensho::Logging" rel="noopener noreferrer"&gt;something else&lt;/a&gt; to suit your needs.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Cover image: &lt;a href="https://www.flickr.com/photos/38834306@N00/2049428733" rel="noopener noreferrer"&gt;"Warning!"&lt;/a&gt; by &lt;a href="https://www.flickr.com/photos/38834306@N00" rel="noopener noreferrer"&gt;John Goodridge&lt;/a&gt; is licensed under &lt;a href="https://creativecommons.org/licenses/by-nc-sa/2.0/?ref=openverse&amp;amp;atype=html" rel="noopener noreferrer"&gt;CC BY-NC-SA 2.0&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>perl</category>
      <category>warnings</category>
      <category>logging</category>
    </item>
    <item>
      <title>Avoid Yoda conditions in Perl you should</title>
      <dc:creator>Mark Gardner</dc:creator>
      <pubDate>Tue, 28 Dec 2021 15:00:00 +0000</pubDate>
      <link>https://dev.to/mjgardner/avoid-yoda-conditions-in-perl-you-should-o0j</link>
      <guid>https://dev.to/mjgardner/avoid-yoda-conditions-in-perl-you-should-o0j</guid>
      <description>&lt;p&gt;I remember a brief time in the mid-2000s insisting on so-called &lt;a href="https://en.wikipedia.org/wiki/Yoda_conditions" rel="noopener noreferrer"&gt;“Yoda conditions”&lt;/a&gt; in my Perl. I would place constants to the left of &lt;a href="https://perldoc.perl.org/perlop#Equality-Operators" rel="noopener noreferrer"&gt;equality comparisons&lt;/a&gt;. In case I accidentally typed a single &lt;code&gt;=&lt;/code&gt; instead of &lt;code&gt;==&lt;/code&gt;, the compiler would catch it instead of blithely &lt;a href="https://perldoc.perl.org/perlop#Assignment-Operators" rel="noopener noreferrer"&gt;assigning&lt;/a&gt; a variable. E.g.:&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="nv"&gt;$foo&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt; &lt;span class="p"&gt;)&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="c1"&gt;# don’t do this&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt; &lt;span class="o"&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="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;# do this&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;$foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;  &lt;span class="p"&gt;)&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="c1"&gt;# to prevent this&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And because &lt;a href="https://www.goodreads.com/quotes/353571" rel="noopener noreferrer"&gt;a foolish consistency is the hobgoblin of little minds&lt;/a&gt;, I would even extend this to string and relational comparisons.&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="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="ow"&gt;eq&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="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;# weirdo&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt; &lt;span class="o"&gt;&amp;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="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;# make it stop&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It looks weird, and it turns out it’s unnecessary as long as you precede your code with &lt;code&gt;use warnings;&lt;/code&gt;. Perl will then &lt;a href="https://perldoc.perl.org/perldiag#Found-=-in-conditional,-should-be-==" rel="noopener noreferrer"&gt;warn you&lt;/a&gt;: “&lt;code&gt;Found = in conditional, should be ==&lt;/code&gt;“. (Sidenote: Perl v5.36, due in mid-2022, is &lt;a href="https://metacpan.org/release/ETHER/perl-5.35.3/view/pod/perldelta.pod#Core-Enhancements" rel="noopener noreferrer"&gt;slated to enable warnings by default&lt;/a&gt; if you do &lt;code&gt;use v5.35;&lt;/code&gt; or above, in addition to the strictness that &lt;a href="https://perldoc.perl.org/perl5120delta#Implicit-strictures" rel="noopener noreferrer"&gt;was enabled with &lt;code&gt;use v5.11;&lt;/code&gt;&lt;/a&gt;. Yay for less boilerplate!)&lt;/p&gt;

&lt;p&gt;If you want to fatally catch this and many other warnings, use the &lt;a href="https://metacpan.org/pod/strictures" rel="noopener noreferrer"&gt;strictures module from CPAN&lt;/a&gt; in your code 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;use&lt;/span&gt; &lt;span class="nv"&gt;strictures&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will cause your code to throw an &lt;a href="https://phoenixtrap.com/2021/02/22/exceptional-perl-failure-is-an-option/" rel="noopener noreferrer"&gt;exception&lt;/a&gt; if it commits many &lt;a href="https://perldoc.perl.org/warnings#Category-Hierarchy" rel="noopener noreferrer"&gt;categories&lt;/a&gt; of mistakes. If you’re running in a version control system’s working directory (specifically &lt;a href="https://git-scm.com/" rel="noopener noreferrer"&gt;Git&lt;/a&gt;, &lt;a href="https://subversion.apache.org/" rel="noopener noreferrer"&gt;Subversion&lt;/a&gt;, &lt;a href="https://www.mercurial-scm.org/" rel="noopener noreferrer"&gt;Mercurial&lt;/a&gt;, or &lt;a href="https://bazaar.canonical.com/" rel="noopener noreferrer"&gt;Bazaar&lt;/a&gt;), the module also prevents you from using &lt;a href="https://perldoc.perl.org/perlobj#Indirect-Object-Syntax" rel="noopener noreferrer"&gt;indirect object syntax&lt;/a&gt;, &lt;a href="https://perldoc.perl.org/variables/%24;" rel="noopener noreferrer"&gt;Perl 4‑style multidimensional arrays&lt;/a&gt;, and &lt;a href="https://perldoc.perl.org/functions/open#Assigning-a-filehandle-to-a-bareword" rel="noopener noreferrer"&gt;bareword filehandles&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Getting back to assignments vs. conditionals, there is one case where I’ve found it to be acceptable to use an assignment inside an if statement, and that’s when I need to use the result of a check inside the condition. For 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="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;some_truthy_function&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="o"&gt;...&lt;/span&gt; &lt;span class="c1"&gt;# do something further with $foo&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps the scope of &lt;code&gt;some_truthy_function()&lt;/code&gt;‘s result inside the block so that I don’t pollute the outer scope with a temporary variable. Fortunately, Perl doesn’t warn on this syntax.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Cover image: &lt;a href="https://commons.wikimedia.org/wiki/File:Yoda_(29065553886).jpg" rel="noopener noreferrer"&gt;Paul VanDerWerf from Brunswick, Maine, USA&lt;/a&gt;, &lt;a href="https://creativecommons.org/licenses/by/2.0" rel="noopener noreferrer"&gt;CC BY 2.0&lt;/a&gt;, via Wikimedia Commons&lt;/em&gt;&lt;/p&gt;

</description>
      <category>perl</category>
      <category>conditions</category>
      <category>warnings</category>
      <category>strictures</category>
    </item>
    <item>
      <title>34 at 34 for v5.34: Modern Perl features for Perl’s birthday</title>
      <dc:creator>Mark Gardner</dc:creator>
      <pubDate>Tue, 21 Dec 2021 15:00:00 +0000</pubDate>
      <link>https://dev.to/mjgardner/34-at-34-for-v534-modern-perl-features-for-perls-birthday-2mai</link>
      <guid>https://dev.to/mjgardner/34-at-34-for-v534-modern-perl-features-for-perls-birthday-2mai</guid>
      <description>&lt;p&gt;Friday, December 17, 2021, marked the &lt;a href="https://github.com/Perl/perl5/commit/8d063cd8450e59ea1c611a2f4f5a21059a2804f1" rel="noopener noreferrer"&gt;thirty-fourth birthday&lt;/a&gt; of the Perl programming language, and coincidentally this year saw the &lt;a href="https://www.nntp.perl.org/group/perl.perl5.porters/2021/05/msg260110.html" rel="noopener noreferrer"&gt;release of version 5.34&lt;/a&gt;. There are plenty of Perl developers out there who haven’t kept up with recent (and not-so-recent) improvements to the language and its ecosystem, so I thought I might list a batch. (You may have seen some of these before in May’s post &lt;a href="https://phoenixtrap.com/2021/05/25/perl-can-do-that-now/" rel="noopener noreferrer"&gt;“Perl can do that now!”&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://perldoc.perl.org/feature" rel="noopener noreferrer"&gt;The &lt;code&gt;feature&lt;/code&gt; pragma&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.nntp.perl.org/group/perl.perl5.porters/2007/12/msg131636.html" rel="noopener noreferrer"&gt;Perl v5.10 was released in December 2007&lt;/a&gt;, and with it came &lt;code&gt;feature&lt;/code&gt;, a way of enabling new syntax without breaking backward compatibility. You can enable individual features by name (e.g., &lt;code&gt;use feature qw(say fc);&lt;/code&gt; for the &lt;code&gt;say&lt;/code&gt; and &lt;code&gt;fc&lt;/code&gt; keywords), or by using a &lt;a href="https://perldoc.perl.org/feature#FEATURE-BUNDLES" rel="noopener noreferrer"&gt;feature bundle&lt;/a&gt; based on the Perl version that introduced them. For example, the following:&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;feature&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;:5.34&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;…gives you the equivalent of:&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;feature&lt;/span&gt; &lt;span class="sx"&gt;qw(bareword_filehandles bitwise current_sub evalbytes fc indirect multidimensional postderef_qq say state switch unicode_eval unicode_strings)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Boy, that’s a mouthful. &lt;em&gt;Feature bundles are good.&lt;/em&gt; The corresponding bundle also gets &lt;a href="https://perldoc.perl.org/feature#IMPLICIT-LOADING" rel="noopener noreferrer"&gt;implicitly loaded&lt;/a&gt; if you specify a minimum required Perl version, e.g., with &lt;code&gt;use v5.32;&lt;/code&gt;. If you &lt;code&gt;use v5.12;&lt;/code&gt; or higher, &lt;a href="https://perldoc.perl.org/strict" rel="noopener noreferrer"&gt;&lt;code&gt;strict&lt;/code&gt; mode&lt;/a&gt; is enabled for free. So just say:&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;.34&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And lastly, one-liners can use the &lt;a href="https://perldoc.perl.org/perlrun#-E-commandline" rel="noopener noreferrer"&gt;&lt;code&gt;-E&lt;/code&gt; switch&lt;/a&gt; instead of &lt;code&gt;-e&lt;/code&gt; to enable all features for that version of Perl, so you can say the following on the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;perl &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'say "Hello world!"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;perl &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'print "Hello world!\n"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which is great when you’re trying to save some typing.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://perldoc.perl.org/experimental" rel="noopener noreferrer"&gt;The &lt;code&gt;experimental&lt;/code&gt; pragma&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Sometimes new Perl features need to be &lt;a href="https://perldoc.perl.org/perlpolicy#experimental" rel="noopener noreferrer"&gt;driven a couple of releases around the block&lt;/a&gt; before their behavior settles. Those experiments are documented in &lt;a href="https://perldoc.perl.org/perlexperiment" rel="noopener noreferrer"&gt;the perlexperiment page&lt;/a&gt;, and usually, you need both a &lt;code&gt;use feature&lt;/code&gt; (see above) and &lt;code&gt;no warnings&lt;/code&gt; statement to safely enable them. Or you can simply pass a list to &lt;code&gt;use experimental&lt;/code&gt; of the features you want, e.g.:&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;experimental&lt;/span&gt; &lt;span class="sx"&gt;qw(isa postderef signatures)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Ever-expanding &lt;a href="https://perldoc.perl.org/warnings#Category-Hierarchy" rel="noopener noreferrer"&gt;&lt;code&gt;warnings&lt;/code&gt; categories&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.nntp.perl.org/group/perl.perl5.porters/2000/03/msg10668.html" rel="noopener noreferrer"&gt;March 2000 saw the release of Perl 5.6&lt;/a&gt;, and with it, the expansion of the &lt;a href="https://perldoc.perl.org/perlrun#-w" rel="noopener noreferrer"&gt;&lt;code&gt;-w&lt;/code&gt; command-line switch&lt;/a&gt; to a system of fine-grained controls for warning against “dubious constructs” that can be turned on and off depending on the lexical &lt;a href="https://perldoc.perl.org/perlintro#Variable-scoping" rel="noopener noreferrer"&gt;scope&lt;/a&gt;. What started as &lt;a href="https://perldoc.perl.org/5.6.0/perllexwarn#Category-Hierarchy" rel="noopener noreferrer"&gt;26 main and 20 subcategories&lt;/a&gt; has &lt;a href="https://perldoc.perl.org/warnings#Category-Hierarchy" rel="noopener noreferrer"&gt;expanded into 31 main and 43 subcategories&lt;/a&gt;, including warnings for the aforementioned experimental features.&lt;/p&gt;

&lt;p&gt;As the &lt;a href="https://metacpan.org/pod/Perl::Critic::Policy::TestingAndDebugging::RequireUseWarnings#DESCRIPTION" rel="noopener noreferrer"&gt;relevant Perl::Critic policy says&lt;/a&gt;, “Using warnings, and paying attention to what they say, is probably the single most effective way to improve the quality of your code.” If you must violate warnings (perhaps because you’re rehabilitating some legacy code), you can isolate such violations to a small scope and individual categories. Check out the &lt;a href="https://metacpan.org/pod/strictures" rel="noopener noreferrer"&gt;strictures module on CPAN&lt;/a&gt; if you’d like to go further and make a safe subset of these categories fatal during development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Document other recently-introduced syntax with &lt;a href="https://metacpan.org/pod/Syntax::Construct" rel="noopener noreferrer"&gt;Syntax::Construct&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Not every new bit of Perl syntax is enabled with a &lt;code&gt;feature&lt;/code&gt; guard. For the rest, there’s E. Choroba’s &lt;a href="https://metacpan.org/pod/Syntax::Construct" rel="noopener noreferrer"&gt;Syntax::Construct module on CPAN&lt;/a&gt;. Rather than having to remember which version of Perl introduced what, Syntax::Construct lets you declare only what you use and provides a helpful error message if someone tries to run your code on an older unsupported version. Between it and the &lt;code&gt;feature&lt;/code&gt; pragma, you can prevent many head-scratching moments and give your users a chance to either upgrade or workaround.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make built-in functions throw exceptions with &lt;code&gt;autodie&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Many of Perl’s built-in functions only return false on failure, requiring the developer to check every time whether a file can be &lt;code&gt;open&lt;/code&gt;ed or a &lt;code&gt;system&lt;/code&gt; command executed. The lexical &lt;a href="https://perldoc.perl.org/autodie" rel="noopener noreferrer"&gt;&lt;code&gt;autodie&lt;/code&gt; pragma&lt;/a&gt; replaces them with versions that &lt;a href="https://perldoc.perl.org/functions/die" rel="noopener noreferrer"&gt;raise an exception&lt;/a&gt; with an &lt;a href="https://perldoc.perl.org/autodie::exception" rel="noopener noreferrer"&gt;object&lt;/a&gt; that can be interrogated for further details. No matter how many functions or methods deep a problem occurs, you can choose to catch it and respond appropriately. This leads us to…&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://perldoc.perl.org/perlsyn#Try-Catch-Exception-Handling" rel="noopener noreferrer"&gt;&lt;code&gt;try&lt;/code&gt;/&lt;code&gt;catch&lt;/code&gt; exception handling&lt;/a&gt; and &lt;a href="https://metacpan.org/pod/Feature::Compat::Try" rel="noopener noreferrer"&gt;Feature::Compat::Try&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.nntp.perl.org/group/perl.perl5.porters/2021/05/msg260110.html" rel="noopener noreferrer"&gt;This year’s Perl v5.34 release&lt;/a&gt; introduced &lt;a href="https://perldoc.perl.org/perlsyn#Try-Catch-Exception-Handling" rel="noopener noreferrer"&gt;experimental &lt;code&gt;try&lt;/code&gt;/&lt;code&gt;catch&lt;/code&gt; syntax&lt;/a&gt; for exception handling that should look more familiar to users of other languages while handling the &lt;a href="https://metacpan.org/pod/Try::Tiny#BACKGROUND" rel="noopener noreferrer"&gt;issues&lt;/a&gt; surrounding using &lt;a href="https://perldoc.perl.org/functions/eval#Block-eval" rel="noopener noreferrer"&gt;block &lt;code&gt;eval&lt;/code&gt;&lt;/a&gt; and testing of the &lt;a href="https://perldoc.perl.org/variables/%24@" rel="noopener noreferrer"&gt;special &lt;code&gt;$@&lt;/code&gt; variable&lt;/a&gt;. If you need to remain compatible with older versions of Perl (back to v5.14), just use the &lt;a href="https://metacpan.org/pod/Feature::Compat::Try" rel="noopener noreferrer"&gt;Feature::Compat::Try module from CPAN&lt;/a&gt; to automatically select either v5.34’s native &lt;code&gt;try&lt;/code&gt;/&lt;code&gt;catch&lt;/code&gt; or a subset of the functionality provided by &lt;a href="https://metacpan.org/pod/Syntax::Keyword::Try" rel="noopener noreferrer"&gt;Syntax::Keyword::Try&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pluggable keywords
&lt;/h2&gt;

&lt;p&gt;The abovementioned Syntax::Keyword::Try was made possible by the &lt;a href="https://perldoc.perl.org/perl5120delta#Pluggable-keywords" rel="noopener noreferrer"&gt;introduction of a pluggable keyword mechanism in 2010’s Perl v5.12&lt;/a&gt;. So was the &lt;a href="https://metacpan.org/pod/Future::AsyncAwait" rel="noopener noreferrer"&gt;Future::AsyncAwait&lt;/a&gt; asynchronous programming library and the &lt;a href="https://metacpan.org/pod/Object::Pad" rel="noopener noreferrer"&gt;Object::Pad&lt;/a&gt; testbed for new object-oriented Perl syntax. If you’re handy with C and &lt;a href="https://perldoc.perl.org/perlxs" rel="noopener noreferrer"&gt;Perl’s XS glue language&lt;/a&gt;, check out Paul “LeoNerd” Evans’ &lt;a href="https://metacpan.org/pod/XS::Parse::Keyword" rel="noopener noreferrer"&gt;XS::Parse::Keyword&lt;/a&gt; module to get a leg up on developing your own syntax module.&lt;/p&gt;

&lt;h2&gt;
  
  
  Define &lt;code&gt;package&lt;/code&gt;s with versions and blocks
&lt;/h2&gt;

&lt;p&gt;Perl v5.12 also helped reduce clutter by enabling a &lt;a href="https://perldoc.perl.org/functions/package" rel="noopener noreferrer"&gt;&lt;code&gt;package&lt;/code&gt; namespace declaration&lt;/a&gt; to &lt;a href="https://perldoc.perl.org/perl5120delta#New-package-NAME-VERSION-syntax" rel="noopener noreferrer"&gt;also include a version number&lt;/a&gt;, instead of requiring a separate &lt;code&gt;our $VERSION = ...;&lt;/code&gt; v5.14 further refined &lt;code&gt;package&lt;/code&gt;s to be &lt;a href="https://perldoc.perl.org/perl5140delta#package-block-syntax" rel="noopener noreferrer"&gt;specified in code blocks&lt;/a&gt;, so a namespace declaration can be the same as a lexical scope. Putting the two together gives you:&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="nn"&gt;Local::&lt;/span&gt;&lt;span class="nv"&gt;NewHotness&lt;/span&gt; &lt;span class="nv"&gt;v1&lt;/span&gt;&lt;span class="mf"&gt;.2.3&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead of:&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="nb"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;Local::&lt;/span&gt;&lt;span class="nv"&gt;OldAndBusted&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;version&lt;/span&gt; &lt;span class="mf"&gt;0.77&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;our&lt;/span&gt; &lt;span class="nv"&gt;$VERSION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="s2"&gt;v1.2.3&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I know which I’d rather do. (Though you may want to also &lt;code&gt;use Syntax::Construct qw(package-version package-block);&lt;/code&gt; to help along with older installations as described above.)&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://perldoc.perl.org/perlop#Logical-Defined-Or" rel="noopener noreferrer"&gt;The &lt;code&gt;//&lt;/code&gt; defined-or operator&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;This is an easy win &lt;a href="https://perldoc.perl.org/perl5100delta#Defined-or-operator" rel="noopener noreferrer"&gt;from Perl v5.10&lt;/a&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;defined&lt;/span&gt; &lt;span class="nv"&gt;$foo&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="nv"&gt;$bar&lt;/span&gt; &lt;span class="c1"&gt;# replace this&lt;/span&gt;
&lt;span class="nv"&gt;$foo&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="nv"&gt;$bar&lt;/span&gt;               &lt;span class="c1"&gt;# with this&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And:&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;$foo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$bar&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="nb"&gt;defined&lt;/span&gt; &lt;span class="nv"&gt;$foo&lt;/span&gt; &lt;span class="c1"&gt;# replace this&lt;/span&gt;
&lt;span class="nv"&gt;$foo&lt;/span&gt; &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$bar&lt;/span&gt;                   &lt;span class="c1"&gt;# with this&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perfect for assigning defaults to variables.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://perldoc.perl.org/functions/state" rel="noopener noreferrer"&gt;&lt;code&gt;state&lt;/code&gt; variables&lt;/a&gt; only initialize once
&lt;/h2&gt;

&lt;p&gt;Speaking of variables, ever want one to keep its old value the next time a scope is entered, like &lt;a href="https://perldoc.perl.org/perlsub#Persistent-Private-Variables" rel="noopener noreferrer"&gt;in a &lt;code&gt;sub&lt;/code&gt;&lt;/a&gt;? Declare it with &lt;code&gt;state&lt;/code&gt; instead of &lt;code&gt;my&lt;/code&gt;. Before &lt;a href="https://perldoc.perl.org/perl5100delta#state()-variables" rel="noopener noreferrer"&gt;Perl v5.10&lt;/a&gt;, you needed to &lt;a href="https://perldoc.perl.org/perlsub#Persistent-variables-with-closures" rel="noopener noreferrer"&gt;use a closure instead&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Save some typing with &lt;code&gt;say&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://perldoc.perl.org/perl5100delta#Core-Enhancements" rel="noopener noreferrer"&gt;Perl v5.10’s bumper crop of enhancements&lt;/a&gt; also included the &lt;a href="https://perldoc.perl.org/functions/say" rel="noopener noreferrer"&gt;&lt;code&gt;say&lt;/code&gt; function&lt;/a&gt;, which handles the common use case of &lt;code&gt;print&lt;/code&gt;ing a string or list of strings with a newline. It’s less noise in your code and saves you four characters. What’s not to love?&lt;/p&gt;

&lt;h2&gt;
  
  
  Note unimplemented code with &lt;code&gt;...&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://perldoc.perl.org/perlsyn#The-Ellipsis-Statement" rel="noopener noreferrer"&gt;&lt;code&gt;...&lt;/code&gt; ellipsis statement&lt;/a&gt; (colloquially “yada-yada”) gives you an easy placeholder for yet-to-be-implemented code. It parses OK but will throw an exception if executed. Hopefully, your &lt;a href="https://metacpan.org/pod/Devel::Cover" rel="noopener noreferrer"&gt;test coverage&lt;/a&gt; (or at least &lt;a href="https://metacpan.org/pod/Perl::Critic::Policy::ControlStructures::ProhibitYadaOperator" rel="noopener noreferrer"&gt;static analysis&lt;/a&gt;) will catch it before your users do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Loop and enumerate arrays with &lt;code&gt;each&lt;/code&gt;, &lt;code&gt;keys&lt;/code&gt;, and &lt;code&gt;values&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;each&lt;/code&gt;, &lt;code&gt;keys&lt;/code&gt;, and &lt;code&gt;values&lt;/code&gt; functions have always been able to operate on hashes. &lt;a href="https://perldoc.perl.org/perl5120delta#each,-keys,-values-are-now-more-flexible" rel="noopener noreferrer"&gt;Perl v5.12 and above make them work on arrays, too.&lt;/a&gt; The latter two are mainly for consistency, but you can use &lt;code&gt;each&lt;/code&gt; to iterate over an array’s indices and values at the same time:&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;while&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;$index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;each&lt;/span&gt; &lt;span class="nv"&gt;@array&lt;/span&gt;&lt;span class="p"&gt;)&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can be &lt;a href="https://metacpan.org/pod/Perl::Critic::Policy::Community::Each" rel="noopener noreferrer"&gt;problematic in non-trivial loops&lt;/a&gt;, but I’ve found it helpful in quick scripts and one-liners.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://perldoc.perl.org/perlsub#Localized-deletion-of-elements-of-composite-types" rel="noopener noreferrer"&gt;&lt;code&gt;delete local&lt;/code&gt; hash (and array) entries&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Ever needed to &lt;code&gt;delete&lt;/code&gt; an entry from a hash (e.g, an environment variable from &lt;code&gt;%ENV&lt;/code&gt; or a signal handler from &lt;code&gt;%SIG&lt;/code&gt;) just inside a block? &lt;a href="https://perldoc.perl.org/perl5120delta#delete-local" rel="noopener noreferrer"&gt;Perl v5.12 lets you do that&lt;/a&gt; with &lt;code&gt;delete local&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Paired hash slices
&lt;/h2&gt;

&lt;p&gt;Jumping forward to &lt;a href="https://www.nntp.perl.org/group/perl.perl5.porters/2014/05/msg215815.html" rel="noopener noreferrer"&gt;2014’s Perl v5.20&lt;/a&gt;, the &lt;a href="https://perldoc.perl.org/perl5200delta#New-slice-syntax" rel="noopener noreferrer"&gt;new &lt;code&gt;%foo{'bar', 'baz'}&lt;/code&gt; syntax&lt;/a&gt; enables you to &lt;a href="https://perldoc.perl.org/perldata#Key%2FValue-Hash-Slices" rel="noopener noreferrer"&gt;slice a subset of a hash&lt;/a&gt; with its keys and values intact. Very helpful for cherry-picking or aggregating many hashes into one. For 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;%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;verbose&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="s"&gt;name&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;Mark&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;
    &lt;span class="s"&gt;extra&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;pizza&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;# don't frob the pizza&lt;/span&gt;
&lt;span class="nv"&gt;$my_object&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;frob&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="sx"&gt;qw(verbose name)&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Paired array slices
&lt;/h2&gt;

&lt;p&gt;Not to be left out, you can also &lt;a href="https://perldoc.perl.org/perldata#Index/Value-Array-Slices" rel="noopener noreferrer"&gt;slice arrays&lt;/a&gt; in the same way, in this case returning indices and values:&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;@letters&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a&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="s1"&gt;z&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;@subset_kv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;%letters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;16&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;18&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="c1"&gt;# @subset_kv is now (16, 'p', 5, 'e', 18, 'r', 12, 'l')&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  More readable dereferencing
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://perldoc.perl.org/perl5200delta#Experimental-Postfix-Dereferencing" rel="noopener noreferrer"&gt;Perl v5.20 introduced&lt;/a&gt; and &lt;a href="https://perldoc.perl.org/perl5240delta#Postfix-dereferencing-is-no-longer-experimental" rel="noopener noreferrer"&gt;v5.24 de-experimentalized&lt;/a&gt; a more readable &lt;a href="https://perldoc.perl.org/perlref#Postfix-Dereference-Syntax" rel="noopener noreferrer"&gt;postfix dereferencing syntax&lt;/a&gt; for navigating nested data structures. Instead of using &lt;code&gt;{&lt;/code&gt;braces&lt;code&gt;}&lt;/code&gt; or smooshing sigils to the left of identifiers, you can use a postfixed sigil-and-star:&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;push&lt;/span&gt; &lt;span class="nv"&gt;@$array_ref&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="c1"&gt;# noisy&lt;/span&gt;
&lt;span class="nb"&gt;push&lt;/span&gt; &lt;span class="nv"&gt;@&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$array_ref&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="c1"&gt;# a little easier&lt;/span&gt;
&lt;span class="nb"&gt;push&lt;/span&gt; &lt;span class="nv"&gt;$array_ref&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;@&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="c1"&gt;# read from left to right&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So much of web development is slinging around and picking apart complicated &lt;a href="https://perldoc.perl.org/perldsc" rel="noopener noreferrer"&gt;data structures&lt;/a&gt; via &lt;a href="https://www.json.org/" rel="noopener noreferrer"&gt;JSON&lt;/a&gt;, so I welcome anything like this to reduce the cognitive load.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;when&lt;/code&gt; as a statement modifier
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://perldoc.perl.org/perl5120delta#when-as-a-statement-modifier" rel="noopener noreferrer"&gt;Starting in Perl v5.12&lt;/a&gt;, you can use the &lt;a href="https://perldoc.perl.org/perlsyn#Switch-Statements" rel="noopener noreferrer"&gt;experimental switch feature&lt;/a&gt;’s &lt;code&gt;when&lt;/code&gt; keyword as a postfix modifier. For 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;for&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;$a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="nv"&gt;when&lt;/span&gt; &lt;span class="sr"&gt;/^abc/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;$a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt; &lt;span class="nv"&gt;when&lt;/span&gt; &lt;span class="sr"&gt;/^dna/&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But I don’t recommend &lt;code&gt;when&lt;/code&gt;, &lt;code&gt;given&lt;/code&gt;, or &lt;code&gt;given&lt;/code&gt;’s &lt;a href="https://perldoc.perl.org/perlop#Smartmatch-Operator" rel="noopener noreferrer"&gt;smartmatch&lt;/a&gt; operations as they were &lt;a href="https://perldoc.perl.org/perl5180delta#New-mechanism-for-experimental-features" rel="noopener noreferrer"&gt;retconned as experiments in 2013’s Perl v5.18&lt;/a&gt; and have remained so due to their &lt;a href="https://perldoc.perl.org/perlsyn#Experimental-Details-on-given-and-when" rel="noopener noreferrer"&gt;tricky behavior&lt;/a&gt;. I wrote about &lt;a href="https://phoenixtrap.com/2021/02/14/switching-up-my-switches/" rel="noopener noreferrer"&gt;some alternatives using stable syntax&lt;/a&gt; back in February.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simple class inheritance with &lt;code&gt;use parent&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Sometimes in older object-oriented Perl code, you’ll see &lt;code&gt;use base&lt;/code&gt; as a pragma to establish inheritance from another class. Older still is the direct manipulation of the &lt;a href="https://perldoc.perl.org/variables/@ISA" rel="noopener noreferrer"&gt;package’s special &lt;code&gt;@ISA&lt;/code&gt; array&lt;/a&gt;. In most cases, both should be avoided in favor of &lt;code&gt;use parent&lt;/code&gt;, which was &lt;a href="https://perldoc.perl.org/perl5101delta#parent" rel="noopener noreferrer"&gt;added to core in Perl v5.10.1&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Mind you, if you’re following the &lt;a href="https://perldoc.perl.org/perlootut#PERL-OO-SYSTEMS" rel="noopener noreferrer"&gt;Perl object-oriented tutorial’s advice and have selected an OO system&lt;/a&gt; from CPAN, use its subclassing mechanism if it has one. &lt;a href="https://metacpan.org/pod/Moose#extends-(@superclasses)" rel="noopener noreferrer"&gt;Moose&lt;/a&gt;, &lt;a href="https://metacpan.org/pod/Moo#extends" rel="noopener noreferrer"&gt;Moo&lt;/a&gt;, and &lt;a href="https://metacpan.org/pod/Class::Accessor#Moose!" rel="noopener noreferrer"&gt;Class::Accessor’s “antlers” mode&lt;/a&gt; all provide an &lt;code&gt;extends&lt;/code&gt; function; &lt;a href="https://metacpan.org/pod/Object::Pad#:isa" rel="noopener noreferrer"&gt;Object::Pad provides an &lt;code&gt;:isa&lt;/code&gt; attribute&lt;/a&gt; on its &lt;a href="https://metacpan.org/pod/Object::Pad#class" rel="noopener noreferrer"&gt;&lt;code&gt;class&lt;/code&gt; keyword&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test for class membership with the &lt;a href="https://perldoc.perl.org/perlop#Class-Instance-Operator" rel="noopener noreferrer"&gt;&lt;code&gt;isa&lt;/code&gt; operator&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;As an alternative to the &lt;a href="https://perldoc.perl.org/UNIVERSAL#%24obj-%3Eisa(-TYPE-)" rel="noopener noreferrer"&gt;&lt;code&gt;isa()&lt;/code&gt; method&lt;/a&gt; provided to all Perl objects, &lt;a href="https://perldoc.perl.org/perl5320delta#The-isa-Operator" rel="noopener noreferrer"&gt;Perl v5.32 introduced&lt;/a&gt; the experimental &lt;a href="https://perldoc.perl.org/perlop#Class-Instance-Operator" rel="noopener noreferrer"&gt;&lt;code&gt;isa&lt;/code&gt; infix operator&lt;/a&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="nv"&gt;$my_object&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;isa&lt;/span&gt;&lt;span class="p"&gt;('&lt;/span&gt;&lt;span class="s1"&gt;Local::MyClass&lt;/span&gt;&lt;span class="p"&gt;')&lt;/span&gt;
&lt;span class="c1"&gt;# or&lt;/span&gt;
&lt;span class="nv"&gt;$my_object&lt;/span&gt; &lt;span class="nv"&gt;isa&lt;/span&gt; &lt;span class="nn"&gt;Local::&lt;/span&gt;&lt;span class="nv"&gt;MyClass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The latter can take either a bareword class name or string expression, but more importantly, it’s safer as it also returns false if the left argument is undefined or isn’t a &lt;code&gt;bless&lt;/code&gt;ed object reference. The older &lt;code&gt;isa()&lt;/code&gt; method will throw an exception in the former case and might return true if called as a class method when &lt;code&gt;$my_object&lt;/code&gt; is actually a string of a class name that’s the same as or inherits from &lt;code&gt;isa()&lt;/code&gt;’s argument.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://perldoc.perl.org/perlsub#Lexical-Subroutines" rel="noopener noreferrer"&gt;Lexical subroutines&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://perldoc.perl.org/perl5180delta#Lexical-subroutines" rel="noopener noreferrer"&gt;Introduced in Perl v5.18&lt;/a&gt; and &lt;a href="https://perldoc.perl.org/perl5260delta#Lexical-subroutines-are-no-longer-experimental" rel="noopener noreferrer"&gt;de-experimentalized in 2017’s Perl v5.26&lt;/a&gt;, you can now precede sub declarations with &lt;a href="https://perldoc.perl.org/perlsub#Lexical-Subroutines" rel="noopener noreferrer"&gt;&lt;code&gt;my&lt;/code&gt;, &lt;code&gt;state&lt;/code&gt;&lt;/a&gt;, or &lt;code&gt;our&lt;/code&gt;. One use of the first two is truly private functions and methods, as described in &lt;a href="https://jacoby.github.io/perl/2018/08/29/use-perl-features-lexical_subs.html" rel="noopener noreferrer"&gt;this 2018 Dave Jacoby blog&lt;/a&gt; and as part of &lt;a href="http://neilb.org/2014/07/24/private-functions.html" rel="noopener noreferrer"&gt;Neil Bowers’ 2014 survey&lt;/a&gt; of private function techniques.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://perldoc.perl.org/perlsub#Signatures" rel="noopener noreferrer"&gt;Subroutine signatures&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I’ve &lt;a href="https://phoenixtrap.com/2021/01/27/better-perl-with-subroutine-signatures-and-type-validation/" rel="noopener noreferrer"&gt;written&lt;/a&gt; and &lt;a href="https://phoenixtrap.com/2021/03/17/video-for-better-perl-subroutine-signatures-and-type-validation/" rel="noopener noreferrer"&gt;presented&lt;/a&gt; &lt;a href="https://phoenixtrap.com/2021/02/16/better-perl-more-on-signatures-and-types/" rel="noopener noreferrer"&gt;extensively&lt;/a&gt; about signatures and alternatives over the past year, so I won’t repeat that here. I’ll just add that the &lt;a href="https://lists.perl.org/list/perl5-porters.html" rel="noopener noreferrer"&gt;Perl 5 Porters&lt;/a&gt; development mailing list has been &lt;a href="https://www.nntp.perl.org/group/perl.perl5.porters/2021/11/msg261939.html" rel="noopener noreferrer"&gt;making a concerted effort&lt;/a&gt; over the past month to hash out the remaining issues towards rendering this feature non-experimental. The popular Mojolicious real-time web framework also &lt;a href="https://metacpan.org/dist/Mojolicious/view/lib/Mojolicious/Guides.pod#Signatures" rel="noopener noreferrer"&gt;provides a shortcut for enabling signatures&lt;/a&gt; and uses them extensively in examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Indented here-documents with &lt;code&gt;&amp;lt;&amp;lt;~&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Perl has had shell-style &lt;a href="https://perldoc.perl.org/perlop#%3C%3CEOF" rel="noopener noreferrer"&gt;“here-document” syntax&lt;/a&gt; for embedding multi-line strings of quoted text for a long time. &lt;a href="https://perldoc.perl.org/perlop#%3C%3CEOF" rel="noopener noreferrer"&gt;Starting with Perl v5.26&lt;/a&gt;, you can precede the delimiting string with a &lt;code&gt;~&lt;/code&gt; character and Perl will both allow the ending delimiter to be indented as well as strip indentation from the embedded text. This allows for much more readable embedded code such as runs of HTML and SQL. For 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="nv"&gt;$do_query&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;$rows_deleted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$dbh&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="p"&gt;(&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="s1"&gt;END_SQL&lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="nb"&gt;undef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nv"&gt;DELETE&lt;/span&gt; &lt;span class="nv"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;table&lt;/span&gt;
      &lt;span class="nv"&gt;WHERE&lt;/span&gt; &lt;span class="nv"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt;
      &lt;span class="nv"&gt;END_SQL&lt;/span&gt;
    &lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$rows_deleted&lt;/span&gt;&lt;span class="s2"&gt; rows were deleted.&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;h2&gt;
  
  
  More readable chained comparisons
&lt;/h2&gt;

&lt;p&gt;When I learned math in school, my teachers and textbooks would often describe multiple comparisons and inequalities as a single expression. Unfortunately, when it came time to learn programming every computer language I saw required them to be broken up with a series of &lt;code&gt;and&lt;/code&gt; (or &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;) operators. &lt;a href="https://perldoc.perl.org/perl5320delta#Chained-comparisons-capability" rel="noopener noreferrer"&gt;With Perl v5.32, this is no more&lt;/a&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;$y&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nv"&gt;$z&lt;/span&gt; &lt;span class="p"&gt;)&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="c1"&gt;# old way&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;$x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nv"&gt;$y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nv"&gt;$z&lt;/span&gt; &lt;span class="p"&gt;)&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="c1"&gt;# new way&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It’s more concise, less noisy, and more like what regular math looks like.&lt;/p&gt;

&lt;h2&gt;
  
  
  Self-documenting named regular expression captures
&lt;/h2&gt;

&lt;p&gt;Perl’s expressive &lt;a href="https://perldoc.perl.org/perlre" rel="noopener noreferrer"&gt;regular expression&lt;/a&gt; matching and text-processing prowess are legendary, although overuse and poor use of readability enhancements often turn people away from them (and Perl in general). We often use regexps for extracting data from a matched pattern. For 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="sr"&gt;/Time: (..):(..):(..)/&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;# parse out values&lt;/span&gt;
    &lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$1 hours, $2 minutes, $3 seconds&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;Named &lt;a href="https://perldoc.perl.org/perlre#Capture-groups" rel="noopener noreferrer"&gt;capture groups&lt;/a&gt;, &lt;a href="https://perldoc.perl.org/perl5100delta#Named-Capture-Buffers" rel="noopener noreferrer"&gt;introduced in Perl v5.10&lt;/a&gt;, make both the pattern more obvious and retrieval of its data less cryptic:&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="sr"&gt;/Time: (?&amp;lt;hours&amp;gt;..):(?&amp;lt;minutes&amp;gt;..):(?&amp;lt;seconds&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;say&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;$+{hours} hours, $+{minutes} minutes, $+{seconds} seconds&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;h2&gt;
  
  
  More readable regexp character classes
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;/x&lt;/code&gt; regular expression modifier already enables better readability by telling the parser to ignore most whitespace, allowing you to break up complicated patterns into spaced-out groups and multiple lines with code comments. &lt;a href="https://perldoc.perl.org/perl5260delta#New-regular-expression-modifier-/xx" rel="noopener noreferrer"&gt;With Perl v5.26 you can specify &lt;code&gt;/xx&lt;/code&gt;&lt;/a&gt; to also ignore spaces and tabs inside &lt;code&gt;[&lt;/code&gt;bracketed&lt;code&gt;]&lt;/code&gt; character classes, turning 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="sr"&gt;/[d-eg-i3-7]/&lt;/span&gt;
&lt;span class="sr"&gt;/[!@"#$%^&amp;amp;*()=?&amp;lt;&amp;gt;']/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;…into 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="sr"&gt;/ [d-e g-i 3-7]/xx&lt;/span&gt;
&lt;span class="sr"&gt;/[! @ " # $ % ^ &amp;amp; * () = ? &amp;lt;&amp;gt; ']/xx&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;a href="https://perldoc.perl.org/re#'/flags'-mode" rel="noopener noreferrer"&gt;Set default regexp flags with the &lt;code&gt;re&lt;/code&gt; pragma&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://perldoc.perl.org/re#'/flags'-mode" rel="noopener noreferrer"&gt;Beginning with Perl v5.14&lt;/a&gt;, writing &lt;code&gt;use re '/xms';&lt;/code&gt; (or any combination of &lt;a href="https://perldoc.perl.org/perlre#Modifiers" rel="noopener noreferrer"&gt;regular expression modifier flags&lt;/a&gt;) will turn on those flags until the end of that lexical scope, saving you the trouble of remembering them every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Non-destructive substitution with &lt;code&gt;s///r&lt;/code&gt; and &lt;code&gt;tr///r&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://perldoc.perl.org/perlop#s/PATTERN/REPLACEMENT/msixpodualngcer" rel="noopener noreferrer"&gt;&lt;code&gt;s///&lt;/code&gt; substitution&lt;/a&gt; and &lt;a href="https://perldoc.perl.org/perlop#tr/SEARCHLIST/REPLACEMENTLIST/cdsr" rel="noopener noreferrer"&gt;&lt;code&gt;tr///&lt;/code&gt; transliteration&lt;/a&gt; operators typically change their input directly, often in conjunction with the &lt;a href="https://perldoc.perl.org/perlop#Binding-Operators" rel="noopener noreferrer"&gt;&lt;code&gt;=~&lt;/code&gt; binding operator&lt;/a&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="sr"&gt;s/foo/bar/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# changes the first foo to bar in $_&lt;/span&gt;
&lt;span class="nv"&gt;$baz&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;s/foo/bar/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# the same but in $baz&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But what if you want to leave the original untouched, such as when processing an array of strings with a &lt;code&gt;map&lt;/code&gt;? &lt;a href="https://perldoc.perl.org/perl5140delta#Non-destructive-substitution" rel="noopener noreferrer"&gt;With Perl v5.14 and above, add the &lt;code&gt;/r&lt;/code&gt; flag&lt;/a&gt;, which makes the substitution on a copy and returns the result:&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;@changed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="sr"&gt;s/foo/bar/r&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;@original&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;a href="https://perldoc.perl.org/functions/fc" rel="noopener noreferrer"&gt;Unicode case-folding with &lt;code&gt;fc&lt;/code&gt;&lt;/a&gt; for better string comparisons
&lt;/h2&gt;

&lt;p&gt;Unicode and character encoding in general are complicated beasts. Perl has &lt;a href="https://perldoc.perl.org/perl56delta#Unicode-and-UTF-8-support" rel="noopener noreferrer"&gt;handled Unicode since v5.6&lt;/a&gt; and has kept pace with fixes and support for updated standards in the intervening decades. If you need to test if two strings are equal regardless of case, use the &lt;a href="https://perldoc.perl.org/functions/fc" rel="noopener noreferrer"&gt;&lt;code&gt;fc&lt;/code&gt; function&lt;/a&gt; introduced &lt;a href="https://perldoc.perl.org/perl5160delta#New-function-fc-and-corresponding-escape-sequence-%5CF-for-Unicode-foldcase" rel="noopener noreferrer"&gt;in Perl v5.16&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Safer processing of file arguments with &lt;code&gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;&amp;lt;&amp;gt;&lt;/code&gt; null filehandle or “diamond operator” is often used in &lt;a href="https://perldoc.perl.org/perlsyn#Compound-Statements" rel="noopener noreferrer"&gt;&lt;code&gt;while&lt;/code&gt; loops&lt;/a&gt; to process input per line coming either from standard input (e.g., piped from another program) or from a list of files on the command line. Unfortunately, it uses a &lt;a href="https://perldoc.perl.org/functions/open#open-FILEHANDLE,EXPR" rel="noopener noreferrer"&gt;form of Perl’s &lt;code&gt;open&lt;/code&gt; function&lt;/a&gt; that interprets special characters such as pipes (&lt;code&gt;|&lt;/code&gt;) that would allow it to insecurely &lt;a href="https://perldoc.perl.org/perlopentut#Opening-Pipes" rel="noopener noreferrer"&gt;run external commands&lt;/a&gt;. Using the &lt;code&gt;&amp;lt;&amp;lt;&amp;gt;&amp;gt;&lt;/code&gt; “double diamond” operator &lt;a href="https://perldoc.perl.org/perl5220delta#New-double-diamond-operator" rel="noopener noreferrer"&gt;introduced in Perl v5.22&lt;/a&gt; forces &lt;code&gt;open&lt;/code&gt; to treat all command-line arguments as file names only. For older Perls, the &lt;a href="https://perldoc.perl.org/perlop#I/O-Operators" rel="noopener noreferrer"&gt;perlop documentation&lt;/a&gt; recommends the &lt;a href="https://metacpan.org/pod/ARGV::readonly" rel="noopener noreferrer"&gt;ARGV::readonly CPAN module&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Safer loading of Perl libraries and modules from &lt;code&gt;@INC&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://perldoc.perl.org/perl5260delta#Removal-of-the-current-directory-(%22.%22)-from-@INC" rel="noopener noreferrer"&gt;Perl v5.26 removed the ability for all programs to load modules by default from the current directory&lt;/a&gt;, closing a security vulnerability originally identified and fixed as &lt;a href="https://nvd.nist.gov/vuln/detail/CVE-2016-1238" rel="noopener noreferrer"&gt;CVE-2016–1238&lt;/a&gt; in previous versions’ included scripts. If your code relied on this unsafe behavior, the &lt;a href="https://perldoc.perl.org/perl5260delta#Removal-of-the-current-directory-(%22.%22)-from-@INC" rel="noopener noreferrer"&gt;v5.26 release notes include steps&lt;/a&gt; on how to adapt.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://perldoc.perl.org/HTTP::Tiny" rel="noopener noreferrer"&gt;HTTP::Tiny&lt;/a&gt; simple HTTP/1.1 client included
&lt;/h2&gt;

&lt;p&gt;To bootstrap access to &lt;a href="https://cpan.org/" rel="noopener noreferrer"&gt;CPAN&lt;/a&gt; on the web in the possible absence of external tools like &lt;code&gt;curl&lt;/code&gt; or &lt;code&gt;wget&lt;/code&gt;, &lt;a href="https://perldoc.perl.org/HTTP::Tiny" rel="noopener noreferrer"&gt;Perl v5.14 began including the HTTP::Tiny module&lt;/a&gt;. You can also use it in your programs if you need a simple web client with no dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://perldoc.perl.org/Test2" rel="noopener noreferrer"&gt;Test2&lt;/a&gt;: The next generation of Perl testing frameworks
&lt;/h2&gt;

&lt;p&gt;Forked and refactored from the venerable &lt;a href="https://perldoc.perl.org/Test::Builder" rel="noopener noreferrer"&gt;Test::Builder&lt;/a&gt; (the basis for the &lt;a href="https://perldoc.perl.org/Test::More" rel="noopener noreferrer"&gt;Test::More&lt;/a&gt; library that many are familiar with), &lt;a href="https://perldoc.perl.org/Test2" rel="noopener noreferrer"&gt;Test2&lt;/a&gt; was included in the core module library &lt;a href="https://perldoc.perl.org/5.26.0/perlmodlib#Test2" rel="noopener noreferrer"&gt;beginning with Perl v5.26&lt;/a&gt;. I’ve &lt;a href="https://phoenixtrap.com/tag/test2/" rel="noopener noreferrer"&gt;experimented recently&lt;/a&gt; with using the &lt;a href="https://metacpan.org/pod/Test2::Suite" rel="noopener noreferrer"&gt;Test2::Suite&lt;/a&gt; CPAN library instead of Test::More and it looks pretty good. I’m also intrigued by &lt;a href="https://metacpan.org/pod/Test2::Harness" rel="noopener noreferrer"&gt;Test2::Harness&lt;/a&gt;’ support for threading, forking, and preloading modules to reduce test run times.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://metacpan.org/pod/Task::Kensho" rel="noopener noreferrer"&gt;Task::Kensho&lt;/a&gt;: Where to start for recommended Perl modules
&lt;/h2&gt;

&lt;p&gt;This last item may not be included when you install Perl, but it’s where I turn for a collection of well-regarded CPAN modules for accomplishing a wide variety of common tasks spanning from &lt;a href="https://metacpan.org/pod/Task::Kensho::Async" rel="noopener noreferrer"&gt;asynchronous programming&lt;/a&gt; to &lt;a href="https://metacpan.org/pod/Task::Kensho::XML" rel="noopener noreferrer"&gt;XML&lt;/a&gt;. Use it as a starting point or &lt;a href="https://metacpan.org/dist/App-cpanminus/view/lib/App/cpanminus/fatscript.pm#-interactive" rel="noopener noreferrer"&gt;interactively&lt;/a&gt; select the mix of libraries appropriate to your project.&lt;/p&gt;




&lt;p&gt;And there you have it: a selection of 34 features, enhancements, and improvements for the first 34 years of Perl. What’s your favorite? Did I miss anything? Let me know in the comments.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Cover image: &lt;a href="https://www.flickr.com/photos/93472573@N00/5372262156" rel="noopener noreferrer"&gt;"My birthday cake"&lt;/a&gt; by &lt;a href="https://www.flickr.com/photos/frosted_peppercorn/" rel="noopener noreferrer"&gt;Wesley Bowler&lt;/a&gt; is licensed under &lt;a href="https://creativecommons.org/licenses/by-nc-sa/2.0/?ref=openverse&amp;amp;atype=html" rel="noopener noreferrer"&gt;CC BY-NC-SA 2.0&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>perl</category>
      <category>programming</category>
      <category>opensource</category>
      <category>news</category>
    </item>
    <item>
      <title>A brief note on Log4perl</title>
      <dc:creator>Mark Gardner</dc:creator>
      <pubDate>Tue, 14 Dec 2021 15:00:00 +0000</pubDate>
      <link>https://dev.to/mjgardner/a-brief-note-on-log4perl-3m0b</link>
      <guid>https://dev.to/mjgardner/a-brief-note-on-log4perl-3m0b</guid>
      <description>&lt;p&gt;The Java world had an… interesting weekend when security researchers revealed on December 9 a &lt;a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44228" rel="noopener noreferrer"&gt;vulnerability&lt;/a&gt; in the popular &lt;a href="https://logging.apache.org/log4j/2.x/" rel="noopener noreferrer"&gt;Apache Log4j 2&lt;/a&gt; software library for recording and debugging events. Systems as diverse as &lt;a href="https://aws.amazon.com/security/security-bulletins/AWS-2021-006/" rel="noopener noreferrer"&gt;Amazon Web Services&lt;/a&gt;, &lt;a href="https://www.macworld.com/article/559108/icloud-patch-log4shell-exploit.html" rel="noopener noreferrer"&gt;Apple iCloud&lt;/a&gt;, and the &lt;a href="https://www.minecraft.net/en-us/article/important-message--security-vulnerability-java-edition" rel="noopener noreferrer"&gt;Minecraft video game&lt;/a&gt; could be exploited to run arbitrary code on a server merely by sending a specially-crafted string of text. Information technology professionals have been scrambling ever since the initial disclosure to patch, upgrade, reconfigure, or otherwise protect affected servers. &lt;a href="https://log4shell.com/" rel="noopener noreferrer"&gt;It’s bad&lt;/a&gt;, and past unpatched vulnerabilities &lt;a href="https://arstechnica.com/information-technology/2017/09/massive-equifax-breach-caused-by-failure-to-patch-two-month-old-bug/" rel="noopener noreferrer"&gt;like this&lt;/a&gt; have been responsible for the exposure of millions of people’s sensitive data.&lt;/p&gt;

&lt;p&gt;Many Perl applications use the similarly-named and ‑designed &lt;a href="https://metacpan.org/pod/Log::Log4perl" rel="noopener noreferrer"&gt;Log::Log4perl&lt;/a&gt; library, and the good news is that as far as I can tell the latter doesn’t suffer from the type of vulnerability described above. &lt;strong&gt;This doesn’t mean poorly-written or ‑configured Perl-based systems are immune to all exploits, just this particular one.&lt;/strong&gt; You should be safe to continue using Log4perl unless someone has deliberately configured it otherwise, and in fact, &lt;a href="https://www.hostgator.com/" rel="noopener noreferrer"&gt;my work&lt;/a&gt; uses it extensively.&lt;/p&gt;

&lt;p&gt;You might be surprised to read me suggesting a logging framework after &lt;a href="https://phoenixtrap.com/tag/debugging/" rel="noopener noreferrer"&gt;writing multiple articles espousing the Perl step debugger&lt;/a&gt; as an alternative. Log4perl developer Mike Schilli’s &lt;a href="https://www.perl.com/pub/2002/09/11/log4perl.html" rel="noopener noreferrer"&gt;2002 introduction to the package for Perl.com&lt;/a&gt; came down on the opposite side of the argument. It can seem like one of those programmer religious issues like &lt;a href="https://thenewstack.io/spaces-vs-tabs-a-20-year-debate-and-now-this-what-the-hell-is-wrong-with-go/" rel="noopener noreferrer"&gt;tabs vs. spaces&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Editor_war" rel="noopener noreferrer"&gt;vim vs. Emacs&lt;/a&gt;, or &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/" rel="noopener noreferrer"&gt;Linux&lt;/a&gt; vs. &lt;a href="https://www.winehq.org/" rel="noopener noreferrer"&gt;Windows&lt;/a&gt;. (For the record, the correct answers are &lt;a href="https://metacpan.org/pod/Perl::Critic::Policy::CodeLayout::ProhibitHardTabs" rel="noopener noreferrer"&gt;spaces&lt;/a&gt;, &lt;a href="https://www.barebones.com/products/bbedit/" rel="noopener noreferrer"&gt;BBEdit&lt;/a&gt;, and &lt;a href="https://www.apple.com/macos/" rel="noopener noreferrer"&gt;macOS&lt;/a&gt;. 😉)&lt;/p&gt;

&lt;p&gt;But in this case, you can and should have the best of both worlds—logging at different &lt;a href="https://metacpan.org/pod/Log::Log4perl#Log-Levels" rel="noopener noreferrer"&gt;levels&lt;/a&gt; to appropriate &lt;a href="https://metacpan.org/pod/Log::Log4perl#Appenders" rel="noopener noreferrer"&gt;destinations&lt;/a&gt; while still dropping into the &lt;a href="https://perldoc.perl.org/perldebug" rel="noopener noreferrer"&gt;interactive debugger&lt;/a&gt; when you need to do something trickier like examine program state or tweak a data structure on the fly. I use both techniques and only emphasize the advocacy of step debugging because it’s understood less.&lt;/p&gt;

</description>
      <category>perl</category>
      <category>logging</category>
      <category>log4j</category>
      <category>security</category>
    </item>
    <item>
      <title>Sweeter Perl exception classes</title>
      <dc:creator>Mark Gardner</dc:creator>
      <pubDate>Tue, 07 Dec 2021 15:00:00 +0000</pubDate>
      <link>https://dev.to/mjgardner/sweeter-perl-exception-classes-23hl</link>
      <guid>https://dev.to/mjgardner/sweeter-perl-exception-classes-23hl</guid>
      <description>&lt;p&gt;I &lt;a href="https://phoenixtrap.com/2021/11/23/video-a-year-of-being-wrong-on-the-internet/" rel="noopener noreferrer"&gt;mentioned&lt;/a&gt; at the &lt;a href="https://thibaultduponchelle.github.io/the-ephemeral-miniconf/" rel="noopener noreferrer"&gt;Ephemeral Miniconf&lt;/a&gt; last month that as soon as I write about one Perl module (or five), someone inevitably brings up another (or seven) I’ve missed. And of course, it happened again &lt;a href="https://phoenixtrap.com/2021/11/30/vicious-test-mockery-of-a-perl-modulino/" rel="noopener noreferrer"&gt;last week&lt;/a&gt;: no sooner had I written in passing that I was using &lt;a href="https://metacpan.org/pod/Exception::Class" rel="noopener noreferrer"&gt;Exception::Class&lt;/a&gt; than the denizens of the &lt;a href="https://web.libera.chat/#perl" rel="noopener noreferrer"&gt;Libera Chat IRC #perl channel&lt;/a&gt; insisted I should use &lt;a href="https://metacpan.org/pod/Throwable" rel="noopener noreferrer"&gt;Throwable&lt;/a&gt; instead for defining my exceptions. (I’ve already blogged about various ways of &lt;a href="https://phoenixtrap.com/2021/02/22/exceptional-perl-failure-is-an-option/" rel="noopener noreferrer"&gt;catching exceptions&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;Why Throwable? Aside from Exception::Class’s author &lt;a href="https://metacpan.org/pod/Exception::Class#DESCRIPTION" rel="noopener noreferrer"&gt;recommending it&lt;/a&gt; over his own work due to a &lt;a href="https://metacpan.org/release/DROLSKY/Exception-Class-1.45/source/Changes#L57" rel="noopener noreferrer"&gt;“nicer, more modern interface,”&lt;/a&gt; Throwable is a &lt;a href="https://metacpan.org/pod/Moo::Role" rel="noopener noreferrer"&gt;Moo role&lt;/a&gt;, so it’s composable into classes along with other &lt;a href="https://perldoc.perl.org/perlootut#Roles" rel="noopener noreferrer"&gt;roles&lt;/a&gt; instead of mucking about with multiple inheritance. This means that if your exceptions need to do something reusable in your application like &lt;a href="https://metacpan.org/pod/Task::Kensho::Logging" rel="noopener noreferrer"&gt;logging&lt;/a&gt;, you can also consume a role that does that and not have so much duplicate code. (No, I’m not going to pick a favorite logging module; I’ll probably get that wrong too.)&lt;/p&gt;

&lt;p&gt;However, since Throwable is a role instead of a class, I would have to define several additional &lt;a href="https://perldoc.perl.org/functions/package" rel="noopener noreferrer"&gt;&lt;code&gt;package&lt;/code&gt;&lt;/a&gt;s in my tiny &lt;a href="https://perlmaven.com/modulino-both-script-and-module" rel="noopener noreferrer"&gt;modulino&lt;/a&gt; script from last week, one for each exception class I want. The beauty of Exception::Class is its simple declarative nature: just &lt;a href="https://perldoc.perl.org/functions/use" rel="noopener noreferrer"&gt;&lt;code&gt;use&lt;/code&gt;&lt;/a&gt; it and &lt;a href="https://metacpan.org/pod/Exception::Class#DECLARING-EXCEPTION-CLASSES" rel="noopener noreferrer"&gt;pass a list&lt;/a&gt; of desired class names along with options for attributes and whatnot. What’s needed for simple use cases like mine is a declarative syntax for defining several exception classes without the noise of multiple packages.&lt;/p&gt;

&lt;p&gt;Enter &lt;a href="https://metacpan.org/pod/Throwable::SugarFactory" rel="noopener noreferrer"&gt;Throwable::SugarFactory&lt;/a&gt;, a module that enables you to do just that by adding an &lt;code&gt;exception&lt;/code&gt; function for declaring exception classes. (There’s also the similarly-named &lt;a href="https://metacpan.org/pod/Throwable::Factory" rel="noopener noreferrer"&gt;Throwable::Factory&lt;/a&gt;; see the above discussion about never being able to cover everybody’s favorites.) The &lt;code&gt;exception&lt;/code&gt; function &lt;a href="https://metacpan.org/pod/Throwable::SugarFactory#DECLARATION" rel="noopener noreferrer"&gt;takes three arguments&lt;/a&gt;: the name of the desired exception class as a string, a description, and an optional list of instructions Moo uses to build the class. It might look something 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="nb"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;Local::My::&lt;/span&gt;&lt;span class="nv"&gt;Exceptions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Throwable::&lt;/span&gt;&lt;span class="nv"&gt;SugarFactory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;exception&lt;/span&gt; &lt;span class="s"&gt;GenericError&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;something bad happened&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;span class="nv"&gt;exception&lt;/span&gt; &lt;span class="s"&gt;DetailedError&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;something specific happened&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="s"&gt;has&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;message&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;is&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;ro&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="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;Throwable::SugarFactory takes care of creating constructor functions in Perl-style &lt;code&gt;snake_case&lt;/code&gt; as well as functions for detecting what kind of exception is being caught, so you can use your new exception library 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="c1"&gt;#!/usr/bin/env perl&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;experimental&lt;/span&gt; &lt;span class="sx"&gt;qw(isa)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Feature::Compat::&lt;/span&gt;&lt;span class="nv"&gt;Try&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;JSON::&lt;/span&gt;&lt;span class="nv"&gt;MaybeXS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Local::My::&lt;/span&gt;&lt;span class="nv"&gt;Exceptions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;try&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;generic_error&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nv"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;warn&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;whoops!&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;try&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;detailed_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;message&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;you got me&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;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$e&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="nv"&gt;encode_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;to_hash&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;$e&lt;/span&gt; &lt;span class="nv"&gt;isa&lt;/span&gt; &lt;span class="nv"&gt;DetailedError&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nb"&gt;defined&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;message&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;does&lt;/span&gt;&lt;span class="p"&gt;('&lt;/span&gt;&lt;span class="s1"&gt;Throwable&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;$e&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 above also demonstrates a couple of other Throwable::SugarFactory features. First, you get a &lt;code&gt;to_hash&lt;/code&gt; method that returns a hash reference of all exception data, suitable for serializing to JSON. Second, you &lt;a href="https://metacpan.org/pod/Throwable::SugarFactory#Throwable" rel="noopener noreferrer"&gt;get all of Throwable’s methods&lt;/a&gt;, including &lt;code&gt;throw&lt;/code&gt; for re-throwing exceptions.&lt;/p&gt;

&lt;p&gt;So where does this leave last week’s &lt;a href="https://foaas.com/" rel="noopener noreferrer"&gt;FOAAS.com&lt;/a&gt; modulino client demonstration of &lt;a href="https://en.wikipedia.org/wiki/Mock_object" rel="noopener noreferrer"&gt;object mocking&lt;/a&gt; tests? With a little bit of rewriting to define and then use our sweeter exception library, it looks like this. You can &lt;a href="https://phoenixtrap.com/2021/11/30/vicious-test-mockery-of-a-perl-modulino/" rel="noopener noreferrer"&gt;review&lt;/a&gt; for a description of the rest of its workings.&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="nb"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;Local::CallFOAAS::&lt;/span&gt;&lt;span class="nv"&gt;Exceptions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Throwable::&lt;/span&gt;&lt;span class="nv"&gt;SugarFactory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;BEGIN&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;exception&lt;/span&gt; &lt;span class="s"&gt;NoMethodError&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;no matching WebService::FOAAS method&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="s"&gt;has&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;method&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;is&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;ro&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="nv"&gt;exception&lt;/span&gt; &lt;span class="s"&gt;ServiceError&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;error from WebService::FOAAS&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="s"&gt;has&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;message&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;is&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;ro&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="p"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;Local::&lt;/span&gt;&lt;span class="nv"&gt;CallFOAAS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;# this is a modulino&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Test2::&lt;/span&gt;&lt;span class="nv"&gt;V0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;             &lt;span class="c1"&gt;# enables strict, warnings, utf8&lt;/span&gt;

&lt;span class="c1"&gt;# declare all the new stuff we're using&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;feature&lt;/span&gt; &lt;span class="sx"&gt;qw(say state)&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;experimental&lt;/span&gt; &lt;span class="sx"&gt;qw(isa postderef signatures)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Feature::Compat::&lt;/span&gt;&lt;span class="nv"&gt;Try&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Syntax::&lt;/span&gt;&lt;span class="nv"&gt;Construct&lt;/span&gt; &lt;span class="sx"&gt;qw(non-destructive-substitution)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;WebService::&lt;/span&gt;&lt;span class="nv"&gt;FOAAS&lt;/span&gt; &lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Package::&lt;/span&gt;&lt;span class="nv"&gt;Stash&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nn"&gt;Local::CallFOAAS::&lt;/span&gt;&lt;span class="nv"&gt;Exceptions&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;import&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;$foaas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Package::&lt;/span&gt;&lt;span class="nv"&gt;Stash&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="s1"&gt;WebService::FOAAS&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;$run_as&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="nv"&gt;$ENV&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;CPANTEST&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;test&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;defined&lt;/span&gt; &lt;span class="nb"&gt;scalar&lt;/span&gt; &lt;span class="nb"&gt;caller&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;run&lt;/span&gt;&lt;span class="p"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;:&lt;/span&gt;                          &lt;span class="nb"&gt;undef&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;__PACKAGE__&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;$run_as&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@ARGV&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;defined&lt;/span&gt; &lt;span class="nv"&gt;$run_as&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;run&lt;/span&gt; &lt;span class="p"&gt;( $class, @args ) {&lt;/span&gt;
    &lt;span class="nv"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="nv"&gt;$class&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;call_method&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="p"&gt;}&lt;/span&gt;
    &lt;span class="nv"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$e&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;No method &lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;method&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;if&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt; &lt;span class="nv"&gt;isa&lt;/span&gt; &lt;span class="nv"&gt;NoMethodError&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;Service error: &lt;/span&gt;&lt;span class="p"&gt;',&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;message&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;if&lt;/span&gt; &lt;span class="nv"&gt;$e&lt;/span&gt; &lt;span class="nv"&gt;isa&lt;/span&gt; &lt;span class="nv"&gt;ServiceError&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="si"&gt;$e&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="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Utilities&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;methods&lt;/span&gt; &lt;span class="p"&gt;($)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;state&lt;/span&gt; &lt;span class="nv"&gt;@methods&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt; &lt;span class="sr"&gt;s/^foaas_(.+)/$1/r&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;/^foaas_/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$foaas&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;list_all_symbols&lt;/span&gt;&lt;span class="p"&gt;('&lt;/span&gt;&lt;span class="s1"&gt;CODE&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;@methods&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;call_method&lt;/span&gt; &lt;span class="p"&gt;( $class, $method = '', @args ) {&lt;/span&gt;
    &lt;span class="nv"&gt;state&lt;/span&gt; &lt;span class="nv"&gt;%methods&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="vg"&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="nv"&gt;$class&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;methods&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;no_method_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;method&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$method&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="nv"&gt;$methods&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$method&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$foaas&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;get_symbol&lt;/span&gt;&lt;span class="p"&gt;("&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;&lt;/span&gt;&lt;span class="si"&gt;$method&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="nv"&gt;@args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nv"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$e&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="nv"&gt;service_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="s"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$e&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="c1"&gt;# Testing&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt; &lt;span class="p"&gt;( $class, @ ) {&lt;/span&gt;
    &lt;span class="nv"&gt;state&lt;/span&gt; &lt;span class="nv"&gt;$stash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Package::&lt;/span&gt;&lt;span class="nv"&gt;Stash&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="nv"&gt;$class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;state&lt;/span&gt; &lt;span class="nv"&gt;@tests&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;sort&lt;/span&gt; &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="sr"&gt;/^_test_/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nv"&gt;$stash&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;list_all_symbols&lt;/span&gt;&lt;span class="p"&gt;('&lt;/span&gt;&lt;span class="s1"&gt;CODE&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;$test&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;@tests&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;subtest&lt;/span&gt; &lt;span class="nv"&gt;$test&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$class&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;$test&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nv"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;diag&lt;/span&gt; &lt;span class="nv"&gt;$e&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;done_testing&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="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;_test_can&lt;/span&gt; &lt;span class="p"&gt;($class) {&lt;/span&gt;
    &lt;span class="nv"&gt;state&lt;/span&gt; &lt;span class="nv"&gt;@subs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sx"&gt;qw(run call_method methods test)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nv"&gt;can_ok&lt;/span&gt; &lt;span class="nv"&gt;$class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;\&lt;/span&gt;&lt;span class="nv"&gt;@subs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;can do: &lt;/span&gt;&lt;span class="si"&gt;@subs&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="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;sub &lt;/span&gt;&lt;span class="nf"&gt;_test_methods&lt;/span&gt; &lt;span class="p"&gt;($class) {&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$mock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;mock&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WebService::FOAAS&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="s"&gt;track&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;for&lt;/span&gt; &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$method&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$class&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;methods&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;$mock&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;override&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$method&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;ok&lt;/span&gt; &lt;span class="nv"&gt;lives&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$class&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;call_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$method&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;$method&lt;/span&gt;&lt;span class="s2"&gt; lives&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
        &lt;span class="nv"&gt;ok&lt;/span&gt; &lt;span class="nb"&gt;scalar&lt;/span&gt; &lt;span class="nv"&gt;$mock&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;sub_tracking&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;$method&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;@&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="si"&gt;$method&lt;/span&gt;&lt;span class="s2"&gt; called&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="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;_test_service_failure&lt;/span&gt; &lt;span class="p"&gt;($class) {&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$mock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;mock&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WebService::FOAAS&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;$method&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$class&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;methods&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;$mock&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;override&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$method&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="s1"&gt;mocked&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;my&lt;/span&gt; &lt;span class="nv"&gt;$exception&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
          &lt;span class="nv"&gt;dies&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$class&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;call_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="nv"&gt;isa_ok&lt;/span&gt; &lt;span class="nv"&gt;$exception&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ServiceError&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
          &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$method&lt;/span&gt;&lt;span class="s2"&gt; throws ServiceError on failure&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
        &lt;span class="nv"&gt;like&lt;/span&gt; &lt;span class="nv"&gt;$exception&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sx"&gt;qr/^mocked/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;correct error in &lt;/span&gt;&lt;span class="si"&gt;$method&lt;/span&gt;&lt;span class="s2"&gt; exception&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="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;&lt;em&gt;[Updated, thanks to &lt;a href="http://www.grinnz.com/" rel="noopener noreferrer"&gt;Dan Book&lt;/a&gt;, &lt;a href="https://github.com/karenetheridge" rel="noopener noreferrer"&gt;Karen Etheridge&lt;/a&gt;, and &lt;a href="https://metacpan.org/author/BOBK" rel="noopener noreferrer"&gt;Bob Kleemann&lt;/a&gt;]&lt;/em&gt; The only goofy bit above is the need to put the exception calls in a &lt;code&gt;BEGIN&lt;/code&gt; block and then explic­it­ly call &lt;code&gt;BEGIN { Local::CallFOAAS::Exceptions-&amp;gt;import() }&lt;/code&gt;. Since the two pack­ages are in the same file, I can’t do a &lt;code&gt;use&lt;/code&gt; state­ment since the implied &lt;a href="https://perldoc.perl.org/functions/require" rel="noopener noreferrer"&gt;&lt;code&gt;require&lt;/code&gt;&lt;/a&gt; would look for a cor­re­spond­ing file or entry in &lt;a href="https://perldoc.perl.org/variables/%25INC" rel="noopener noreferrer"&gt;&lt;code&gt;%INC&lt;/code&gt;&lt;/a&gt;. (You can get around this by mess­ing with &lt;code&gt;%INC&lt;/code&gt; direct­ly or through a mod­ule like &lt;a href="https://metacpan.org/pod/me::inlined" rel="noopener noreferrer"&gt;me::inlined&lt;/a&gt; that does that mess­ing for you, but for a single-​purpose mod­uli­no like this it’s fine.)&lt;/p&gt;




&lt;p&gt;&lt;a href="https://phoenixtrap.com/tip" rel="noopener noreferrer"&gt;Do you like what you see? Leave a tip!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>perl</category>
      <category>oop</category>
      <category>exceptions</category>
      <category>moo</category>
    </item>
  </channel>
</rss>
