<?xml version="1.0" encoding="us-ascii"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Perl Advent Calendar 2023</title><id>https://perladvent.org/2023/</id><link href="https://perladvent.org/2023/atom.xml" rel="self"/><updated>2026-04-14T18:25:16Z</updated><author><name>PerlAdvent Org</name></author><generator uri="https://metacpan.org/pod/XML::Atom::SimpleFeed" version="0.905">XML::Atom::SimpleFeed</generator><entry><title>24 Years of the Perl Advent Calendar</title><link href="https://perladvent.org/2023/2023-12-25.html"/><id>https://perladvent.org/2023/2023-12-25.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h3 id=&#34;The-Journey&#34;&gt;The Journey&lt;/h3&gt;

&lt;p&gt;It&#38;#39;s Christmas Day, marking the end of year 24 of the Perl Advent Calendar. Is there another programming Advent Calendar with a longer history? I don&#38;#39;t know and, to be honest, I haven&#38;#39;t checked, but this feels like an impressive accomplishment and a good time to take a look back on this monumental project.&lt;/p&gt;

&lt;p&gt;The archives begin &lt;a href=&#34;https://perladvent.org/2000&#34;&gt;in the year 2000&lt;/a&gt;. In those days, an Advent article was literally the documentation for a Perl module, beginning with &lt;a href=&#34;https://perladvent.org/2000/1/&#34;&gt;Data::Dumper&lt;/a&gt; on Dec 1 and ending with &lt;a href=&#34;https://perladvent.org/2000/25/&#34;&gt;Date::Christmas&lt;/a&gt; on the 25th. As an aside, &lt;a href=&#34;https://metacpan.org/module/Date::Christmas&#34;&gt;Date::Christmas&lt;/a&gt; had its last release on Dec 3, 2000 and it still works.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;$ cpm install -g Date::Christmas&lt;br /&gt;$ perl -MDate::Christmas -le &#39;print christmasday (2023)&#39;&lt;br /&gt;Monday&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you&#38;#39;re interested in the history of this project and how &lt;a href=&#34;https://metacpan.org/author/MARKF&#34;&gt;Mark Fowler&lt;/a&gt; came up with it, I encourage you to read the notes in &lt;a href=&#34;https://perladvent.org/FAQ.html&#34;&gt;the FAQ&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&#34;The-Stats&#34;&gt;The Stats&lt;/h3&gt;

&lt;p&gt;When I got involved in this project last year, I had just assumed that the calendar in its current format was much how it began, but that&#38;#39;s not really true. The layout and the URLs have evolved over time and there have been varying levels of activity. Let&#38;#39;s write a quick &lt;code&gt;bash&lt;/code&gt; script to figure out some statistics.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    #!/usr/bin/env bash

    set -eu -o pipefail

    for year in $(seq 2000 2010); do
        found=$(find &#38;quot;$year&#38;quot; | grep -e &#38;quot;/\d\d/index.html&#38;quot; -c)
        echo &#38;quot;$year $(printf &#38;quot;%0.s&#38;#x1F384;&#38;quot; $(seq 1 &#38;quot;$found&#38;quot;))&#38;quot;
    done

    for year in $(seq 2011 2023); do
        found=$(find &#38;quot;$year/articles&#38;quot; | grep -c pod$)
        echo &#38;quot;$year $(printf &#38;quot;%0.s&#38;#x1F384;&#38;quot; $(seq 1 &#38;quot;$found&#38;quot;))&#38;quot;
    done&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We get the following pretty graph:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    2000 &#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;
    2001 &#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;
    2002 &#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;
    2003 &#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;
    2004 &#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;
    2005 &#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;
    2006 &#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;
    2007 &#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;
    2008 &#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;
    2009 &#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;
    2010 &#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;
    2011 &#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;
    2012 &#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;
    2013 &#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;
    2014 &#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;
    2015 &#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;
    2016 &#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;
    2017 &#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;
    2018 &#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;
    2019 &#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;
    2020 &#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;
    2021 &#38;#x1F384;
    2022 &#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;
    2023 &#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&#38;#x1F384;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can see that years 2000 to 2006 had 25 articles. The following 4 years don&#38;#39;t quite make it to 25, but I would argue that the 24 articles in 2008 is genuinely &#38;quot;good enough&#38;quot;. 2020 was sort of greatest hits repackaging of articles from earlier years and 2021 is an outlier. Last year we had so much momentum that we added a couple of extra articles and this year we are back to the usual pace.&lt;/p&gt;

&lt;h3 id=&#34;The-Evolution&#34;&gt;The Evolution&lt;/h3&gt;

&lt;p&gt;As we noted above, the year 2000 was strictly Perl module documentation. The documentation angle may seem a bit weird, but back in 2000, CPAN &lt;a href=&#34;https://github.com/neilb/history-of-cpan/blob/master/history.md&#34;&gt;wasn&#38;#39;t all that old&lt;/a&gt;. Beginning in 2001, Mark wrote short blog posts about useful modules with his thoughts on them.&lt;/p&gt;

&lt;p&gt;How about the delightful Christmas-themed posts? Well, the first mention of Santa is not until &lt;a href=&#34;https://perladvent.org/2002/25th/&#34;&gt;Dec 25, 2002&lt;/a&gt;. St. Nick does not seem to re-appear until &lt;a href=&#34;https://perladvent.org/2006/10/&#34;&gt;Dec 10, 2006&lt;/a&gt;, the same year in which elves have their first mention.&lt;/p&gt;

&lt;p&gt;In 2011 the calendar shifts from the layout which mimics a traditional advent calendar to one which looks more like a regular calendar. I&#38;#39;m guessing this is due to the emergence of &lt;a href=&#34;https://metacpan.org/module/WWW::AdventCalendar&#34;&gt;WWW::AdventCalendar&lt;/a&gt;, which had its first release on &lt;a href=&#34;https://metacpan.org/release/RJBS/WWW-AdventCalendar-0.093580/view/lib/WWW/AdventCalendar.pm&#34;&gt;Dec 25, 2009&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I should also note that over the 24 years of this project there have been many, many blog authors and editors. It has been an impressive group effort with real continuity.&lt;/p&gt;

&lt;h3 id=&#34;Where-are-we-Now&#34;&gt;Where are we Now?&lt;/h3&gt;

&lt;p&gt;In the intervening years, the Perl Advent Calendar has become a holiday tradition for many of us and something we look forward to. It&#38;#39;s much more than just an interesting project, though. It&#38;#39;s a snapshot of Perl as it is being used in the wild, a wonderful trip down memory lane and it documents the evolution of a genre: technical writing that leans on and extends the mythology of a collective Christmas traditions. Also, it&#38;#39;s fun.&lt;/p&gt;

&lt;p&gt;There is a real legacy to the calendar, though. I don&#38;#39;t know how many of the authors imagined that decades later, their work would still be available for instructional reading and general enjoyment. Some of our personal blogs fade away as hosting disappears or even as we ourselves move on from this earth, but the calendar, after 24 years of service, documents the writings of Perl developers past and present.&lt;/p&gt;

&lt;p&gt;If you&#38;#39;re interested in becoming part of this history, we will accept articles throughout the year. The Call for Papers traditionally opens in the summer, but if you have a burning desire to write a blog post for the Advent Calendar, you can start right now and someone will be happy to help you along in the process.&lt;/p&gt;

&lt;h3 id=&#34;A-Big-Thank-You&#34;&gt;A Big Thank You&lt;/h3&gt;

&lt;p&gt;For this year in particular, I&#38;#39;d like to thank everyone who helped out with the calendar. &lt;a href=&#34;https://metacpan.org/author/BDFOY&#34;&gt;brian d foy&lt;/a&gt;, for kickstarting things in November when my mind was somewhere else. Also &lt;a href=&#34;https://metacpan.org/author/BDFOY&#34;&gt;brian d foy&lt;/a&gt; for reviewing articles and contributing articles. On that note a large debt is owed to &lt;a href=&#34;https://metacpan.org/author/HOUSTON&#34;&gt;Pete Houston&lt;/a&gt; for reviewing many articles, with a number of those being on very short notice. I&#38;#39;d like to thank all of this year&#38;#39;s authors and note that several of them contributed more than one article, which allowed us to make it to 25.&lt;/p&gt;

&lt;p&gt;Lastly, I&#38;#39;d like to thank &lt;a href=&#34;https://metacpan.org/author/MARKF&#34;&gt;Mark Fowler&lt;/a&gt; for allowing us to continue on this great tradition.&lt;/p&gt;

&lt;h3 id=&#34;A-Big-Anniversary&#34;&gt;A Big Anniversary&lt;/h3&gt;

&lt;p&gt;2024 will be year 25 of the Perl Advent Calandar. We should mark this in some way. How will we do it? We have a year to think about it.&lt;/p&gt;

&lt;p&gt;In the meantime, please allow me to wish all of our editors, contributors and readers a &#38;quot;Happy Christmas to All and to All a Good Night&#38;quot;.&lt;/p&gt;

&lt;/div&gt;</summary><updated>2023-12-25T00:00:00Z</updated><category term="Perl"/><author><name>olaf</name></author></entry><entry><title>Santa Kotlin is coming to Perl</title><link href="https://perladvent.org/2023/2023-12-24.html"/><id>https://perladvent.org/2023/2023-12-24.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;This post starts with a long introduction to explain &lt;i&gt;why&lt;/i&gt; I&#38;#39;m writing, but if you want to skip all of that you can jump directly to the &lt;a href=&#34;#Binding-to-Kotlin-from-Perl&#34;&gt;meat and potatoes&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&#34;Stay-awhile-and-listen&#34;&gt;Stay awhile and listen&lt;/h3&gt;

&lt;p&gt;I grew up as a Nintendo kid. Some of the first video games I played were on an NES, and the first console I ever owned was an SNES. I have very fond memories of those times and of the games I got to know and play.&lt;/p&gt;

&lt;p&gt;Although at the time I don&#38;#39;t think I considered applying that label to myself, it was very much a part of how I understood myself and my place among my peers. I was a Nintendo kid, and they... well, they were something else. Sega kids, maybe.&lt;/p&gt;

&lt;p&gt;This misguided sense of identity paired well with a misguided sense of loyalty, which made it so I found it difficult to enjoy both at the same time. If I was a &#38;quot;Nintendo&#38;quot; kid, what would it mean if I enjoyed Sega... things? What would it mean to &lt;i&gt;own&lt;/i&gt; one?&lt;/p&gt;

&lt;p&gt;This was not only related to video games, either. I remember very easily falling into this trap with all sorts of similar &#38;quot;contrasts&#38;quot;. I was a Beatles kid, so I couldn&#38;#39;t like The Rolling Stones. I was a Star Wars kid, so I couldn&#38;#39;t enjoy Star Trek. The list was tragically endless.&lt;/p&gt;

&lt;p&gt;This was not so hard when my team was inarguably better than the other. But I remember how hard it got to be a &#38;quot;Nintendo kid&#38;quot; when the PlayStation came around. It was gritty, it was powerful, it was exciting... and it &lt;i&gt;felt&lt;/i&gt; inaccessible.&lt;/p&gt;

&lt;h3 id=&#34;Am-I-still-reading-the-Perl-advent-calendar&#34;&gt;Am I still reading the Perl advent calendar?&lt;/h3&gt;

&lt;p&gt;Ah, yes. Perl.&lt;/p&gt;

&lt;p&gt;I&#38;#39;ve always loved Perl. It was not my very first programming language (you and me, BASIC, for life), but it was the first one where I felt like I could write real programs. The first that I felt was worth mastering, and the one I&#38;#39;m most comfortable with, even today.&lt;/p&gt;

&lt;p&gt;So, surprise surprise, I was a Perl kid.&lt;/p&gt;

&lt;p&gt;And there have been times when being a Perl kid has not been easy.&lt;/p&gt;

&lt;p&gt;I am fortunately past the time when I look at the world in terms of clubs that you belong to because of the things you like. I will have you know I can listen to both Radiohead &lt;i&gt;and&lt;/i&gt; Coldplay without breaking a sweat (I take no responsibility for deciding what contrasted with what).&lt;/p&gt;

&lt;p&gt;But to this day, there are aspects of this worldview that remain in me.&lt;/p&gt;

&lt;h3 id=&#34;Perls-PlayStation&#34;&gt;Perl&#38;#39;s PlayStation&lt;/h3&gt;

&lt;p&gt;I imagine this largely depends on my particular interests, but for the Perl kid in me, it was hard to see how easy the &lt;i&gt;other&lt;/i&gt; kids had it when they wanted to integrate with other languages.&lt;/p&gt;

&lt;p&gt;To me, this was the PlayStation to Perl&#38;#39;s Nintendo.&lt;/p&gt;

&lt;p&gt;I remember several attempts trying to teach my teenager-self how to write XS, so I could bind to this or that library. I remember feeling frustrated and defeated. I remember wondering if this meant that Perl was holding me back...&lt;/p&gt;

&lt;p&gt;The answer is &#38;quot;no&#38;quot;. &lt;i&gt;If&lt;/i&gt; I was being held back, it was me who was doing so by again thinking in terms of clubs.&lt;/p&gt;

&lt;p&gt;But even if I had continued to see the world through that lens, the Perl we have at our disposal today is miles from the Perl I learned as a kid. There are still, I am sure, plenty of areas where I think Perl has to catch up. But we are at a moment where Perl is positively blooming with new features and tools, that make catching up possible, if not outright easy.&lt;/p&gt;

&lt;p&gt;In the last two versions alone (at the time of writing, 5.36 and 5.38) we have &lt;a href=&#34;https://perldoc.pl/perl5360delta#iterating-over-multiple-values-at-a-time-(experimental)&#34;&gt;n-at-a-time iteration&lt;/a&gt;, &lt;a href=&#34;https://perldoc.pl/perl5360delta#try/catch-can-now-have-a-finally-block-(experimental)&#34;&gt;a native try with finally support&lt;/a&gt; (finally!), &lt;a href=&#34;https://perldoc.pl/perl5360delta#defer-blocks-(experimental)&#34;&gt;the new defer blocks&lt;/a&gt;, &lt;a href=&#34;https://perldoc.pl/perl5360delta#Stable-boolean-tracking&#34;&gt;native booleans&lt;/a&gt;, &lt;a href=&#34;https://perldoc.pl/perl5360delta#builtin-functions-(experimental)&#34;&gt;the new builtin namespace&lt;/a&gt;, and a powerful &lt;a href=&#34;https://perldoc.pl/perl5380delta#New-class-Feature&#34;&gt;new syntax for defining classes&lt;/a&gt;. Not to mention other recent native features (like sub signatures and the &lt;code&gt;isa&lt;/code&gt; operator), or the things made possible via CPAN: &lt;a href=&#34;https://metacpan.org/module/Future::AsyncAwait&#34;&gt;async/await support&lt;/a&gt;, the renewed efforts into &lt;a href=&#34;https://metacpan.org/module/PDL&#34;&gt;PDL&lt;/a&gt;, and what I might consider the jewel of modern Perl: &lt;a href=&#34;https://metacpan.org/module/FFI::Platypus&#34;&gt;FFI::Platypus&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Time will tell, but I feel like this is what it must feel like to live during a renaissance.&lt;/p&gt;

&lt;h3 id=&#34;Any-chance-of-having-actual-code-in-this-post&#34;&gt;Any chance of having actual code in this post?&lt;/h3&gt;

&lt;p&gt;Yes, I&#38;#39;m getting to that. Now that I&#38;#39;ve finished with the introduction we can get to the meat and potatoes of this post. I hope I didn&#38;#39;t lose too many of you along the way.&lt;/p&gt;

&lt;h3 id=&#34;Binding-to-Kotlin-from-Perl&#34;&gt;Binding to Kotlin from Perl&lt;/h3&gt;

&lt;p&gt;What motivated this post in the first place was a task at work where I was asked to look into the feasibility of integrating with a third-party that provided SDKs for several languages... but not Perl.&lt;/p&gt;

&lt;p&gt;Lucky for me, they had made the code of those SDKs publicly available, so I could examine it. And while looking through them I realised that most of the heavy lifting was done by binding to a shared C library. My teenager-self would have had a traumatic flashback sequence at this point, but this is modern Perl. We have &lt;a href=&#34;https://metacpan.org/module/FFI::Platypus&#34;&gt;FFI::Platypus&lt;/a&gt;. &#38;quot;This will be easy&#38;quot;, I thought.&lt;/p&gt;

&lt;p&gt;The challenge came when I realised that the library was originally written in Kotlin via what they know as &#38;quot;Kotlin/Native&#38;quot;, which &lt;a href=&#34;https://kotlinlang.org/docs/native-dynamic-libraries.html#generated-headers-file&#34;&gt;generates header files&lt;/a&gt; with some ad-hoc hoops for us to jump through. As an attempt at simplifying things, I&#38;#39;ve put together &lt;a href=&#34;https://github.com/jjatria/santa-kotlin&#34;&gt;a repository&lt;/a&gt; with a sort of sample distribution that you can play around with as an illustration. The code examples below will be taken from it.&lt;/p&gt;

&lt;p&gt;In any case, the native Kotlin extension will take code that looks like &lt;a href=&#34;https://github.com/jjatria/santa-kotlin/blob/91714e6a2928c54f738253537f1ee362bbc41b88/share/src/nativeMain/kotlin/example.kt&#34;&gt;this&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;package example&lt;br /&gt;&lt;br /&gt;fun reverseString(str: String) : String {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;return str.reversed()&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and eventually wrap it in a C struct which will look like the one below:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;synType&#34;&gt;typedef&lt;/span&gt; &lt;span class=&#34;synType&#34;&gt;struct&lt;/span&gt; {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synComment&#34;&gt;/* Service functions. */&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synComment&#34;&gt;// ... Snipped 28 fields with fields pointing to service functions&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synComment&#34;&gt;/* User functions. */&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synType&#34;&gt;struct&lt;/span&gt; {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synType&#34;&gt;struct&lt;/span&gt; {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synType&#34;&gt;struct&lt;/span&gt; {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synType&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;synType&#34;&gt;char&lt;/span&gt;* (*reverseString)(&lt;span class=&#34;synType&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;synType&#34;&gt;char&lt;/span&gt;* str);&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;} example;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;} root;&lt;br /&gt;&#38;nbsp;&#38;nbsp;} kotlin;&lt;br /&gt;} libexample_ExportedSymbols;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synType&#34;&gt;extern&lt;/span&gt; libexample_ExportedSymbols* libexample_symbols(&lt;span class=&#34;synType&#34;&gt;void&lt;/span&gt;);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which, to summarise, is exposing a global &lt;code&gt;libexample_symbols&lt;/code&gt; function which returns a pointer to a struct where the last field (named &lt;code&gt;kotlin&lt;/code&gt;) holds a pointer to a struct with a field (named &lt;code&gt;root&lt;/code&gt;) which holds a pointer to a struct with a field (named &lt;code&gt;example&lt;/code&gt;) which holds a pointer to the function that you wrote.&lt;/p&gt;

&lt;p&gt;That&#38;#39;s a mouthful.&lt;/p&gt;

&lt;p&gt;When I first saw this, and saw that doing it in eg. Ruby (the SDK I was looking at for guidance) was not only possible, but relatively simple-looking, I got pangs of that PlayStation feeling.&lt;/p&gt;

&lt;p&gt;But as it turns out, &lt;a href=&#34;https://metacpan.org/module/FFI::Platypus&#34;&gt;FFI::Platypus&lt;/a&gt; already gives us all the tools to deal with something like this.&lt;/p&gt;

&lt;p&gt;The first thing will be to define the nested structs, and for that we will need &lt;a href=&#34;https://metacpan.org/module/FFI::C&#34;&gt;FFI::C&lt;/a&gt; (remember that you can look at &lt;a href=&#34;https://github.com/jjatria/santa-kotlin/blob/main/lib/Santa/Kotlin.pm&#34;&gt;the whole file&lt;/a&gt; these snippets are taken from &lt;a href=&#34;https://github.com/jjatria/santa-kotlin&#34;&gt;in the sample repository&lt;/a&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;package&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;Santa::Kotlin::Example {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;FFI::C-&#38;gt;struct( &lt;span class=&#34;synConstant&#34;&gt;Example&lt;/span&gt; =&#38;gt; [&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;reverseString&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;&#39;opaque&#39;&lt;/span&gt;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;]);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;package&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;Santa::Kotlin::Root {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;FFI::C-&#38;gt;struct( &lt;span class=&#34;synConstant&#34;&gt;Root&lt;/span&gt; =&#38;gt; [ &lt;span class=&#34;synConstant&#34;&gt;example&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;&#39;Example&#39;&lt;/span&gt; ]);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;package&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;Santa::Kotlin::Kotlin {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;FFI::C-&#38;gt;struct( &lt;span class=&#34;synConstant&#34;&gt;Kotlin&lt;/span&gt; =&#38;gt; [ &lt;span class=&#34;synConstant&#34;&gt;root&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;&#39;Root&#39;&lt;/span&gt; ]);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;package&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;Santa::Kotlin::Symbols {&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;FFI::C-&#38;gt;struct( &lt;span class=&#34;synConstant&#34;&gt;Symbols&lt;/span&gt; =&#38;gt; [&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synComment&#34;&gt;# ... 28 skipped fields which we must have here too ...&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;kotlin&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;&#39;Kotlin&#39;&lt;/span&gt;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;]);&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These packages are only for internal use, so that&#38;#39;s why they have a newline after the &lt;code&gt;package&lt;/code&gt; keyword: it makes it so that if this code is ever put on CPAN, these packages will not be indexed.&lt;/p&gt;

&lt;p&gt;When defining a struct with &lt;a href=&#34;https://metacpan.org/module/FFI::C&#34;&gt;FFI::C&lt;/a&gt;, the first parameter is a name that can be referred to later, which is why these are defined from the inside (the ones most deeply nested) going out. It means I can refer to the types of the inner fields when defining the outer structs, like in the &lt;code&gt;root&lt;/code&gt; field of type &lt;code&gt;Root&lt;/code&gt; in the struct for the Santa::Kotlin::Kotlin package: since it is of type &lt;code&gt;Root&lt;/code&gt;, its value will automatically be cast into a Santa::Kotlin::Root object.&lt;/p&gt;

&lt;p&gt;We still need to get our hands on an instance of this outermost struct, and for that we have to bind to that global &lt;code&gt;libexample_symbols&lt;/code&gt; function:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;synComment&#34;&gt;# Register $ffi with FFI::C, so new types become available&lt;/span&gt;&lt;br /&gt;FFI::C-&#38;gt;ffi(&lt;span class=&#34;synIdentifier&#34;&gt;$ffi&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synComment&#34;&gt;# ...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$symbols&lt;/span&gt; = &lt;span class=&#34;synIdentifier&#34;&gt;$ffi&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;-&#38;gt;function( &lt;span class=&#34;synConstant&#34;&gt;libexample_symbols&lt;/span&gt; =&#38;gt; [&lt;span class=&#34;synConstant&#34;&gt;&#39;void&#39;&lt;/span&gt;] =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;&#39;Symbols&#39;&lt;/span&gt; )&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;-&#38;gt;();&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Since we&#38;#39;ve told &lt;a href=&#34;https://metacpan.org/module/FFI::C&#34;&gt;FFI::C&lt;/a&gt; that it should register any types it creates with this instance of &lt;a href=&#34;https://metacpan.org/module/FFI::Platypus&#34;&gt;FFI::Platypus&lt;/a&gt;, we can use the &lt;code&gt;Symbols&lt;/code&gt; type (which corresponds to the Santa::Kotlin::Symbols package defined above) as the return value of this function.&lt;/p&gt;

&lt;p&gt;Note also that we are not &lt;a href=&#34;https://metacpan.org/module/FFI::Platypus#attach&#34;&gt;attaching&lt;/a&gt; this function, because we are not going to expose it to our users. We only want to be able to call it once so we can get a reference to the struct it returns, which we store in &lt;code&gt;$symbols&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Once we&#38;#39;ve done all this preparation, we are ready to attach any functions in our &lt;code&gt;example&lt;/code&gt; Kotlin package to our Santa::Kotlin Perl package, and we do this by using the memory addresses of the functions we are interested in:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;synIdentifier&#34;&gt;$ffi&lt;/span&gt;-&#38;gt;attach(&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synComment&#34;&gt;#                  we look up the address    and give it a Perl name&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synComment&#34;&gt;#                                    \                 \&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;[ &lt;span class=&#34;synIdentifier&#34;&gt;$symbols&lt;/span&gt;-&#38;gt;kotlin-&#38;gt;root-&#38;gt;example-&#38;gt;reverseString, &lt;span class=&#34;synConstant&#34;&gt;&#39;reverse_string&#39;&lt;/span&gt; ],&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;[&lt;span class=&#34;synConstant&#34;&gt;&#39;string&#39;&lt;/span&gt;] =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;&#39;string&#39;&lt;/span&gt;,&lt;br /&gt;);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;At this point, we are ready to call this function as we would any other from our perl code:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;synStatement&#34;&gt;use &lt;/span&gt;Santa::Kotlin;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;Santa&lt;/span&gt;::Kotlin::reverse_string(&lt;span class=&#34;synConstant&#34;&gt;&#39;lrep ot gnimoc si niltok atnas&#39;&lt;/span&gt;);&lt;br /&gt;&lt;span class=&#34;synComment&#34;&gt;# OUTPUT: santa kotlin is coming to perl&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These are good times to be a Perl kid, so happy holidays to all the good ones out there.&lt;/p&gt;

&lt;p&gt;Happy hacking!&lt;/p&gt;

&lt;/div&gt;</summary><updated>2023-12-24T00:00:00Z</updated><category term="Perl"/><author><name>jjatria</name></author></entry><entry><title>Elves Versus Unused Imports</title><link href="https://perladvent.org/2023/2023-12-23.html"/><id>https://perladvent.org/2023/2023-12-23.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;Santa&#38;#39;s elves are interested in code quality. This is something we touched on about 9 years ago in &lt;a href=&#34;https://perladvent.org/2014/2014-12-16.html&#34;&gt;How Santa&#38;#39;s Elves Keep their Workshop Tidy&lt;/a&gt; and, more recently, in &lt;a href=&#34;https://perladvent.org/2023/2023-12-21.html&#34;&gt;Elves Versus Typos&lt;/a&gt;. Since the elves like keeping up with the times, they are currently experimenting with another, newer Perl code quality tool. It&#38;#39;s finally time to take a close look at &lt;a href=&#34;https://metacpan.org/dist/App-perlimports/view/script/perlimports&#34;&gt;perlimports&lt;/a&gt;. &lt;a href=&#34;https://metacpan.org/dist/App-perlimports/view/script/perlimports&#34;&gt;perlimports&lt;/a&gt; is a fixer -- it can rewrite your code for you. It&#38;#39;s also a linter, so you can use it to report on problems without fixing them. With this power comes great responsibility and &lt;code&gt;perlimports&lt;/code&gt; tries to be responsible. Inspired by &lt;a href=&#34;https://pkg.go.dev/golang.org/x/tools/cmd/goimports&#34;&gt;goimports&lt;/a&gt;, &lt;code&gt;perlimports&lt;/code&gt; is an opinionated tool which tries to force its opinions on your code. What you get in return is a tool which takes much of the burden of managing imports out of your hands.&lt;/p&gt;

&lt;p&gt;If you&#38;#39;re interested in an in-depth discussion of how &lt;code&gt;perlimports&lt;/code&gt; and Perl&#38;#39;s &lt;code&gt;use&lt;/code&gt; and &lt;code&gt;require&lt;/code&gt; work, check out this YouTube video from The Perl Conference in 2021: &lt;a href=&#34;https://www.youtube.com/watch?v=fKqxdTbGxYY&#34;&gt;perlimports or &#38;quot;Where did that symbol come from?&#38;quot;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As a bonus, if you make it to the bottom of this article, we&#38;#39;ll also explore a &lt;a href=&#34;https://github.com/houseabsolute/precious&#34;&gt;precious&lt;/a&gt;, which is a successor to &lt;a href=&#34;https://metacpan.org/module/Code::TidyAll&#34;&gt;Code::TidyAll&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&#34;Installation&#34;&gt;Installation&lt;/h3&gt;

&lt;p&gt;Let&#38;#39;s take a look at a typical getting started workflow. First the elves install the package from CPAN:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  cpm install -g App::perlimports&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once that is done, the elves are ready to try this out. They&#38;#39;ll probably just dive right in. The quick way to run &lt;code&gt;perlimports&lt;/code&gt; on a new repository might look something like this:&lt;/p&gt;

&lt;h3 id=&#34;Getting-Started&#34;&gt;Getting Started&lt;/h3&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;Clone a repo&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install *all* of the repository&#38;#39;s dependencies (including recommended)&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run the test suite&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ensure all of the tests are passing. If there are test failures, fix those first&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run &lt;code&gt;perlimports&lt;/code&gt; with the &lt;code&gt;--lint&lt;/code&gt; flag to see what changes it might make&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tweak the configuration until we&#38;#39;re happy with the linting results&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Apply &lt;code&gt;perlimports&lt;/code&gt; to the tests. We can do this via &lt;code&gt;perlimports -i t&lt;/code&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ensure all of the tests are still passing&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Commit the changes&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Move on to other parts of the code, like &lt;code&gt;lib&lt;/code&gt;. &lt;code&gt;perlimports --lint lib&lt;/code&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In a best case scenario, this &#38;quot;just works&#38;quot;. Let&#38;#39;s try it on a really old repository of mine.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;$ git clone https://github.com/oalders/acme-odometer.git&lt;br /&gt;$ cd acme-odometer/&lt;br /&gt;$ cpm install -g --with-recommends --cpanfile cpanfile&lt;br /&gt;$ yath t&lt;br /&gt;$ perlimports --lint t&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And indeed, all of the steps &#38;quot;just worked&#38;quot;. We ran the test(s) via &lt;a href=&#34;https://metacpan.org/module/yath&#34;&gt;yath&lt;/a&gt; and they passed. Why did we use &lt;a href=&#34;https://metacpan.org/module/yath&#34;&gt;yath&lt;/a&gt; rather than &lt;code&gt;make test&lt;/code&gt; or &lt;a href=&#34;https://metacpan.org/module/prove&#34;&gt;prove&lt;/a&gt;? We certainly could have done either of those things, but we&#38;#39;re trying to get in the habit of using more modern tools. &lt;a href=&#34;https://metacpan.org/module/yath&#34;&gt;yath&lt;/a&gt; comes bundled with &lt;a href=&#34;https://metacpan.org/module/Test2::Harness&#34;&gt;Test2::Harness&lt;/a&gt;. If you&#38;#39;d like to learn more about some of the features which &lt;a href=&#34;https://metacpan.org/module/Test2&#34;&gt;Test2&lt;/a&gt; provides, please see &lt;a href=&#34;https://perladvent.org/2023/2023-12-15.html&#34;&gt;Santa&#38;rsquo;s Workshop Secrets: The Magical Test2 Suite (Part 1)&lt;/a&gt; and &lt;a href=&#34;https://perladvent.org/2023/2023-12-16.html&#34;&gt;Santa&#38;rsquo;s Workshop Secrets: The Magical Test2 Suite (Part 2)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, let&#38;#39;s see what the linting looks like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    $ perlimports --lint t
    &#38;#x274C; Test::Most (import arguments need tidying) at t/load.t line 1
    @@ -1 +1 @@
    -use Test::Most;
    +use Test::Most import =&#38;gt; [ qw( done_testing ok ) ];

    &#38;#x274C; Acme::Odometer (import arguments need tidying) at t/load.t line 3
    @@ -3 +3 @@
    -use Acme::Odometer;
    +use Acme::Odometer ();

    &#38;#x274C; Path::Class (import arguments need tidying) at t/load.t line 4
    @@ -4 +4 @@
    -use Path::Class qw(file);
    +use Path::Class qw( file );&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can see three suggestions have been made. In the first suggestion, &lt;code&gt;perlimports&lt;/code&gt; has detected that &lt;code&gt;done_testing&lt;/code&gt; and &lt;code&gt;ok&lt;/code&gt; are the only functions exported by &lt;a href=&#34;https://metacpan.org/module/Test::Most&#34;&gt;Test::Most&lt;/a&gt; which the test is using, so it has made this explicit.&lt;/p&gt;

&lt;p&gt;In the second suggestion &lt;code&gt;perlimports&lt;/code&gt; has detected that the test is not importing any symbols from &lt;a href=&#34;https://metacpan.org/module/Acme::Odometer&#34;&gt;Acme::Odometer&lt;/a&gt;, so it has made this explicit by adding the empty round parens following the &lt;code&gt;use&lt;/code&gt; statement.&lt;/p&gt;

&lt;p&gt;In the third suggestion we see that some whitespace padding has been added to the &lt;a href=&#34;https://metacpan.org/module/Path::Class&#34;&gt;Path::Class&lt;/a&gt; import.&lt;/p&gt;

&lt;p&gt;If we don&#38;#39;t like these changes, we can tweak the configuration. To tell &lt;code&gt;perlimports&lt;/code&gt; to ignore &lt;a href=&#34;https://metacpan.org/module/Test::Most&#34;&gt;Test::Most&lt;/a&gt;, we can change our incantation:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  perlimports --lint --ignore-modules Test::Most t&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If we also don&#38;#39;t like the additional padding, we can turn that off:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  perlimports --lint --ignore-modules Test::Most --no-padding t&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Applying these settings we now get:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  $ perlimports --lint --ignore-modules Test::Most --no-padding t
  &#38;#x274C; Acme::Odometer (import arguments need tidying) at t/load.t line 3
  @@ -3 +3 @@
  -use Acme::Odometer;
  +use Acme::Odometer ();&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It&#38;#39;s time to update the actual file. We&#38;#39;ll use &lt;code&gt;-i&lt;/code&gt; for an inplace edit:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  $ perlimports -i --ignore-modules Test::Most --no-padding t&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The result is:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;git --no-pager diff t&lt;br /&gt;&lt;span class=&#34;synType&#34;&gt;diff --git a/t/load.t b/t/load.t&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synPreProc&#34;&gt;index 503d560..d19688f 100644&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synType&#34;&gt;--- a/t/load.t&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synType&#34;&gt;+++ b/t/load.t&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;@@ -1,6 +1,6 @@&lt;/span&gt;&lt;br /&gt;&#38;nbsp;use Test::Most;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synSpecial&#34;&gt;-use Acme::Odometer;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;+use Acme::Odometer ();&lt;/span&gt;&lt;br /&gt;&#38;nbsp;use Path::Class qw(file);&lt;br /&gt;&lt;br /&gt;&#38;nbsp;my $path = file( &#39;assets&#39;, &#39;odometer&#39; )-&#38;gt;stringify;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Are the tests still passing?&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;yath t&lt;br /&gt;&lt;br /&gt;** Defaulting to the &#39;test&#39; command **&lt;br /&gt;&lt;br /&gt;( PASSED )  job  1    t/load.t&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;Yath Result Summary&lt;br /&gt;-----------------------------------------------------------------------------------&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;File Count: 1&lt;br /&gt;Assertion Count: 3&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;Wall Time: 1.00 seconds&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;CPU Time: 1.42 seconds (usr: 0.32s | sys: 0.09s | cusr: 0.77s | csys: 0.24s)&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;CPU Usage: 142%&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;--&#38;gt;  Result: PASSED  &#38;lt;--&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Excellent. Let&#38;#39;s add the changes via &lt;code&gt;git&lt;/code&gt; and commit them. After that, let&#38;#39;s turn to the &lt;code&gt;lib&lt;/code&gt; directory.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    $ perlimports --lint --ignore-modules Test::Most --no-padding lib
    &#38;#x274C; namespace::clean (appears to be unused and should be removed) at lib/Acme/Odometer.pm line 9
    @@ -9 +8,0 @@
    -use namespace::clean;

    &#38;#x274C; GD (import arguments need tidying) at lib/Acme/Odometer.pm line 11
    @@ -11 +11 @@
    -use GD;
    +use GD ();

    &#38;#x274C; Memoize (import arguments need tidying) at lib/Acme/Odometer.pm line 12
    @@ -12 +12 @@
    -use Memoize;
    +use Memoize qw(memoize);

    &#38;#x274C; Path::Class (import arguments need tidying) at lib/Acme/Odometer.pm line 14
    @@ -14 +14 @@
    -use Path::Class qw( file );
    +use Path::Class qw(file);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, we already see some issues. First off, &lt;code&gt;perlimports&lt;/code&gt; doesn&#38;#39;t seem to know about &lt;a href=&#34;https://metacpan.org/module/namespace::clean&#34;&gt;namespace::clean&lt;/a&gt;. That&#38;#39;s ok. We can ignore it.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  perlimports --lint --ignore-modules namespace::clean,Test::Most --no-padding lib&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As an aside, we could also update the code to use &lt;a href=&#34;https://metacpan.org/module/namespace::autoclean&#34;&gt;namespace::autoclean&lt;/a&gt; while we&#38;#39;re poking around, but we&#38;#39;re trying to make minimal changes in this first iteration.&lt;/p&gt;

&lt;p&gt;The last suggestion is to remove the padding from the &lt;a href=&#34;https://metacpan.org/module/Path::Class&#34;&gt;Path::Class&lt;/a&gt; imports. It&#38;#39;s good to be consistent. The second and third suggestions look to be solid. Let&#38;#39;s make this change.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  perlimports -i --ignore-modules namespace::clean,Test::Most --no-padding lib&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That gives us:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;$ git --no-pager diff lib&lt;br /&gt;&lt;span class=&#34;synType&#34;&gt;diff --git a/lib/Acme/Odometer.pm b/lib/Acme/Odometer.pm&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synPreProc&#34;&gt;index 7fee773..cb1734e 100644&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synType&#34;&gt;--- a/lib/Acme/Odometer.pm&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synType&#34;&gt;+++ b/lib/Acme/Odometer.pm&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;@@ -8,10 +8,10 @@&lt;/span&gt;&lt;span class=&#34;synPreProc&#34;&gt; package Acme::Odometer;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;use Moo 1.001;&lt;br /&gt;&#38;nbsp;use namespace::clean;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synSpecial&#34;&gt;-use GD;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synSpecial&#34;&gt;-use Memoize;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;+use GD ();&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;+use Memoize qw(memoize);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;use MooX::Types::MooseLike::Numeric qw(PositiveInt PositiveOrZeroInt);&lt;br /&gt;&lt;span class=&#34;synSpecial&#34;&gt;-use Path::Class qw( file );&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;+use Path::Class qw(file);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&#38;#39;s pretty good. Do the tests still pass? Yes, they do. So, we can commit this change as well.&lt;/p&gt;

&lt;h3 id=&#34;A-Configuration-File&#34;&gt;A Configuration File&lt;/h3&gt;

&lt;p&gt;Now, this is all well and good, but what if we want to run &lt;code&gt;perlimports&lt;/code&gt; via &lt;a href=&#34;https://github.com/bscan/PerlNavigator&#34;&gt;the Perl Navigator Language Server&lt;/a&gt;? It would be better if we didn&#38;#39;t have to worry about the custom command line switches. This sounds like a good time to create a config file.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;perlimports --create-config-file perlimports.toml&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Nice! We have a stub configuration file. Let&#38;#39;s see what&#38;#39;s inside &lt;code&gt;perlimports.toml&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;# Valid log levels are:&lt;br /&gt;# debug, info, notice, warning, error, critical, alert, emergency&lt;br /&gt;# critical, alert and emergency are not currently used.&lt;br /&gt;#&lt;br /&gt;# Please use boolean values in this config file. Negated options (--no-*) are&lt;br /&gt;# not permitted here. Explicitly set options to true or false.&lt;br /&gt;#&lt;br /&gt;# Some of these values deviate from the regular perlimports defaults. In&lt;br /&gt;# particular, you&#39;re encouraged to leave preserve_duplicates and&lt;br /&gt;# preserve_unused disabled.&lt;br /&gt;&lt;br /&gt;cache                           = false # setting this to true is currently discouraged&lt;br /&gt;ignore_modules                  = []&lt;br /&gt;ignore_modules_filename         = &#38;quot;&#38;quot;&lt;br /&gt;ignore_modules_pattern          = &#38;quot;&#38;quot; # regex like &#38;quot;^(Foo|Foo::Bar)&#38;quot;&lt;br /&gt;ignore_modules_pattern_filename = &#38;quot;&#38;quot;&lt;br /&gt;libs                            = [&#38;quot;lib&#38;quot;, &#38;quot;t/lib&#38;quot;]&lt;br /&gt;log_filename                    = &#38;quot;&#38;quot;&lt;br /&gt;log_level                       = &#38;quot;warn&#38;quot;&lt;br /&gt;never_export_modules            = []&lt;br /&gt;never_export_modules_filename   = &#38;quot;&#38;quot;&lt;br /&gt;padding                         = true&lt;br /&gt;preserve_duplicates             = false&lt;br /&gt;preserve_unused                 = false&lt;br /&gt;tidy_whitespace                 = true&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let&#38;#39;s commit the stub file to git and then let&#38;#39;s move our command line switches to the config file. The diff should look something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;$ git --no-pager diff perlimports.toml&lt;br /&gt;&lt;span class=&#34;synType&#34;&gt;diff --git a/perlimports.toml b/perlimports.toml&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synPreProc&#34;&gt;index d631998..1e54c9e 100644&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synType&#34;&gt;--- a/perlimports.toml&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synType&#34;&gt;+++ b/perlimports.toml&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;@@ -10,7 +10,7 @@&lt;/span&gt;&lt;br /&gt;&#38;nbsp;# preserve_unused disabled.&lt;br /&gt;&lt;br /&gt;&#38;nbsp;cache                           = false # setting this to true is currently discouraged&lt;br /&gt;&lt;span class=&#34;synSpecial&#34;&gt;-ignore_modules                  = []&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;+ignore_modules                  = [&#38;quot;namespace::clean&#38;quot;, &#38;quot;Test::Most&#38;quot;]&lt;/span&gt;&lt;br /&gt;&#38;nbsp;ignore_modules_filename         = &#38;quot;&#38;quot;&lt;br /&gt;&#38;nbsp;ignore_modules_pattern          = &#38;quot;&#38;quot; # regex like &#38;quot;^(Foo|Foo::Bar)&#38;quot;&lt;br /&gt;&#38;nbsp;ignore_modules_pattern_filename = &#38;quot;&#38;quot;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;@@ -19,7 +19,7 @@&lt;/span&gt;&lt;span class=&#34;synPreProc&#34;&gt; log_filename                    = &#38;quot;&#38;quot;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;log_level                       = &#38;quot;warn&#38;quot;&lt;br /&gt;&#38;nbsp;never_export_modules            = []&lt;br /&gt;&#38;nbsp;never_export_modules_filename   = &#38;quot;&#38;quot;&lt;br /&gt;&lt;span class=&#34;synSpecial&#34;&gt;-padding                         = true&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;+padding                         = false&lt;/span&gt;&lt;br /&gt;&#38;nbsp;preserve_duplicates             = false&lt;br /&gt;&#38;nbsp;preserve_unused                 = false&lt;br /&gt;&#38;nbsp;tidy_whitespace                 = true&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;Integrations&#34;&gt;Integrations&lt;/h3&gt;

&lt;p&gt;That&#38;#39;s it! Now, when we apply &lt;code&gt;perlimports&lt;/code&gt; via Perl Navigator, our custom configuration will be respected. Also, we can now run &lt;code&gt;perlimports&lt;/code&gt; from the command line without needing to include the &lt;code&gt;--ignore-modules&lt;/code&gt; and &lt;code&gt;--no-padding&lt;/code&gt; flags. We can think about adding &lt;code&gt;perlimports&lt;/code&gt; to our Continuous Integration and &lt;code&gt;pre-commit&lt;/code&gt; hooks as well, so that we maintain the changes we&#38;#39;ve just imposed.&lt;/p&gt;

&lt;p&gt;As a bonus, if you are a &lt;code&gt;neovim&lt;/code&gt; user and you&#38;#39;re using &lt;a href=&#34;https://github.com/jose-elias-alvarez/null-ls.nvim&#34;&gt;null-ls&lt;/a&gt; or its successor &lt;a href=&#34;https://github.com/nvimtools/none-ls.nvim/blob/main/doc/BUILTINS.md&#34;&gt;none-ls&lt;/a&gt;, then &lt;code&gt;perlimports&lt;/code&gt; is already available as a builtin. We can now apply &lt;code&gt;perlimports&lt;/code&gt; as part of your &#38;quot;format on save&#38;quot; behaviours.&lt;/p&gt;

&lt;h3 id=&#34;The-Power-of-precious&#34;&gt;The Power of precious&lt;/h3&gt;

&lt;p&gt;We talked about using &lt;a href=&#34;https://metacpan.org/module/Code::TidyAll&#34;&gt;Code::TidyAll&lt;/a&gt; in &lt;a href=&#34;https://perladvent.org/2014/2014-12-16.html&#34;&gt;How Santa&#38;#39;s Elves Keep their Workshop Tidy&lt;/a&gt;. &lt;a href=&#34;https://metacpan.org/module/tidyall&#34;&gt;tidyall&lt;/a&gt; is a wonderful tool that solves a lot of problems, but its design was not perfect and it&#38;#39;s looking for a new maintainer. In the meantime, &lt;a href=&#34;https://github.com/houseabsolute/precious&#34;&gt;precious&lt;/a&gt; has drawn inspiration from &lt;a href=&#34;https://metacpan.org/module/tidyall&#34;&gt;tidyall&lt;/a&gt; and can be regarded as its spiritual successor, even if it&#38;#39;s written in Rust. If we want to run &lt;code&gt;perlimports&lt;/code&gt; along with other fixing and linting tools, we can use &lt;code&gt;precious&lt;/code&gt; for this.&lt;/p&gt;

&lt;p&gt;We won&#38;#39;t cover installation here, but after installing &lt;code&gt;precious&lt;/code&gt; we can generate a stub config file:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;$ precious config init --component perl&lt;br /&gt;&lt;br /&gt;Writing precious.toml&lt;br /&gt;&lt;br /&gt;The generated precious.toml requires the following tools to be installed:&lt;br /&gt;&#38;nbsp;&#38;nbsp;https://metacpan.org/dist/Perl-Critic&lt;br /&gt;&#38;nbsp;&#38;nbsp;https://metacpan.org/dist/Perl-Tidy&lt;br /&gt;&#38;nbsp;&#38;nbsp;https://metacpan.org/dist/App-perlimports&lt;br /&gt;&#38;nbsp;&#38;nbsp;https://metacpan.org/dist/Pod-Checker&lt;br /&gt;&#38;nbsp;&#38;nbsp;https://metacpan.org/dist/Pod-Tidy&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let&#38;#39;s have a look at the created file:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;excludes = [&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;quot;.build/**&#38;quot;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;quot;blib/**&#38;quot;,&lt;br /&gt;]&lt;br /&gt;&lt;br /&gt;[commands.perlcritic]&lt;br /&gt;type = &#38;quot;lint&#38;quot;&lt;br /&gt;include = [ &#38;quot;**/*.{pl,pm,t,psgi}&#38;quot; ]&lt;br /&gt;cmd = [ &#38;quot;perlcritic&#38;quot;, &#38;quot;--profile=$PRECIOUS_ROOT/perlcriticrc&#38;quot; ]&lt;br /&gt;ok_exit_codes = 0&lt;br /&gt;lint_failure_exit_codes = 2&lt;br /&gt;&lt;br /&gt;[commands.perltidy]&lt;br /&gt;type = &#38;quot;both&#38;quot;&lt;br /&gt;include = [ &#38;quot;**/*.{pl,pm,t,psgi}&#38;quot; ]&lt;br /&gt;cmd = [ &#38;quot;perltidy&#38;quot;, &#38;quot;--profile=$PRECIOUS_ROOT/perltidyrc&#38;quot; ]&lt;br /&gt;lint_flags = [ &#38;quot;--assert-tidy&#38;quot;, &#38;quot;--no-standard-output&#38;quot;, &#38;quot;--outfile=/dev/null&#38;quot; ]&lt;br /&gt;tidy_flags = [ &#38;quot;--backup-and-modify-in-place&#38;quot;, &#38;quot;--backup-file-extension=/&#38;quot; ]&lt;br /&gt;ok_exit_codes = 0&lt;br /&gt;lint_failure_exit_codes = 2&lt;br /&gt;ignore_stderr = &#38;quot;Begin Error Output Stream&#38;quot;&lt;br /&gt;&lt;br /&gt;[commands.perlimports]&lt;br /&gt;type = &#38;quot;both&#38;quot;&lt;br /&gt;include = [ &#38;quot;**/*.{pl,pm,t,psgi}&#38;quot; ]&lt;br /&gt;cmd = [ &#38;quot;perlimports&#38;quot; ]&lt;br /&gt;lint_flags = [&#38;quot;--lint&#38;quot; ]&lt;br /&gt;tidy_flags = [&#38;quot;-i&#38;quot; ]&lt;br /&gt;ok_exit_codes = 0&lt;br /&gt;expect_stderr = true&lt;br /&gt;&lt;br /&gt;[commands.podchecker]&lt;br /&gt;type = &#38;quot;lint&#38;quot;&lt;br /&gt;include = [ &#38;quot;**/*.{pl,pm,pod}&#38;quot; ]&lt;br /&gt;cmd = [ &#38;quot;podchecker&#38;quot;, &#38;quot;--warnings&#38;quot;, &#38;quot;--warnings&#38;quot; ]&lt;br /&gt;ok_exit_codes = [ 0, 2 ]&lt;br /&gt;lint_failure_exit_codes = 1&lt;br /&gt;ignore_stderr = [&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;quot;.+ pod syntax OK&#38;quot;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;quot;.+ does not contain any pod commands&#38;quot;,&lt;br /&gt;]&lt;br /&gt;&lt;br /&gt;[commands.podtidy]&lt;br /&gt;type = &#38;quot;tidy&#38;quot;&lt;br /&gt;include = [ &#38;quot;**/*.{pl,pm,pod}&#38;quot; ]&lt;br /&gt;cmd = [ &#38;quot;podtidy&#38;quot;, &#38;quot;--columns&#38;quot;, &#38;quot;80&#38;quot;, &#38;quot;--inplace&#38;quot;, &#38;quot;--nobackup&#38;quot; ]&lt;br /&gt;ok_exit_codes = 0&lt;br /&gt;lint_failure_exit_codes = 1&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can see that the config already includes a linting and tidying configuration for lots of helpful Perl linters and tidiers, including &lt;code&gt;perlimports&lt;/code&gt;. Now, we can run &lt;code&gt;precious tidy --all&lt;/code&gt; or &lt;code&gt;precious lint --all&lt;/code&gt; to run all sorts of helpfu checks in &lt;code&gt;pre-commit&lt;/code&gt; hooks and other places where code quality needs to be ensured.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;precious&lt;/code&gt; is a powerful tool and it merits its own blog post, but let&#38;#39;s leave this as a quick introduction. Perhaps you&#38;#39;ll feel inspired to try it out.&lt;/p&gt;

&lt;h3 id=&#34;The-State-of-the-Workshop&#34;&gt;The State of the Workshop&lt;/h3&gt;

&lt;p&gt;And as for Santa&#38;#39;s elves? They have a large codebase which doesn&#38;#39;t have 100% test coverage, so they&#38;#39;re starting slowly with the changes introduced by &lt;code&gt;perlimports&lt;/code&gt;. After applying &lt;code&gt;perlimports&lt;/code&gt; to the test suite, they&#38;#39;ve also applied it to the files which have very good test coverage. Once they&#38;#39;re confident in those changes, they&#38;#39;ll move on to other parts of the codebase. Once they have an updated list of modules which &lt;code&gt;perlimports&lt;/code&gt; should always ignore, maybe they&#38;#39;ll even send in a patch to the maintainer. &#38;#x1F91E;&lt;/p&gt;

&lt;/div&gt;</summary><updated>2023-12-23T00:00:00Z</updated><category term="Perl"/><author><name>olaf</name></author></entry><entry><title type="html">St. Nick&#38;#39;s Reindeers Need More H2O!</title><link href="https://perladvent.org/2023/2023-12-22.html"/><id>https://perladvent.org/2023/2023-12-22.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;Last year in 2022 [1], Santa Claus discovered a very useful Perl module called &lt;a href=&#34;https://metacpan.org/module/Util::H2O&#34;&gt;Util::H2O&lt;/a&gt; that makes it very seamless to add &lt;i&gt;object oriented programming&lt;/i&gt; conveniences to Perl programs; it is particularly useful when it comes to adding Perl OOP to existing or legacy code bases.&lt;/p&gt;

&lt;p&gt;Over the past year, he&#38;#39;s done quite a bit of digging into a related module named, &lt;a href=&#34;https://metacpan.org/module/Util::H2O::More&#34;&gt;Util::H2O::More&lt;/a&gt;. The following is a summary of a few neat things available in this module, most of which are built upon &lt;a href=&#34;https://metacpan.org/module/Util::H2O&#34;&gt;Util::H2O&lt;/a&gt;&#38;#39;s &lt;code&gt;h2o&lt;/code&gt; method which gives accessors to to &lt;code&gt;HASH&lt;/code&gt; references - and the &lt;i&gt;inverse&lt;/i&gt;, that converts an &lt;i&gt;blessed&lt;/i&gt; reference with accessors into a pure &lt;code&gt;HASH&lt;/code&gt; reference, &lt;code&gt;o2h&lt;/code&gt;. There&#38;#39;s a mnemonic there, &lt;b&gt;h&lt;/b&gt;ash &lt;b&gt;2&lt;/b&gt; &lt;b&gt;o&lt;/b&gt;bject; and the reverse, &lt;b&gt;o&lt;/b&gt;ject &lt;b&gt;2&lt;/b&gt; &lt;b&gt;h&lt;/b&gt;ash. All of the public methods try to follow this pattern, which will hopefully be apparent below.&lt;/p&gt;

&lt;h3 id=&#34;Santas-Got-Options...-for-Options&#34;&gt;Santa&#38;#39;s Got Options... for Options&lt;/h3&gt;

&lt;p&gt;There are lots of modules on CPAN that present &lt;a href=&#34;https://metacpan.org/module/Getopt::Long&#34;&gt;Getopt::Long&lt;/a&gt; in different ways. &lt;a href=&#34;https://metacpan.org/module/Util::H2O::More&#34;&gt;Util::H2O::More&lt;/a&gt; makes its entry into the mix with two different methods; one that builds upon the other.&lt;/p&gt;

&lt;p&gt;The first is a nifty method called &lt;code&gt;opt2h2o&lt;/code&gt;. This method makes it more convenient to define the fields of a reference destined to be objectified by &lt;code&gt;h2o&lt;/code&gt; by using the parameter array description format used by &lt;code&gt;Getopt::Long::GetOptionsFromArray&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;opt2h2o&lt;/code&gt; is used to provide a list of default accessors to &lt;code&gt;h2o&lt;/code&gt; to a given &lt;code&gt;HASH&lt;/code&gt; reference. This reference is then provided to &lt;code&gt;GetOptionsFromArray&lt;/code&gt;, as shown in the example below that can explain better than mere words:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;synStatement&#34;&gt;use strict&lt;/span&gt;;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;use warnings&lt;/span&gt;;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;use &lt;/span&gt;Util::H2O::More &lt;span class=&#34;synConstant&#34;&gt;qw/h2o opt2h2o/&lt;/span&gt;;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;use &lt;/span&gt;Getopt::Long &lt;span class=&#34;synConstant&#34;&gt;qw//&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;@opts&lt;/span&gt; = (&lt;span class=&#34;synConstant&#34;&gt;qw/name=s country=s meaning=s/&lt;/span&gt;);&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$o&lt;/span&gt; = h2o { &lt;span class=&#34;synConstant&#34;&gt;meaning&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;q{???}&lt;/span&gt; }, opt2h2o(&lt;span class=&#34;synIdentifier&#34;&gt;@opts&lt;/span&gt;);     &lt;span class=&#34;synComment&#34;&gt;# example showing how to set default&lt;/span&gt;&lt;br /&gt;Getopt::Long::GetOptionsFromArray( \&lt;span class=&#34;synIdentifier&#34;&gt;@ARGV&lt;/span&gt;, &lt;span class=&#34;synIdentifier&#34;&gt;$o&lt;/span&gt;, &lt;span class=&#34;synIdentifier&#34;&gt;@opts&lt;/span&gt; );&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;if&lt;/span&gt; (&lt;span class=&#34;synIdentifier&#34;&gt;$o&lt;/span&gt;-&#38;gt;country) {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;printf&lt;/span&gt; &lt;span class=&#34;synConstant&#34;&gt;qq{Did you know, Santa is known as &#39;%s&#39; in the country/region of %s? It means, &#38;quot;%s&#38;quot;!&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;}&lt;/span&gt;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;$o&lt;/span&gt;-&#38;gt;name, &lt;span class=&#34;synIdentifier&#34;&gt;$o&lt;/span&gt;-&#38;gt;country, &lt;span class=&#34;synIdentifier&#34;&gt;$o&lt;/span&gt;-&#38;gt;meaning;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which results in,&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;prompt&#38;gt; perl Santa-facts.pl --name Jultomten --meaning &#38;quot;Christmas Brownie&#38;quot; --country Sweden&lt;br /&gt;Did you know, Santa is known as &#39;Jultomten&#39; in the country/region of Sweden? It means, &#38;quot;Christmas Brownie&#38;quot;!&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But as famous &lt;i&gt;elvish&lt;/i&gt; pitchman, Willy Nays says, &lt;i&gt;but wait, there&#38;#39;s more ...!&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Util::H2O::More&#34;&gt;Util::H2O::More&lt;/a&gt; has a method that combines everything, including the need to &lt;code&gt;require Getopt::Long;&lt;/code&gt;, called &lt;code&gt;Getopt2h2o&lt;/code&gt;; it can dramatically shorten the amount of typing needed to process options &lt;i&gt;and&lt;/i&gt; provide accessors to the options:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;synStatement&#34;&gt;use strict&lt;/span&gt;;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;use warnings&lt;/span&gt;;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;use &lt;/span&gt;Util::H2O::More &lt;span class=&#34;synConstant&#34;&gt;qw/Getopt2h2o/&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$o&lt;/span&gt; = Getopt2h2o \&lt;span class=&#34;synIdentifier&#34;&gt;@ARGV&lt;/span&gt;, { &lt;span class=&#34;synConstant&#34;&gt;meaning&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;q{???}&lt;/span&gt; }, &lt;span class=&#34;synConstant&#34;&gt;qw/name=s country=s meaning=s/&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;if&lt;/span&gt; (&lt;span class=&#34;synIdentifier&#34;&gt;$o&lt;/span&gt;-&#38;gt;country) {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;printf&lt;/span&gt; &lt;span class=&#34;synConstant&#34;&gt;qq{Did you know, Santa is known as &#39;%s&#39; in the country/region of %s? It means, &#38;quot;%s&#38;quot;!&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;}&lt;/span&gt;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;$o&lt;/span&gt;-&#38;gt;name, &lt;span class=&#34;synIdentifier&#34;&gt;$o&lt;/span&gt;-&#38;gt;country, &lt;span class=&#34;synIdentifier&#34;&gt;$o&lt;/span&gt;-&#38;gt;meaning;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which results in,&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;prompt&#38;gt; perl ./Santa-facts.pl --name Christkindl --meaning &#38;quot;Christ child&#38;quot; --country Germany&lt;br /&gt;Did you know, Santa is known as &#39;Christkindl&#39; in the country/region of Germany? It means, &#38;quot;Christ child&#38;quot;!&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Personally Santa prefers this version the best. He still loves brownies very much, as his waistline can attest - especially with red soda from the local grocer!&lt;/p&gt;

&lt;h3 id=&#34;Ye-Old-Configuration-Files&#34;&gt;Ye Old Configuration Files&lt;/h3&gt;

&lt;h4 id=&#34;Config::Tiny&#34;&gt;&lt;code&gt;Config::Tiny&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Util::H2O::More&#34;&gt;Util::H2O::More&lt;/a&gt; also has a couple of convenient options for handling conf files written in both &lt;i&gt;.ini&lt;/i&gt; and &lt;i&gt;YAML&lt;/i&gt; formats.&lt;/p&gt;

&lt;p&gt;The first method is designed to provide accessors to configuration references provided by &lt;a href=&#34;https://metacpan.org/module/Config::Tiny&#34;&gt;Config::Tiny&lt;/a&gt;; in fact there is no need to explicitly &lt;code&gt;use&lt;/code&gt; or &lt;code&gt;require&lt;/code&gt; &lt;a href=&#34;https://metacpan.org/module/Config::Tiny&#34;&gt;Config::Tiny&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We begin with an &lt;i&gt;INI&lt;/i&gt; format configuratino file, &lt;code&gt;santa.ini&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  ; santa.ini
  ;   this is an ini file that is
  ;   used to power Santa&#38;#39;s Facts
  ;   generating Perl script

  [SantaByCountry]
  Afghanistan=Aba Chaghaloo, ???
  Greece=&#38;Alpha;&#38;gamma;&#38;iota;&#38;omicron;&#38;sigmaf; &#38;Beta;&#38;alpha;&#38;sigma;&#38;#x3AF;&#38;lambda;&#38;eta;&#38;sigmaf;, Santa Clause
  Sweden=Jultomten, Christmas Brownie
  Austria=Christkind, Christ Child
  Switzerland=Christkindl, Christ Child
  Germany=Christkindle, Christ Child
  Mexico=Ni&#38;ntilde;o Dios, God Child
  CentralAmerica=Ni&#38;ntilde;o Jes&#38;uacute;s, Baby Jesus

  ; sample from https://www.historiesdarkmysteries.com/2021/12/the-surprising-origins-of-jolly-old-st.html&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Combining the joys of &lt;code&gt;Getopt2h2o&lt;/code&gt; with &lt;code&gt;ini2h2o&lt;/code&gt;, we get a pretty compact script with minimal set up. The example below is not missing it&#38;#39;s statement to &lt;code&gt;use Config::Tiny&lt;/code&gt; - &lt;code&gt;ini2h2o&lt;/code&gt; handles that internally.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;synStatement&#34;&gt;use strict&lt;/span&gt;;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;use warnings&lt;/span&gt;;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;use &lt;/span&gt;Util::H2O::More &lt;span class=&#34;synConstant&#34;&gt;qw/Getopt2h2o ini2h2o/&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$o&lt;/span&gt; = Getopt2h2o \&lt;span class=&#34;synIdentifier&#34;&gt;@ARGV&lt;/span&gt;, { &lt;span class=&#34;synConstant&#34;&gt;conf&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;q{./santa.ini}&lt;/span&gt; }, &lt;span class=&#34;synConstant&#34;&gt;qw/conf=s/&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$conf&lt;/span&gt; = ini2h2o &lt;span class=&#34;synIdentifier&#34;&gt;$o&lt;/span&gt;-&#38;gt;conf;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;synConstant&#34;&gt;qq{Did You Know:&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;}&lt;/span&gt;;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$country&lt;/span&gt; (&lt;span class=&#34;synStatement&#34;&gt;keys&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;%{$conf&lt;/span&gt;-&#38;gt;SantaByCountry&lt;span class=&#34;synIdentifier&#34;&gt;}&lt;/span&gt;) {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$entry&lt;/span&gt; = &lt;span class=&#34;synIdentifier&#34;&gt;$conf&lt;/span&gt;-&#38;gt;SantaByCountry-&#38;gt;&lt;span class=&#34;synIdentifier&#34;&gt;$country&lt;/span&gt;;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; (&lt;span class=&#34;synIdentifier&#34;&gt;$name&lt;/span&gt;, &lt;span class=&#34;synIdentifier&#34;&gt;$meaning&lt;/span&gt;) = &lt;span class=&#34;synStatement&#34;&gt;split&lt;/span&gt; &lt;span class=&#34;synStatement&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;, &lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;+&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;/&lt;/span&gt;, &lt;span class=&#34;synIdentifier&#34;&gt;$entry&lt;/span&gt;;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;printf&lt;/span&gt; &lt;span class=&#34;synConstant&#34;&gt;qq{  + Santa is known as &#39;%s&#39; in the country/region of %s? It means, &#38;quot;%s&#38;quot;!&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;}&lt;/span&gt;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;$name&lt;/span&gt;, &lt;span class=&#34;synIdentifier&#34;&gt;$country&lt;/span&gt;, &lt;span class=&#34;synIdentifier&#34;&gt;$meaning&lt;/span&gt;;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And running this script with the configuration file yields,&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;prompt&#38;gt; perl ./Santa-facts.pl&lt;br /&gt;Did You Know:&lt;br /&gt;&#38;nbsp;&#38;nbsp;+ Santa is known as &#39;Aba Chaghaloo&#39; in the country/region of Afghanistan? It means, &#38;quot;???&#38;quot;!&lt;br /&gt;&#38;nbsp;&#38;nbsp;+ Santa is known as &#39;Ni&#195;&#177;o Jes&#195;&#186;s&#39; in the country/region of CentralAmerica? It means, &#38;quot;Baby Jesus&#38;quot;!&lt;br /&gt;&#38;nbsp;&#38;nbsp;+ Santa is known as &#39;Ni&#195;&#177;o Dios&#39; in the country/region of Mexico? It means, &#38;quot;God Child&#38;quot;!&lt;br /&gt;&#38;nbsp;&#38;nbsp;+ Santa is known as &#39;Christkindle&#39; in the country/region of Germany? It means, &#38;quot;Christ Child&#38;quot;!&lt;br /&gt;&#38;nbsp;&#38;nbsp;+ Santa is known as &#39;Christkindl&#39; in the country/region of Switzerland? It means, &#38;quot;Christ Child&#38;quot;!&lt;br /&gt;&#38;nbsp;&#38;nbsp;+ Santa is known as &#39;Jultomten&#39; in the country/region of Sweden? It means, &#38;quot;Christmas Brownie&#38;quot;!&lt;br /&gt;&#38;nbsp;&#38;nbsp;+ Santa is known as &#39;Christkind&#39; in the country/region of Austria? It means, &#38;quot;Christ Child&#38;quot;!&lt;br /&gt;&#38;nbsp;&#38;nbsp;+ Santa is known as &#39;&#206;~Q&#206;&#179;&#206;&#185;&#206;&#191;&#207;~B &#206;~R&#206;&#177;&#207;~C&#206;&#175;&#206;&#187;&#206;&#183;&#207;~B&#39; in the country/region of Greece? It means, &#38;quot;Santa Clause&#38;quot;!&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;He is now able to build up a configuration file that has considerably more facts for his &lt;i&gt;Did you know ...?&lt;/i&gt; script.&lt;/p&gt;

&lt;p&gt;The script even uses the aforementioned method, &lt;code&gt;Getopt2h2o&lt;/code&gt;, to enable a &lt;code&gt;--conf&lt;/code&gt; flag in case Santa ever wanted to use a different configuration file.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;prompt&#38;gt; perl ./Santa-facts.pl --config ./santa2.ini&lt;br /&gt;...&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Given a &lt;code&gt;$config&lt;/code&gt; reference, &lt;code&gt;h2o2ini&lt;/code&gt; gives Santa the ability to &lt;i&gt;write&lt;/i&gt; the reference back as an &lt;code&gt;.ini&lt;/code&gt; file using &lt;a href=&#34;https://metacpan.org/module/Config::Tiny&#34;&gt;Config::Tiny&lt;/a&gt;&#38;#39;s &lt;code&gt;write&lt;/code&gt; method underneath the hood.&lt;/p&gt;

&lt;p&gt;If Santa had modifed the &lt;code&gt;.ini&lt;/code&gt; file, then he could have written it back to disk using the inverse method, &lt;code&gt;h2o2ini&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id=&#34;YAML-Files&#34;&gt;&lt;code&gt;YAML&lt;/code&gt; Files&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;    ---
    Santa:
      By:
        Country:
          Afghanistan:
            name: Aba Chaghaloo
            meaning: ???
          Greece:
            name: &#38;Alpha;&#38;gamma;&#38;iota;&#38;omicron;&#38;sigmaf; &#38;Beta;&#38;alpha;&#38;sigma;&#38;#x3AF;&#38;lambda;&#38;eta;&#38;sigmaf;
            meaning: Santa Clause
          Sweden:
            name: Jultomten
            meaning: Christmas Brownie
          Austria:
            name: Christkind
            meaning: Christ Child
          Switzerland:
            name: Christkindl
            meaning: Christ Child
          Germany:
            name: Christkindle
            meaning: Christ Child
          Mexico:
            name: Ni&#38;ntilde;o Dios
            meaning: God Child
          CentralAmerica:
            name: Ni&#38;ntilde;o Jes&#38;uacute;s
            meaning: Baby Jesus&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here, again, there is no need to &lt;code&gt;use YAML&lt;/code&gt;. The &lt;code&gt;yaml2h2o&lt;/code&gt; method employed below handles that behind the scenes, as well.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;synStatement&#34;&gt;use strict&lt;/span&gt;;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;use warnings&lt;/span&gt;;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;use &lt;/span&gt;Util::H2O::More &lt;span class=&#34;synConstant&#34;&gt;qw/Getopt2h2o yaml2h2o/&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synComment&#34;&gt;# author note: added because it was needed with the YAML example&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synComment&#34;&gt;# but not the .ini example, not really sure why ...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;use open&lt;/span&gt; &lt;span class=&#34;synConstant&#34;&gt;qw( :std :encoding(UTF-8) )&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$o&lt;/span&gt; = Getopt2h2o \&lt;span class=&#34;synIdentifier&#34;&gt;@ARGV&lt;/span&gt;, { &lt;span class=&#34;synConstant&#34;&gt;conf&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;q{./santa.yaml}&lt;/span&gt; }, &lt;span class=&#34;synConstant&#34;&gt;qw/conf=s/&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; (&lt;span class=&#34;synIdentifier&#34;&gt;$conf&lt;/span&gt;) = yaml2h2o &lt;span class=&#34;synIdentifier&#34;&gt;$o&lt;/span&gt;-&#38;gt;conf;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;synConstant&#34;&gt;qq{Did You Know:&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;}&lt;/span&gt;;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$country&lt;/span&gt; (&lt;span class=&#34;synStatement&#34;&gt;keys&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;%{$conf&lt;/span&gt;-&#38;gt;Santa-&#38;gt;By-&#38;gt;Country&lt;span class=&#34;synIdentifier&#34;&gt;}&lt;/span&gt;) {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$name&lt;/span&gt; = &lt;span class=&#34;synIdentifier&#34;&gt;$conf&lt;/span&gt;-&#38;gt;Santa-&#38;gt;By-&#38;gt;Country-&#38;gt;&lt;span class=&#34;synIdentifier&#34;&gt;$country&lt;/span&gt;-&#38;gt;name;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$meaning&lt;/span&gt; = &lt;span class=&#34;synIdentifier&#34;&gt;$conf&lt;/span&gt;-&#38;gt;Santa-&#38;gt;By-&#38;gt;Country-&#38;gt;&lt;span class=&#34;synIdentifier&#34;&gt;$country&lt;/span&gt;-&#38;gt;meaning;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;printf&lt;/span&gt; &lt;span class=&#34;synConstant&#34;&gt;qq{  + Santa is known as &#39;%s&#39; in the country/region of %s? It means, &#38;quot;%s&#38;quot;!&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;}&lt;/span&gt;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;$name&lt;/span&gt;, &lt;span class=&#34;synIdentifier&#34;&gt;$country&lt;/span&gt;, &lt;span class=&#34;synIdentifier&#34;&gt;$meaning&lt;/span&gt;;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And running this script with the &lt;code&gt;YAML&lt;/code&gt; configuration file now yields,&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  prompt&#38;gt; perl ./Santa-facts.pl
  Did You Know:
    + Santa is known as &#38;#39;Aba Chaghaloo&#38;#39; in the country/region of Afghanistan? It means, &#38;quot;???&#38;quot;!
    + Santa is known as &#38;#39;Ni&#38;ntilde;o Jes&#38;uacute;s&#38;#39; in the country/region of CentralAmerica? It means, &#38;quot;Baby Jesus&#38;quot;!
    + Santa is known as &#38;#39;Ni&#38;ntilde;o Dios&#38;#39; in the country/region of Mexico? It means, &#38;quot;God Child&#38;quot;!
    + Santa is known as &#38;#39;Christkindle&#38;#39; in the country/region of Germany? It means, &#38;quot;Christ Child&#38;quot;!
    + Santa is known as &#38;#39;Christkindl&#38;#39; in the country/region of Switzerland? It means, &#38;quot;Christ Child&#38;quot;!
    + Santa is known as &#38;#39;Jultomten&#38;#39; in the country/region of Sweden? It means, &#38;quot;Christmas Brownie&#38;quot;!
    + Santa is known as &#38;#39;Christkind&#38;#39; in the country/region of Austria? It means, &#38;quot;Christ Child&#38;quot;!
    + Santa is known as &#38;#39;&#38;Alpha;&#38;gamma;&#38;iota;&#38;omicron;&#38;sigmaf; &#38;Beta;&#38;alpha;&#38;sigma;&#38;#x3AF;&#38;lambda;&#38;eta;&#38;sigmaf;&#38;#39; in the country/region of Greece? It means, &#38;quot;Santa Clause&#38;quot;!&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There are many other cool aspects to &lt;code&gt;Util::H2O::More&lt;/code&gt; that Santa wishes to show you, but he hopes that this Christmas break you discover all the time and lines of code that this module has to offer for a vast number of applications.&lt;/p&gt;

&lt;p&gt;There is no &lt;code&gt;h2o2yaml&lt;/code&gt; (or ways t handle &lt;code&gt;JSON&lt;/code&gt; date either way), but if someone reading has the need, the author is quite active on Github and may be more than happy to help out a friend in need.&lt;/p&gt;

&lt;h3 id=&#34;There-is-Still-More&#34;&gt;There is Still More!&lt;/h3&gt;

&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Util::H2O::More&#34;&gt;Util::H2O::More&lt;/a&gt; is any Perl programmer&#38;#39;s secret weapon for dealing with very common things that result ultimately in slinging around a bunch of &lt;code&gt;HASH&lt;/code&gt; references - and occasionally, very complex structures that include &lt;code&gt;ARRAY&lt;/code&gt; refs.&lt;/p&gt;

&lt;p&gt;It builds on &lt;a href=&#34;https://metacpan.org/module/Util::H2O&#34;&gt;Util::H2O&lt;/a&gt;&#38;#39;s massively powerful combination of &lt;code&gt;h2o&lt;/code&gt; and &lt;code&gt;o2h&lt;/code&gt; to provide &lt;i&gt;ad hoc&lt;/i&gt; accessors to data &lt;i&gt;in flight&lt;/i&gt; - and to remove them again when needed.&lt;/p&gt;

&lt;p&gt;Some other pretty useful methods provided for by &lt;a href=&#34;https://metacpan.org/module/Util::H2O::More&#34;&gt;Util::H2O::More&lt;/a&gt; are:&lt;/p&gt;

&lt;dl&gt;

&lt;dt&gt;&lt;code&gt;baptise&lt;/code&gt; - a drop-in replacement for &lt;code&gt;bless&lt;/code&gt;, but allows accessors to be defined:&lt;/dt&gt;
&lt;dd&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;synStatement&#34;&gt;use strict&lt;/span&gt;;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;use warnings&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;package&lt;/span&gt;&lt;span class=&#34;synType&#34;&gt; Foo::Bar&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synComment&#34;&gt;# exports &#39;h2o&#39; also&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;use &lt;/span&gt;Util::H2O::More &lt;span class=&#34;synConstant&#34;&gt;qw/baptise/&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;sub &lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;new &lt;/span&gt;{&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$pkg&lt;/span&gt;    = &lt;span class=&#34;synStatement&#34;&gt;shift&lt;/span&gt;;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;%opts&lt;/span&gt;   = &lt;span class=&#34;synIdentifier&#34;&gt;@_&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synComment&#34;&gt;# replaces bless, defines default constructures and creates&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synComment&#34;&gt;# constructors based on what&#39;s passed into %opts&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$self&lt;/span&gt; = baptise \&lt;span class=&#34;synIdentifier&#34;&gt;%opts&lt;/span&gt;, &lt;span class=&#34;synIdentifier&#34;&gt;$pkg&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;qw/bar haz herp derpes/&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$self&lt;/span&gt;;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synConstant&#34;&gt;1&lt;/span&gt;;&lt;/code&gt;&lt;/pre&gt;

&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;d2o&lt;/code&gt; - like &lt;code&gt;h2o&lt;/code&gt;, but dives deeply into &lt;code&gt;ARRAY&lt;/code&gt; refs, e.g., that contain &lt;code&gt;HASH&lt;/code&gt; refs; and applies &lt;code&gt;h2o&lt;/code&gt; to them&lt;/dt&gt;
&lt;dd&gt;

&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;o2d&lt;/code&gt; - like &lt;code&gt;o2h&lt;/code&gt;, but acts on deeply objectified references that were created by &lt;code&gt;d2o&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;

&lt;/dd&gt;
&lt;dt&gt;&lt;code&gt;ddd&lt;/code&gt; - a shortcut around dumping references to &lt;code&gt;STDERR&lt;/code&gt; via &lt;code&gt;Data::Dumper&lt;/code&gt;&lt;/dt&gt;
&lt;dd&gt;

&lt;/dd&gt;
&lt;/dl&gt;

&lt;h3 id=&#34;Conclusion&#34;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Getting this far down into the article is quite an achievement. Congratulations for persevering with your faith in Perl. As you can see, Santa is very pleased to indulge in the true meaning of Christmas - which obviously, has everything to with spreading as much practical Perl knowledge as possible.&lt;/p&gt;

&lt;p&gt;Joyeux No&#38;euml;l!&lt;/p&gt;

&lt;h3 id=&#34;Links&#34;&gt;Links&lt;/h3&gt;

&lt;dl&gt;

&lt;dt&gt;1. &lt;a href=&#34;https://perladvent.org/2022/2022-12-06.html&#34;&gt;https://perladvent.org/2022/2022-12-06.html&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;

&lt;/dd&gt;
&lt;dt&gt;2. &lt;a href=&#34;https://metacpan.org/pod/Util::H2O::More&#34;&gt;https://metacpan.org/pod/Util::H2O::More&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;

&lt;/dd&gt;
&lt;dt&gt;3. &lt;a href=&#34;https://metacpan.org/pod/Util::H2O&#34;&gt;https://metacpan.org/pod/Util::H2O&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;

&lt;/dd&gt;
&lt;dt&gt;4. &lt;a href=&#34;https://www.historiesdarkmysteries.com/2021/12/the-surprising-origins-of-jolly-old-st.html&#34;&gt;https://www.historiesdarkmysteries.com/2021/12/the-surprising-origins-of-jolly-old-st.html&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;

&lt;/dd&gt;
&lt;/dl&gt;

&lt;/div&gt;</summary><updated>2023-12-22T00:00:00Z</updated><category term="Perl"/><author><name>oodler</name></author></entry><entry><title>Elves Versus Typos</title><link href="https://perladvent.org/2023/2023-12-21.html"/><id>https://perladvent.org/2023/2023-12-21.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;When you&#38;#39;re constantly producing things like toys and code, mistakes will happen. Some will be easy to spot and others may elude you. Santa knows that attention to detail counts. The elves know that if Santa finds a typo in their documentation or their code, he will immediately ask himself what else may be wrong. In order to avoid the impression of carelessness, the elves have automated the finding and fixing of typos.&lt;/p&gt;

&lt;h3 id=&#34;The-Tool&#34;&gt;The Tool&lt;/h3&gt;

&lt;p&gt;Strangely enough, one of the tools which the elves have in their toolkit is the &lt;a href=&#34;https://crates.io/crates/typos&#34;&gt;typos&lt;/a&gt; utility. Now, this tool is not written in Perl, but rather in Rust. This bothers exactly nobody, since the elves use the right tool for the right job. The wonderful thing about &lt;code&gt;typos&lt;/code&gt; is that this Rust-based tool can improve their Perl code. It&#38;#39;s a Christmas miracle!&lt;/p&gt;

&lt;h3 id=&#34;Getting-Set-Up&#34;&gt;Getting Set Up&lt;/h3&gt;

&lt;p&gt;After installing &lt;code&gt;typos&lt;/code&gt;, it&#38;#39;s trivial to spot typos in code.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  $ typos&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&#38;#39;s it! Now, let&#38;#39;s try it on the Advent Calendar. We&#38;#39;ll start with the articles in 2019.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  $ typos 2019&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This gives us all sorts of helpful information.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    typos 2019
    error: `entires` should be `entries`
      --&#38;gt; 2019/articles/2019-12-16.pod:253:23
        |
    253 | And start adding todo entires:
        |                       ^^^^^^^
        |
    error: `hightlight` should be `highlight`
      --&#38;gt; 2019/articles/2019-12-14.pod:113:56
        |
    113 |         # work out the three strings (left of / before hightlight,
        |                                                        ^^^^^^^^^^
        |
    error: `hightlight` should be `highlight`
      --&#38;gt; 2019/articles/2019-12-14.pod:114:24
        |
    114 |         # the middle / hightlight, and then right of / after highlight)
        |                        ^^^^^^^^^^
        |
    error: `assing` should be `assign`
      --&#38;gt; 2019/articles/2019-12-14.pod:121:27
        |
    121 |         # what we want to assing to $x so we start drawing there again.&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There are actually a few more typos, but this is a good demonstration of what we might find. Now, how do we fix it?&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  $ typos -w 2019

    error: `fils` should be `fills`, `files`, `file`
      --&#38;gt; 2019/articles/2019-12-20.pod:136:59
        |
    136 | if that machine can access the internet, if I can put the fils in my home
        |                                                           ^^^^
        |
    error: `whe` should be `when`, `we`
      --&#38;gt; 2019/articles/2019-12-19.pod:25:17
       |
    25 | between runs.&#38;quot;, whe Wise Old Elf explained sagely, &#38;quot;Then you&#38;#39;d be able to
       |                 ^^^
       |&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This actually fixes a number of typos, but there are two which the tool cannot resolve, so it makes some suggestions for us to use in a manual fix.&lt;/p&gt;

&lt;p&gt;This leaves the matter of how many changes were actually made. Let&#38;#39;s see:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    $ git diff --stat 2019
     2019/articles/2010-12-11.pod | 2 +-
     2019/articles/2019-12-04.pod | 2 +-
     2019/articles/2019-12-05.pod | 4 ++--
     2019/articles/2019-12-07.pod | 4 ++--
     2019/articles/2019-12-10.pod | 2 +-
     2019/articles/2019-12-12.pod | 2 +-
     2019/articles/2019-12-13.pod | 8 ++++----
     2019/articles/2019-12-14.pod | 6 +++---
     2019/articles/2019-12-16.pod | 2 +-
     2019/articles/2019-12-18.pod | 6 +++---
     2019/articles/2019-12-20.pod | 4 ++--
     2019/articles/2019-12-21.pod | 4 ++--
     2019/articles/2019-12-22.pod | 2 +-
     2019/articles/2019-12-24.pod | 2 +-
     14 files changed, 25 insertions(+), 25 deletions(-)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can now go over the changes individually via &lt;code&gt;git add -p&lt;/code&gt; and we&#38;#39;ll find that all but one seem to be correct. 24 typos found and fixed in 47 ms. That&#38;#39;s not bad at all.&lt;/p&gt;

&lt;p&gt;As we process more and more files, we will likely find some false positives which we want to correct. This can be done in a config file. Ours is &lt;code&gt;typos.toml&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    [default.extend-words]
    ANDed = &#38;quot;ANDed&#38;quot;
    ba = &#38;quot;ba&#38;quot;
    Claus = &#38;quot;Claus&#38;quot;
    DNE = &#38;quot;DNE&#38;quot;
    IFF = &#38;quot;IFF&#38;quot;
    Signes = &#38;quot;Signes&#38;quot;

    [files]
    extend-exclude = [&#38;quot;advent.ini&#38;quot;, &#38;quot;data.en&#38;quot;]&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In order to skip false positives, we add words to the &lt;code&gt;default.extend-words&lt;/code&gt; section. Yes, it&#38;#39;s kind of a surprising way to do this, but let&#38;#39;s go along with it. Also, any files which we don&#38;#39;t want to check can be added to &lt;code&gt;extend-include&lt;/code&gt; in the &lt;code&gt;[files]&lt;/code&gt; section.&lt;/p&gt;

&lt;h3 id=&#34;More-Than-Just-Documentation&#34;&gt;More Than Just Documentation&lt;/h3&gt;

&lt;p&gt;The neat thing about &lt;code&gt;typos&lt;/code&gt; is that it can also fix things in your Perl code itself and not just the documentation.&lt;/p&gt;

&lt;p&gt;Imagine we have a Perl script with the following contents:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;synStatement&#34;&gt;use strict&lt;/span&gt;;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;use warnings&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;sub &lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;widht &lt;/span&gt;{}&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$strng&lt;/span&gt; = &lt;span class=&#34;synConstant&#34;&gt;&#39;foo&#39;&lt;/span&gt;;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What does &lt;code&gt;typos&lt;/code&gt; have to say about it?&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    typos workshop.pl
    error: `widht` should be `width`
      --&#38;gt; workshop.pl:4:5
      |
    4 | sub widht {}
      |     ^^^^^
      |
    error: `strng` should be `string`
      --&#38;gt; workshop.pl:6:5
      |
    6 | my $strng = &#38;#39;foo&#38;#39;;
      |     ^^^^^
      |&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can see that our function name and our variable name have been caught and will be corrected if we run again with &lt;code&gt;typos -w&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&#34;Now-The-Elves-Look-Smart-er&#34;&gt;Now The Elves Look Smart(er)&lt;/h3&gt;

&lt;p&gt;Having discovered this very useful tool, the elves have added it to their linters and fixers, made it part of their &lt;code&gt;pre-commit&lt;/code&gt; hooks and included it in the Continuous Integration configuration.&lt;/p&gt;

&lt;p&gt;For those of us who enjoy creating a quick pull request to fix someone else&#38;#39;s typos, we can now employ this tool on repositories which we have just checked out. A helpful pull request for a grateful maintainer is just minutes away.&lt;/p&gt;

&lt;p&gt;As one more data point, I used &lt;code&gt;typos&lt;/code&gt; to check this very article and I&#38;#39;m both proud and ashamed to say that it found more than one problem. &#38;#x1F605;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;typos&lt;/code&gt; will not find all errors, but it will find issues which are hard for the human eye to spot. It&#38;#39;s not a replacement for a code review, but it&#38;#39;s a helpful tool for the elves to have in their toolbox for the days when they just don&#38;#39;t see the typos which are staring them in the face. The best part is, they get to find the typos before Santa does.&lt;/p&gt;

&lt;/div&gt;</summary><updated>2023-12-21T00:00:00Z</updated><category term="Perl"/><author><name>olaf</name></author></entry><entry><title>A Dotenv Carol</title><link href="https://perladvent.org/2023/2023-12-20.html"/><id>https://perladvent.org/2023/2023-12-20.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;In the chilling corridors of Scrooge &#38;amp; Marley Software Solutions, Ebenezer Scrooge sat hunched over his laptop, hands clutching his hair, overwhelmed by failed deployments of his containers. Suddenly, a ghostly figure materialized before him &#38;ndash; the Ghost of Configurations Past. It pointed at the stack of old, unwieldy JSON and YAML files in Scrooge&#38;#39;s applications. &lt;i&gt;&#38;quot;Behold, Ebenezer,&#38;quot;&lt;/i&gt; moaned the specter, &lt;i&gt;&#38;quot;the complexity and confusion of your past configurations. Remember the days of endless nested structures and tedious manual edits.&#38;quot;&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;As the ghost swept Scrooge through the digital corridors of time, he saw himself wrestling with intricate configurations, wasting precious hours on syntax errors and misalignments. &lt;i&gt;&#38;quot;There must be a simpler way,&#38;quot;&lt;/i&gt; the ghost whispered.&lt;/p&gt;

&lt;p&gt;Next appeared the Ghost of Configurations Present, adorned with snippets of Perl code and a merry demeanor. It took Scrooge to witness scenes of joyous developers using &lt;a href=&#34;https://12factor.net/config&#34;&gt;dotenv&lt;/a&gt; files &#38;ndash; simple, readable, and devoid of unnecessary complexity. &lt;i&gt;&#38;quot;Behold the present, Ebenezer!&#38;quot;&lt;/i&gt; the ghost declared. &lt;i&gt;&#38;quot;Look at the ease with which developers manage all those different app environments. No more verbosity, no more headaches. Dotenv files bring clarity and simplicity to configuration management.&#38;quot;&lt;/i&gt;.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;&#38;quot;But how were they even able to change all that code to use .env files?&#38;quot;&lt;/i&gt;, Ebenezer scoffed. &lt;i&gt;&#38;quot;It must have cost a fortune to migrate!&#38;quot;&lt;/i&gt;. The spectre quietly directed him to an open IDE, where a single line simply read:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    use ENV::Util -load_dotenv;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As Scrooge squinted at the line, the ghostly voice resonated. &lt;i&gt;&#38;quot;&lt;a href=&#34;https://metacpan.org/module/ENV::Util&#34;&gt;ENV::Util&lt;/a&gt; is a lightweight module with zero dependencies. And just by adding that line, your &lt;code&gt;%ENV&lt;/code&gt; will be populated with all the variables defined in your dotenv file, making it ready to use throughout your app.&#38;quot;&lt;/i&gt; The old man remained skeptical. &lt;i&gt;&#38;quot;Fine, but what if I want a configuration hash that&#38;#39;s specific to my app, that I can for example iterate on, knowing it will only contain relevant settings?&#38;quot;&lt;/i&gt; The ethereal entity waved him to another terminal. &lt;i&gt;&#38;quot;You mean like so?&#38;quot;&lt;/i&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    my %config = ENV::Util::prefix2hash( &#38;#39;MYAPP_&#38;#39; )&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;i&gt;&#38;quot;This will parse &lt;code&gt;%ENV&lt;/code&gt; and return a key/value hash containing just the variables prefixed by &#38;#39;MYAPP_&#38;#39;. It will even remove the prefix and lowercase variable names so they become more Perlish. This way a dotenv file with a line like this:&#38;quot;&lt;/i&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    MYAPP_DB_SERVER_IP=127.0.0.1&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;i&gt;&#38;quot;Can be accessed inside that hash as:&#38;quot;&lt;/i&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    $config{db_server_ip}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Ebenezer was speechless. Then he remembered one of his past hurdles with configuration files. &lt;i&gt;&#38;quot;That doesn&#38;#39;t solve my main debugging issue! When thing go wrong, and in my line of business you know they will eventually, you sometimes need to dump all your configuration data, but that puts a lot of secrets in plain text in my logfiles!&#38;quot;&lt;/i&gt;. With an unchanged demeanor, the apparition replied: &lt;i&gt;&#38;quot;Then instead of dumping %ENV you can dump &lt;code&gt;ENV::Util::redacted_env&lt;/code&gt;, which will mask the values of any keys that look sensitive, like the ones matching &#38;#39;ID&#38;#39;, &#38;#39;EMAIL&#38;#39;, &#38;#39;TOKEN&#38;#39; or &#38;#39;PASS&#38;#39;:&#38;quot;&lt;/i&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    use ENV::Util -load_dotenv;
    use Data::Printer;

    my %redacted = ENV::Util::redacted_env();
    p %redacted;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;i&gt;&#38;quot;You can even add your own rules as to what gets redacted and what doesn&#38;#39;t. With ENV::Util, there really is no excuse to avoid dotenv files.&#38;quot;&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;&lt;i&gt;&#38;quot;It&#38;#39;s a Christmas miracle!&#38;quot;&lt;/i&gt; Scrooge exclaimed, his eyes gleaming with newfound understanding.&lt;/p&gt;

&lt;p&gt;But the Ghost of Configurations Yet to Come loomed ominously. It revealed a desolate future where Scrooge clung stubbornly to traditional configuration files in his apps, leading to confusion, inefficiency, disgruntled developers and... overtime.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;&#38;quot;No more!&#38;quot;&lt;/i&gt; cried Scrooge, awakening from his spectral journey. &lt;i&gt;&#38;quot;I have seen the error of my ways. With &lt;a href=&#34;https://metacpan.org/module/ENV::Util&#34;&gt;ENV::Util&lt;/a&gt;, I shall embrace the simplicity of dotenv files and bid farewell to the chains of complexity that bind my code.&#38;quot;&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;And so, on that Christmas morning, Scrooge used &lt;a href=&#34;https://metacpan.org/module/ENV::Util&#34;&gt;ENV::Util&lt;/a&gt; and replaced his verbose configurations with a neat &lt;code&gt;.env&lt;/code&gt; file. As the clock struck midnight, signaling the dawn of a new day, Scrooge&#38;#39;s software team gathered, their faces beaming with joy. The office, once shrouded in the darkness of cumbersome configurations, now radiated the festive glow of efficient and readable dotenv files.&lt;/p&gt;

&lt;/div&gt;</summary><updated>2023-12-20T00:00:00Z</updated><category term="Perl"/><author><name>Breno G. de Oliveira</name></author></entry><entry><title>Perl - The Humane Programming Language</title><link href="https://perladvent.org/2023/2023-12-19.html"/><id>https://perladvent.org/2023/2023-12-19.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h3 id=&#34;Perl---The-Humane-Programming-Language&#34;&gt;Perl - The Humane Programming Language&lt;/h3&gt;

&lt;p&gt;Programming languages usually reflect the needs of the computer. We find ourselves typing verbose incantations, over and over. Our instructions are so detailed as to remove all ambiguity from them -- yet programs frequently don&#38;#39;t do what we expect. The limitations of the programming language dictate how we think about and solve problems.&lt;/p&gt;

&lt;p&gt;Perl is different. It puts you, the programmer, first. Larry Wall, Perl&#38;#39;s creator was a linguist who brought many principles of &lt;a href=&#34;http://www.wall.org/~larry/natural.html&#34;&gt;natural language&lt;/a&gt; to Perl. As creators, we are at our most productive, contented selves when we get into the flow. Let&#38;#39;s see what makes Perl the flow-state language.&lt;/p&gt;

&lt;h4 id=&#34;Get-the-job-done&#34;&gt;Get the job done&lt;/h4&gt;

&lt;p&gt;Natural languages follow the &lt;a href=&#34;https://en.wikipedia.org/wiki/Brevity_law&#34;&gt;Law of Brevity&lt;/a&gt;, where the most commonly used words are also the shortest. We modify our language to accommodate our time-preference. Perl aims for brevity too. Its keywords tend to be shorter than the traditional versions:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;Traditional    Perl&lt;br /&gt;-----------    ----&lt;br /&gt;break          last&lt;br /&gt;continue       next&lt;br /&gt;filter         grep&lt;br /&gt;function       sub&lt;br /&gt;import         use&lt;br /&gt;let            my&lt;br /&gt;throw          die&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Often entire words can be omitted. Subroutine declarations do not require a &lt;code&gt;return&lt;/code&gt; statement, and may be called without parentheses. Built-in functions can operate on implicit variables like &lt;code&gt;$_&lt;/code&gt; instead of explicit arguments. This code loops over each line of input and splits the tab-separated line into an array, without ever referencing stdin or the line variable:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;readline&#34;&gt;&#38;lt;&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;chomp&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@cols&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;split&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;/\t/&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;  &#38;gt; People like things to be visually distinct from their surroundings. That&#38;#39;s also why the various
  &#38;gt; classes of operators and variables in Perl are visually distinct from each other. It&#38;#39;s just
  &#38;gt; sound human engineering.
  &#38;gt; Larry Wall&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;By making variables, operators and function names visually distinct, Perl saves you reading time too.&lt;/p&gt;

&lt;h4 id=&#34;Do-What-I-Mean&#34;&gt;Do What I Mean&lt;/h4&gt;

&lt;p&gt;Perl might be the most helpful of the dynamic languages. Take this Python function which adds 2 to any number its given:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;def add2(n):&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;return n + 2&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This function works fine when &lt;code&gt;n&lt;/code&gt; is an int or float, but dies on stringified numbers like &lt;code&gt;&#38;quot;5&#38;quot;&lt;/code&gt;, because Python refuses to concatenate a string with the number &lt;code&gt;2&lt;/code&gt;. Now we&#38;#39;re faced with a choice - should we cast &lt;code&gt;n&lt;/code&gt; to a number type inside &lt;code&gt;add2&lt;/code&gt; or change every call site to cast the parameter to a number type before calling &lt;code&gt;add2&lt;/code&gt;?&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;def add2(n):&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;return int(n) + 2 # or float(n) ?&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Casting inside &lt;code&gt;add2&lt;/code&gt; means choosing which type to use (int or float), reducing its flexibility. Since call sites have more knowledge about the origin of &lt;code&gt;n&lt;/code&gt;, that seems like the better trade off, but we&#38;#39;ll always need to watch out for unsafe callers. Let&#38;#39;s go another route:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;def add2_i(n):&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;return int(n) + 2&lt;br /&gt;&lt;br /&gt;def add2_f(n):&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;return float(n) + 2&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We&#38;#39;ve lost the generic behavior of &lt;code&gt;add2&lt;/code&gt; but gained runtime safety without tracking call sites. And all we have to do is type out two versions of every number function we ever write! The dissatisfaction of programming in Python stems from the intuition that the experience should be better, i.e. more &lt;i&gt;natural&lt;/i&gt; for the programmer. To have to write my code at the speed of a static language, but with the run time of a dynamic language just feels dumb.&lt;/p&gt;

&lt;p&gt;In natural languages, context can change the meaning of the expression. Similarly, Perl uses context to change the type of an expression. The &lt;code&gt;+&lt;/code&gt; operator forces a numeric context on its arguments, the concatenation operator &lt;code&gt;.&lt;/code&gt;, a string context. With the ambiguity removed, there&#38;#39;s no need to litter our code with type casts or extra functions:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;add2&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Since text is the lingua franca of program input, Perl is optimized for the common case. Perl uses context to do what you mean.&lt;/p&gt;

&lt;h4 id=&#34;Trust-Me&#34;&gt;Trust Me&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;  &#38;gt; Perl is designed to let you program naturally. Whatever you think natural means.
  &#38;gt; Larry Wall&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Perl doesn&#38;#39;t enforce a particular paradigm on the programmer. Everything isn&#38;#39;t an object, but you&#38;#39;re free to use the OO paradigm if you want to. There are no &#38;quot;private&#38;quot; attributes or methods. Any module, object or data structure can be printed, traversed and manipulated.&lt;/p&gt;

&lt;p&gt;Want to inspect an object to see what it&#38;#39;s made of? Use &lt;a href=&#34;https://metacpan.org/module/Data::Printer&#34;&gt;Data::Printer&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Data::Printer&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;p&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$foo&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Foo&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$foo&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Perl trusts you to solve the problem as you see fit. If you want to fire off a bunch of computation at compile time, you can. If you want to use 90% of a module but monkey-patch that one method to behave how you need it, that&#38;#39;s fine. Safer options for polymorphism include inheritance, traits, operator overloading and tied values.&lt;/p&gt;

&lt;p&gt;You&#38;#39;ll find it edifying to express your solution to a problem without being trammeled by a one-size-fits-all paradigm. You might say, &lt;a href=&#34;https://en.wikipedia.org/wiki/Perl#Philosophy&#34;&gt;There&#38;#39;s More Than One Way To Do It&lt;/a&gt;.&lt;/p&gt;

&lt;h4 id=&#34;Lessons-Learned&#34;&gt;Lessons Learned&lt;/h4&gt;

&lt;p&gt;Perl is an old language, with some features that seemed like a good idea at the time, but haven&#38;#39;t panned out. Implicit variable declaration usually &lt;a href=&#34;https://craftinginterpreters.com/statements-and-state.html#design-note&#34;&gt;causes more trouble than its worth&lt;/a&gt;, so we use the &lt;a href=&#34;https://metacpan.org/module/strict&#34;&gt;strict&lt;/a&gt; pragma to turn it off (Python and Ruby still suffer from it).&lt;/p&gt;

&lt;p&gt;Perl&#38;#39;s interpreter threads are best left alone, and its reliance on global state makes implementing a good threading model a tall order. Process concurrency is easy with &lt;a href=&#34;https://metacpan.org/module/Parallel::ForkManager&#34;&gt;Parallel::ForkManager&lt;/a&gt; though, and &lt;a href=&#34;https://metacpan.org/module/IO::Async&#34;&gt;IO::Async&lt;/a&gt; is good for asynchronous programming.&lt;/p&gt;

&lt;p&gt;Perl used to lack proper booleans, relying on &lt;a href=&#34;https://www.oreilly.com/library/view/programming-perl-3rd/0596000278/ch01s06.html&#34;&gt;truthiness&lt;/a&gt; instead. This didn&#38;#39;t always yield the best results, so they were added in &lt;a href=&#34;https://perldoc.perl.org/perl5360delta&#34;&gt;v5.36&lt;/a&gt;. I still think Perl could use another type or two. For example &#38;quot;pairs&#38;quot; could make hash construction less brittle, and iteration easier.&lt;/p&gt;

&lt;p&gt;And whilst Perl&#38;#39;s concept of context works very well, it would be nice to have a meta-context model to program with, separate from the Perl interpreter. Santa, if you&#38;#39;re listening forget the merino wool socks, add that to my list.&lt;/p&gt;

&lt;h4 id=&#34;Wrapping-Up&#34;&gt;Wrapping Up&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;  &#38;gt; Of all the programming languages I&#38;#39;ve used, Perl is the only one where I never feel like
  &#38;gt; I&#38;#39;m fighting with the language.
  &#38;gt; Martin, Software Engineer&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This month many of us will be celebrating with friends and family. It&#38;#39;s a time of appreciation and reflection. So ask yourself this - how much joy did your programming bring you this year?&lt;/p&gt;

&lt;/div&gt;</summary><updated>2023-12-19T00:00:00Z</updated><category term="Perl"/><author><name>perl</name></author></entry><entry><title>Trimming audio files with Audio::Nama</title><link href="https://perladvent.org/2023/2023-12-18.html"/><id>https://perladvent.org/2023/2023-12-18.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;&lt;center&gt;&lt;img src=&#34;warpedwav7.png&#34; alt=&#34;Warped audio waveforms&#34; width=&#34;85%&#34;&gt;&lt;/center&gt;

&lt;/p&gt;



&lt;h3 id=&#34;Our-task&#34;&gt;Our task&lt;/h3&gt;

&lt;p&gt;The elves&#38;#39; workshop has been as busy as ever this year. To help them pass the time when not gossiping or recounting heroic pranks of Christmases passed, Igvik Graybeard, one of the IT elves, has been piping music to the office, canteen and tool benches using cabling left over from an obsolete phone service.&lt;/p&gt;

&lt;p&gt;In the last years the elves have gotten into radio plays, and Igvik wants to edit some old recordings he has to remove unwanted segments. In other words, he wants to extract relevant parts of an audio file, stitching them together into a new file. Igvik runs Linux and prefers to do his work in the terminal wherever possible. We&#38;#39;ve decided to help.&lt;/p&gt;

&lt;h3 id=&#34;Our-tools&#34;&gt;Our tools&lt;/h3&gt;

&lt;p&gt;We&#38;#39;ll be accomplishing this with &lt;a href=&#34;https://metacpan.org/module/Audio::Nama&#34;&gt;Audio::Nama&lt;/a&gt;, a multitrack recording mixing and audio-processing application written in perl, and &lt;a href=&#34;https://ecasound.seul.org/ecasound/&#34;&gt;Ecasound&lt;/a&gt;, a general-purpose audio engine. We also need git, which Nama uses to manage project state, provide for branching, undo, etc. &lt;code&gt;nama&lt;/code&gt; is the executable program script and also man page, so &#38;quot;man nama&#38;quot; for the docs, or use nama&#38;#39;s internal help.&lt;/p&gt;

&lt;p&gt;Nama configures Ecasound for recording, mixing and a variety of tasks via an audio network definition called a &lt;i&gt;chain setup&lt;/i&gt;. Aside from housekeeping duties, Nama&#38;#39;s main task is to regenerate the chain setup (and re-configure the engine) whenever the graph changes due to user input, such as deactivating a track or changing an output -- a bit like how a spreadsheet recalculates as necessary.&lt;/p&gt;

&lt;p&gt;The first run of &lt;code&gt;nama&lt;/code&gt; creates a &lt;code&gt;$HOME/nama&lt;/code&gt; directory for project files and a configuration file &lt;code&gt;$HOME/.namarc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Nama assumes a linux environment: that you&#38;#39;ll be recording or listening from the default ALSA soundcard device, usually your computer&#38;#39;s built-in soundcard. You can change this setting in &lt;code&gt;namarc&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;center&gt;&lt;img src=&#34;thin2.png&#34; alt=&#34;section divider&#34; width=&#34;7%&#34;&gt;&lt;/center&gt;

&lt;/p&gt;



&lt;h3 id=&#34;Create-a-new-project-add-a-track-and-import-an-audio-file&#34;&gt;Create a new project, add a track and import an audio file&lt;/h3&gt;

&lt;p&gt;We&#38;#39;ll create a new project called &#38;#39;christmas&#38;#39;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ nama -c christmas&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We get a startup banner, then an empty track listing:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;         No. Name       Requested  Status  Source                Destination   Vol   Pan
        ===============================================================================
          1  Main                  MON     Main bus              CH 1/2        100    50
          2  Mixdown               OFF     track Main            --             --    --

        nama christmas Mixdown &#38;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the prompt, &#38;#39;christmas&#38;#39; is the project, &#38;#39;Mixdown&#38;#39;, the current track.&lt;/p&gt;

&lt;p&gt;We create a separate track to accommodate our audio file, then import the file.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;        nama christmas Mixdown &#38;gt; add-track carol
        nama christmas carol &#38;gt; import ~/music/christmas-carol.mp3

        format: s16_le,2,12000
        importing /home/jroth/music/christmas-carol.mp3 as /home/jroth/nama/christmas/.wav/carol_1.wav, converting to s16_le,2,44100,i

         No. Name       Requested  Status  Source                Destination   Vol   Pan
        ===============================================================================
          1  Main                  MON     Main bus              CH 1/2        100    50
          2  Mixdown               OFF     track Main            --             --    --
          3  carol                 PLAY    carol_1.wav           Main bus      100    50&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can now press SPACE to start/stop playback.&lt;/p&gt;

&lt;p&gt;In the track listing above we see that track &#38;#39;carol&#38;#39; with source &lt;code&gt;carol_1.wav&lt;/code&gt; is set to PLAY. The output of &#38;#39;carol&#38;#39; feeds the &#38;#39;Main&#38;#39; track via the &#38;#39;Main&#38;#39; bus. The &#38;#39;Main&#38;#39; track serves as the master fader with output to the sound card. Like &#38;#39;carol&#38;#39;, all new tracks start as members of the &#38;#39;Main&#38;#39; bus.&lt;/p&gt;

&lt;p&gt;&lt;center&gt;&lt;img src=&#34;thin2.png&#34; alt=&#34;section divider&#34; width=&#34;7%&#34;&gt;&lt;/center&gt;

&lt;/p&gt;



&lt;h3 id=&#34;Define-our-clips&#34;&gt;Define our clips&lt;/h3&gt;

&lt;p&gt;We will use a specialized type of bus called a &#38;#39;sequence&#38;#39; to stitch together clips from our radio play. First we need to mark the beginning and end of each clip we want to keep.&lt;/p&gt;

&lt;p&gt;We do that by listening to the track and using the &lt;code&gt;clip-here&lt;/code&gt; command (bound to the F1 key) to mark clip starts and ends.&lt;/p&gt;

&lt;p&gt;After some trial and error, we have the correct marks. In this example: four five-minute sections of content separated by 40-second breaks.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;        nama christmas carol &#38;gt; list-marks

        0 40.0 clip-start-0020
        1 340.0 clip-end-0021
        2 380.0 clip-start-0022
        3 680.0 clip-end-0023
        4 720.0 clip-start-0024
        5 1020.0 clip-end-0025
        6 1060.0 clip-start-0026
        *7 1360.0 clip-end-0027&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;The-final-gathering&#34;&gt;The final gathering&lt;/h3&gt;

&lt;p&gt;We can now assemble our clips.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;        nama christmas carol &#38;gt; gather

         No. Name       Requested  Status  Source                Destination   Vol   Pan
        ===============================================================================
          1  Main                  MON     Main bus              CH 1/2        100    50
          2  Mixdown               OFF     track Main            --             --    --
          3  carol                 MON     carol sequence        Main bus      100    50&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that the source for track 3 has changed from &lt;code&gt;carol_1.wav&lt;/code&gt; to &lt;code&gt;carol sequence&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Having listened to the output and resolved any hiccups (there were none!) we are ready to render it to an audio file.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;        nama christmas carol &#38;gt; mixdown
        Enabling mixdown to file

         No. Name       Requested  Status  Source                Destination   Vol   Pan
        ===============================================================================
          1  Main                  MON     Main bus              Mixdown       100    50
          2  Mixdown               REC v1  Main                  --             --    --
          3  carol                 MON     carol sequence        Main bus      100    50

        Now at: 0:00
        Engine is ready.
        Press SPACE to start the mixdown.

        Engine is running
        Engine is finished at 16:27

        recorded: Mixdown_1.wav
        Setting mixdown playback mode.

         No. Name       Requested  Status  Source                Destination   Vol   Pan
        ===============================================================================
          1  Main                  OFF     Main bus              --            100    50
          2  Mixdown               PLAY    Mixdown_1.wav         --             --    --
          3  carol            MON  OFF     carol sequence        --            100    50&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The mixdown step also generates ogg and mp3 encodings with oggenc and lame, respectively, if desired. These files appear in the project directory:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;~/nama/christmas/christmas_1.mp3&lt;/code&gt; &lt;code&gt;~/nama/christmas/christmas_1.ogg&lt;/code&gt; &lt;code&gt;~/nama/christmas/christmas_1.wav&lt;/code&gt; is a symlink to &lt;code&gt;~/nama/christmas/.wav/Mixdown_1.wav&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;center&gt;&lt;img src=&#34;thin2.png&#34; alt=&#34;section divider&#34; width=&#34;7%&#34;&gt;&lt;/center&gt;

&lt;/p&gt;



&lt;h3 id=&#34;How-the-sausage-is-made&#34;&gt;How the sausage is made&lt;/h3&gt;

&lt;h4 id=&#34;Chain-setup-graph&#34;&gt;Chain setup graph&lt;/h4&gt;

&lt;p&gt;An Ecasound chain setup is made of signal-processing &lt;i&gt;chains&lt;/i&gt;--edges in the processing graph--and &lt;i&gt;loop devices&lt;/i&gt;, which are nodes capable of summing their inputs.&lt;/p&gt;

&lt;p&gt;A chain represents a stream with one input and one output.&lt;/p&gt;

&lt;p&gt;Here is a setup of one chain, omitting general options related to buffer sizes, etc.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;        # audio inputs

        -a:3 -f:s16_le,2,44100 -i:/home/jroth/nama/christmas/.wav/carol_1.wav

        # audio outputs

        -a:3 -o:alsa,default&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There is one chain, with label &lt;code&gt;3&lt;/code&gt;. Its input is from a .wav file, and its output goes to the default soundcard. There is an &lt;code&gt;-f&lt;/code&gt; argument that describes the audio signal bit width, channel count and sample frequency.&lt;/p&gt;

&lt;p&gt;Chains can terminate at an audio file, a sound device or a loop device. A loop device is a buffer stage that can sum the signal from one or more chains. It supplies the sum to another chain (or possibly multiple chains.) A loop device with its sources and an output chain can represent a mixer or bus.&lt;/p&gt;

&lt;p&gt;Significantly for our task, a chain can represent an &lt;i&gt;audio clip&lt;/i&gt;, part of an audio file that plays at a particular time.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;        -a:5 -f:s16_le,2,44100 -i:playat,40,select,80,300,/home/jroth/nama/christmas/.wav/carol_1.wav&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &#38;#39;select,80,300&#38;#39; object extracts 300 seconds of audio starting at 0:80. The &#38;#39;playat,40&#38;#39; object plays the audio after a delay of 40 seconds.&lt;/p&gt;

&lt;p&gt;Chains also perform effects processing. They can host plugins and plugin controllers called &lt;i&gt;chain operators&lt;/i&gt; included in Ecasound and provided by numerous &lt;a href=&#34;https://ladspa.org&#34;&gt;LADSPA&lt;/a&gt; and &lt;a href=&#34;https://wiki.linuxaudio.org/apps/categories/lv2_plugins&#34;&gt;LV2&lt;/a&gt; authors.&lt;/p&gt;

&lt;p&gt;&lt;center&gt;&lt;img src=&#34;thin2.png&#34; alt=&#34;section divider&#34; width=&#34;7%&#34;&gt;&lt;/center&gt;

&lt;/p&gt;



&lt;h4 id=&#34;Basic-mixer-configuration&#34;&gt;Basic mixer configuration&lt;/h4&gt;

&lt;p&gt;Each time a change in track status occurs, Nama generates a Chain setup file and commands Ecasound to load it.&lt;/p&gt;

&lt;p&gt;Let&#38;#39;s start with the mixer configuration when we imported our radio play.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;         No. Name       Requested  Status  Source                Destination   Vol   Pan
        ===============================================================================
          1  Main                  MON     Main bus              CH 1/2        100    50
          2  Mixdown               OFF     track Main            --             --    --
          3  carol                 PLAY    carol_1.wav           Main bus      100    50&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is the corresponding chain setup:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;        nama christmas carol &#38;gt; chains

        # audio inputs

        -a:1 -f:s16_le,16,44100,i -i:loop,Main_in
        -a:3 -f:s16_le,2,44100 -i:/home/jroth/nama/christmas/.wav/carol_1.wav

        # audio outputs

        -a:1 -o:alsa,default
        -a:3 -f:s16_le,16,44100,i -o:loop,Main_in&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Above we have two chains, labeled &lt;code&gt;1&lt;/code&gt;, and &lt;code&gt;3&lt;/code&gt;, corresponding to our tracks &#38;#39;Main&#38;#39; and &#38;#39;carol&#38;#39;.&lt;/p&gt;

&lt;p&gt;Chain &lt;code&gt;3&lt;/code&gt; reads &lt;code&gt;carol_1.wav&lt;/code&gt; and sends its output to loop device &lt;code&gt;Main_in&lt;/code&gt;. Chain &lt;code&gt;1&lt;/code&gt; read the stream from &lt;code&gt;Main_in&lt;/code&gt; and supplies it to the soundcard.&lt;/p&gt;

&lt;h4 id=&#34;Debug-output&#34;&gt;Debug output&lt;/h4&gt;

&lt;p&gt;By starting Nama with the &lt;code&gt;-L ChainSetup&lt;/code&gt; logging option, we can see the steps from Nama&#38;#39;s representation of the routing graph to the final chain setup. Initially, tracks in the graph are allowed to connect directly. Then the graph is simplified. Dead branches are removed. Finally, loop devices are introduced between tracks. I only include the graph where it changes.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;        [1513] ChainSetup  (L 106) Graph after bus routing:
        wav_in-carol, carol-Main

        [1514] ChainSetup  (L 111) Graph after aux sends:
        [1514] ChainSetup  (L 114) Graph with paths from Main:
        wav_in-carol, carol-Main, Main-soundcard_out

        [1514] ChainSetup  (L 117) Graph with mixdown mods:
        [1514] ChainSetup  (L 216) Graph after simplify_send_routing:
        [1514] ChainSetup  (L 218) Graph after remove_out_of_bounds_tracks:
        [1514] ChainSetup  (L 220) Graph after recursively_remove_inputless_tracks:
        [1515] ChainSetup  (L 222) Graph after recursively_remove_outputless_tracks:
        [1515] ChainSetup  (L 122) Graph after pruning unterminated branches:
        [1515] ChainSetup  (L 126) Graph after adding loop devices:
        wav_in-carol, carol-Main_in, Main_in-Main, Main-soundcard_out

        [1515] ChainSetup  (L 130) Graph with inserts:&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So this is our final graph:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;        wav_in-carol, carol-Main_in, Main_in-Main, Main-soundcard_out&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;At this point, one end of each edge is a track. An edge--associating one track and one terminal--is sufficient to write an input or output line in the chain setup.&lt;/p&gt;

&lt;p&gt;This happens through dispatch on the type of terminal, and generates IO objects, each used to write one line of the chain setup: a different class for each type of terminal.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;        [1515] ChainSetup  (L 360) dispatch: wav_in -&#38;gt; carol
        [1515] ChainSetup  (L 362) name: carol, endpoint: wav_in, direction: input
        [1516] ChainSetup  (L 360) dispatch: Main -&#38;gt; soundcard_out
        [1516] ChainSetup  (L 362) name: Main, endpoint: soundcard_out, direction: output
        [1516] ChainSetup  (L 360) dispatch: carol -&#38;gt; Main_in
        [1516] ChainSetup  (L 362) name: carol, endpoint: Main_in, direction: output
        [1516] ChainSetup  (L 360) dispatch: Main_in -&#38;gt; Main
        [1516] ChainSetup  (L 362) name: Main, endpoint: Main_in, direction: input


        bless( {
          chain_id_ =&#38;gt; 3,
          endpoint_ =&#38;gt; &#38;quot;wav_in&#38;quot;,
          track_ =&#38;gt; &#38;quot;carol&#38;quot;,
        }, &#38;#39;Audio::Nama::IO::from_wav&#38;#39; )

        bless( {
          chain_id_ =&#38;gt; 1,
          endpoint_ =&#38;gt; &#38;quot;soundcard_out&#38;quot;,
          track_ =&#38;gt; &#38;quot;Main&#38;quot;,
        }, &#38;#39;Audio::Nama::IO::to_alsa_soundcard_device&#38;#39; )

        bless( {
          chain_id_ =&#38;gt; 3,
          device_id_ =&#38;gt; &#38;quot;loop,Main_in&#38;quot;,
          endpoint_ =&#38;gt; &#38;quot;Main_in&#38;quot;,
          track_ =&#38;gt; &#38;quot;carol&#38;quot;,
        }, &#38;#39;Audio::Nama::IO::to_loop&#38;#39; )

        bless( {
          chain_id_ =&#38;gt; 1,
          device_id_ =&#38;gt; &#38;quot;loop,Main_in&#38;quot;,
          endpoint_ =&#38;gt; &#38;quot;Main_in&#38;quot;,
          track_ =&#38;gt; &#38;quot;Main&#38;quot;,
        }, &#38;#39;Audio::Nama::IO::from_loop&#38;#39; )&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These classes provide methods that can be overridden by field values annotated on the graph edges or graph nodes, with the edge (chain) values having the highest priority.&lt;/p&gt;

&lt;p&gt;Overrides are used for mixdown and anywhere values for an IO object need to differ from those derived from the parent track.&lt;/p&gt;

&lt;h4 id=&#34;Assembling-our-audio-clips&#34;&gt;Assembling our audio clips&lt;/h4&gt;

&lt;p&gt;We&#38;#39;ll look at the project after we issued the &lt;code&gt;gather&lt;/code&gt; command and entered &#38;lt;mixdown&#38;gt;, ready to render the sequenced clips. The output of track &#38;#39;Main&#38;#39; feeds track &#38;#39;Mixdown&#38;#39; which will write &lt;code&gt;Mixdown_1.wav&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;         No. Name       Requested  Status  Source                Destination   Vol   Pan
        ================================================================================
          1  Main                  MON     Main bus              Mixdown       100    50
          2  Mixdown               REC v1  Main                  --             --    --
          3  carol                 MON     carol sequence        Main bus      100    50&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If we show hidden tracks, we see our four clips, each represented as a track. The source for each is the same audio file.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;        nama christmas carol &#38;gt; sha # show all tracks

         No. Name       Requested  Status  Source                Destination   Vol   Pan
        ===============================================================================
          1  Main                  MON     Main bus              CH 1/2        100    50
          2  Mixdown               OFF     track Main            --             --    --
          3  carol                 MON     carol sequence        Main bus      100    50
          4  carol-1-carol-v       PLAY    carol_1.wav           carol sequen  100    50
          5  carol-2-carol-v       PLAY    carol_1.wav           carol sequen  100    50
          6  carol-3-carol-v       PLAY    carol_1.wav           carol sequen  100    50
          7  carol-4-carol-v       PLAY    carol_1.wav           carol sequen  100    50&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the chain setup below we see that &lt;code&gt;select&lt;/code&gt; and &lt;code&gt;playat&lt;/code&gt; objects are used in the inputs to define a region of the audio file and play it with a given delay. The values were generated from our list of marks.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;        # audio inputs

        -a:1 -f:s16_le,16,44100,i -i:loop,Main_in
        -a:3 -f:s16_le,16,44100,i -i:loop,carol_in
        -a:4 -f:s16_le,2,44100 -i:select,40,300,/home/jroth/nama/christmas/.wav/carol_1.wav
        -a:5 -f:s16_le,2,44100 -i:playat,300,select,380,300,/home/jroth/nama/christmas/.wav/carol_1.wav
        -a:6 -f:s16_le,2,44100 -i:playat,600,select,720,300,/home/jroth/nama/christmas/.wav/carol_1.wav
        -a:7 -f:s16_le,2,44100 -i:playat,900,select,1060,300,/home/jroth/nama/christmas/.wav/carol_1.wav
        -a:Mixdown -f:s16_le,16,44100,i -i:loop,Main_out

        # audio outputs

        -a:1 -f:s16_le,16,44100,i -o:loop,Main_out
        -a:3 -f:s16_le,16,44100,i -o:loop,Main_in
        -a:4,5,6,7 -f:s16_le,16,44100,i -o:loop,carol_in
        -a:Mixdown -f:s16_le,2,44100,i -o:/home/jroth/nama/christmas/.wav/Mixdown_1.wav&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Some overriding was involved, as we see &lt;code&gt;-a:Mixdown&lt;/code&gt;, a chain identifier that is not a track number. I think there was some technical reason, but it does stand out.&lt;/p&gt;

&lt;h3 id=&#34;Thanks-for-reading&#34;&gt;Thanks for reading!&lt;/h3&gt;

&lt;h3 id=&#34;Showcase&#34;&gt;Showcase&lt;/h3&gt;

&lt;p&gt;Jeanette Claassen has produced a large number of &lt;a href=&#34;https://www.youtube.com/@jeanette_c3896/videos&#34;&gt;original&lt;/a&gt; &lt;a href=&#34;https://juliencoder.de/nama&#34;&gt;songs&lt;/a&gt; using Nama in combination with various other music software and hardware. She began recording music using Ecasound and migrated to Nama as it became sufficiently featureful.&lt;/p&gt;

&lt;h3 id=&#34;Notable-dependencies&#34;&gt;Notable dependencies&lt;/h3&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Git::Repository&#34;&gt;Git::Repository&lt;/a&gt;: Manage project history, branching, undo&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Log::Log4perl&#34;&gt;Log::Log4perl&lt;/a&gt;: Logging, debugging&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Parse::RecDescent&#34;&gt;Parse::RecDescent&lt;/a&gt;: Command language parser&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Object::Tiny&#34;&gt;Object::Tiny&lt;/a&gt;: Accessor generator&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Role::Tiny&#34;&gt;Role::Tiny&lt;/a&gt;: Breaking up large classes&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Term::ReadLine::Gnu&#34;&gt;Term::ReadLine::Gnu&lt;/a&gt;: Terminal support, tab completion, history, hotkey mappings&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Term::TermKey&#34;&gt;Term::TermKey&lt;/a&gt;: More hotkey mappings&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Graph&#34;&gt;Graph&lt;/a&gt;: Representing, traversing and transforming the signal processing network&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/AnyEvent&#34;&gt;AnyEvent&lt;/a&gt;: Event loop&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Tk&#34;&gt;Tk&lt;/a&gt;: GUI, available with the -g option, use at your own risk!&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Data::Section::Simple&#34;&gt;Data::Section::Simple&lt;/a&gt;: Access sections within the __DATA__ block&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Memoize&#34;&gt;Memoize&lt;/a&gt;: Turn expensive, redundant calculations into cheap lookups&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Devel::NYTProf&#34;&gt;Devel::NYTProf&lt;/a&gt;: Profiling to find and solve bottlenecks&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;</summary><updated>2023-12-18T00:00:00Z</updated><category term="Perl"/><author><name>Joel Roth</name></author></entry><entry><title>Sequentially Consistent Santa</title><link href="https://perladvent.org/2023/2023-12-17.html"/><id>https://perladvent.org/2023/2023-12-17.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;Santa is finally introducing automation into his toy making operation, and this largely manifests itself as a large, black box that he or his elves are supposed to program with the build steps.&lt;/p&gt;

&lt;p&gt;These magic boxes are programmed to follow a specific set of steps using a domain specific language (DSL) provided for by the mysterious makers of the boxen.&lt;/p&gt;

&lt;p&gt;Nobody really knows how they work, not even Santa. Or so he claims. But provided they are able to trust the plan they give the machine, all is good in the North Pole and everyone gets their fill of eggnog.&lt;/p&gt;

&lt;p&gt;Working with Lucas, his chief programmer elf, Santa wrote down the list of steps that he&#38;#39;s perfected by manually building bikes over the last century. These instructions are superficially clear, but because there were lots of dependent steps, it was not so clear at all how they were going specify the proper ordering.&lt;/p&gt;

&lt;p&gt;The steps that he gave his chief programming elf, Lucas, consisted of the following plan for building the perfect bike:&lt;/p&gt;

&lt;dl&gt;

&lt;dt&gt;1. the bike frame must be forged, welded, and painted&lt;/dt&gt;
&lt;dd&gt;

&lt;/dd&gt;
&lt;dt&gt;2. the rear wheel may be attached to the frame once #1 is complete&lt;/dt&gt;
&lt;dd&gt;

&lt;/dd&gt;
&lt;dt&gt;3. the front wheel may be attached to the frame once #1 is complete&lt;/dt&gt;
&lt;dd&gt;

&lt;/dd&gt;
&lt;dt&gt;4. the seat may be added at any time after #1&lt;/dt&gt;
&lt;dd&gt;

&lt;/dd&gt;
&lt;dt&gt;5. handle bars must be attached before the front wheel (#3) is attached&lt;/dt&gt;
&lt;dd&gt;

&lt;/dd&gt;
&lt;dt&gt;6. the front brakes must be added after the front wheel (#3) is added&lt;/dt&gt;
&lt;dd&gt;

&lt;/dd&gt;
&lt;dt&gt;7. the rear brakes must be added after the rear wheel is added in #2&lt;/dt&gt;
&lt;dd&gt;

&lt;/dd&gt;
&lt;dt&gt;8. pedals and gears can be added at any time after #1&lt;/dt&gt;
&lt;dd&gt;

&lt;/dd&gt;
&lt;dt&gt;9. the chain must be added after the pedals and rear wheel (#8)&lt;/dt&gt;
&lt;dd&gt;

&lt;/dd&gt;
&lt;dt&gt;10. send bike to Buddy the Elf for testing&lt;/dt&gt;
&lt;dd&gt;

&lt;/dd&gt;
&lt;/dl&gt;

&lt;p&gt;The work plans are fed into the box using the DSL format that is then read and processed by an internal module called &lt;code&gt;Sub::Genius&lt;/code&gt;. A module aptly named since its original author is certainly not the brightest bulb in the shed. But the module is a good example of the many useful tools that exist on the Internet.&lt;/p&gt;

&lt;p&gt;After being processed by &lt;a href=&#34;https://metacpan.org/module/Sub::Genius&#34;&gt;Sub::Genius&lt;/a&gt;, the plan is turned into a set of actionable steps that the machine blindly follows. If the plan is correct, the end result will be a bicycle.&lt;/p&gt;

&lt;p&gt;The plan is thusly:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    ForgeBike
    InitialPaint
    (
      ( ( RearWheel &#38;amp; Pedals &#38;amp; Gears ) ( RearBrakes &#38;amp; Chain))
      &#38;amp;
      ( Seat)
      &#38;amp;
      ( HandleBars FrontWheel FrontBrakes )
    )
    Buddy2TestBike&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So the elves do not need to list out every possible correct ordering, only ensure that dependent steps are expressed using a nested form that resemble a tree (similar in a lot of ways to &lt;i&gt;LISP&lt;/i&gt;-y &lt;i&gt;S-expressions&lt;/i&gt;).&lt;/p&gt;

&lt;p&gt;Given the program, the magic box provides a way to serialize the execution of the plan into a sequential series of steps, all by using a Perl script:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;strict&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;warnings&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Sub::Genius&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$plan&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;heredoc&#34;&gt;&#38;lt;&#38;lt;EOP&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;heredoc_content&#34;&gt;  ForgeBike&lt;br /&gt;&#38;nbsp;&#38;nbsp;InitialPaint&lt;br /&gt;&#38;nbsp;&#38;nbsp;(&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;( ( RearWheel &#38;amp; Pedals &#38;amp; Gears ) ( RearBrakes &#38;amp; Chain))&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;amp;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;( Seat)&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;amp;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;( HandleBars FrontWheel FrontBrakes )&lt;br /&gt;&#38;nbsp;&#38;nbsp;)&lt;br /&gt;&#38;nbsp;&#38;nbsp;Buddy2TestBike&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;heredoc_terminator&#34;&gt;EOP&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$sg&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Sub::Genius&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;preplan&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$plan&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;init_plan&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# print all sequential orderings of the steps described above&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$preplan&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$sg&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;next&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;interpolate&#34;&gt;qq{$preplan\n}&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When run, this prints all 588 possible correct orders of operations. A sequential set of steps is &lt;i&gt;correct&lt;/i&gt; if it respects the partial ordering among dependent steps described in the plan above.&lt;/p&gt;

&lt;p&gt;For example, &lt;code&gt;HandleBars&lt;/code&gt; must always be installed before the &lt;code&gt;RearBrakes&lt;/code&gt;. But the &lt;code&gt;Pedals&lt;/code&gt; may be installed before or after the &lt;code&gt;FrontBrakes&lt;/code&gt;. And in this way all independent tasks may be interleaved, i.e., may occur in any order; leaving the dependent steps occurring in the order in which they are constrained.&lt;/p&gt;

&lt;p&gt;For example, some of the 588 possible correct orderings follow:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    ForgeBike InitialPaint Pedals Gears RearWheel HandleBars FrontWheel Chain RearBrakes Seat FrontBrakes Buddy2TestBike
    ForgeBike InitialPaint Pedals Gears RearWheel HandleBars FrontWheel Chain RearBrakes FrontBrakes Seat Buddy2TestBike
    ForgeBike InitialPaint Pedals Gears RearWheel Chain HandleBars RearBrakes FrontWheel Seat FrontBrakes Buddy2TestBike
    ForgeBike InitialPaint Pedals Gears RearWheel Chain HandleBars RearBrakes FrontWheel FrontBrakes Seat Buddy2TestBike
    ForgeBike InitialPaint Pedals Gears RearWheel Chain HandleBars RearBrakes Seat FrontWheel FrontBrakes Buddy2TestBike
    ForgeBike InitialPaint Pedals Gears RearWheel Chain HandleBars FrontWheel RearBrakes Seat FrontBrakes Buddy2TestBike
    ForgeBike InitialPaint Pedals Gears RearWheel Chain HandleBars FrontWheel RearBrakes FrontBrakes Seat Buddy2TestBike
    ...
    ForgeBike InitialPaint HandleBars Gears FrontWheel RearWheel Pedals RearBrakes Chain Seat FrontBrakes Buddy2TestBike
    ForgeBike InitialPaint HandleBars Gears FrontWheel RearWheel Pedals RearBrakes Chain FrontBrakes Seat Buddy2TestBike
    ForgeBike InitialPaint HandleBars Gears FrontWheel RearWheel Pedals Chain RearBrakes Seat FrontBrakes Buddy2TestBike
    ForgeBike InitialPaint HandleBars Gears FrontWheel RearWheel Pedals Chain RearBrakes FrontBrakes Seat Buddy2TestBike
    ForgeBike InitialPaint HandleBars Gears FrontWheel Pedals RearWheel RearBrakes Chain Seat FrontBrakes Buddy2TestBike
    ForgeBike InitialPaint HandleBars Gears FrontWheel Pedals RearWheel RearBrakes Chain FrontBrakes Seat Buddy2TestBike
    ForgeBike InitialPaint HandleBars Gears FrontWheel Pedals RearWheel Chain RearBrakes Seat FrontBrakes Buddy2TestBike
    ForgeBike InitialPaint HandleBars Gears FrontWheel Pedals RearWheel Chain RearBrakes FrontBrakes Seat Buddy2TestBike&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It would still be useful, one may suppose, if Lucas could only enumerate the steps in a properly ordered way. But alas, &lt;code&gt;Sub::Genius&lt;/code&gt; is far more useful than that!&lt;/p&gt;

&lt;p&gt;It so happens that if the &lt;code&gt;sub&lt;/code&gt;s with the same names as the &lt;i&gt;steps&lt;/i&gt; of the plan are defined within the scope, then the plan may be actually executed. This allows for each step in the plan to have actions associated with them (even generating additional nested plans).&lt;/p&gt;

&lt;p&gt;Because creating scripts to be executed according to the plan is a tedious task, one of the useful tools &lt;a href=&#34;https://metacpan.org/module/Sub::Genius&#34;&gt;Sub::Genius&lt;/a&gt; provides is called &lt;code&gt;stubby&lt;/code&gt;. This utility can be used to &lt;i&gt;stub&lt;/i&gt; another Perl script with the &lt;code&gt;sub&lt;/code&gt; already in place, just waiting to be filled with useful purpose.&lt;/p&gt;

&lt;p&gt;E.g., if the &lt;i&gt;plan&lt;/i&gt; above is saved to a file, let&#38;#39;s call it &lt;code&gt;./bike.plan&lt;/code&gt;, we&#38;#39;re able to generate a Perl script that contains subroutine stubs for each of the steps that appear in the plan at least once.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  shell&#38;gt; stubby init -f ./bikes.plan --run once &#38;gt; bikes.pl&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The file &lt;code&gt;bikes.pl&lt;/code&gt; is now filled with subroutines stubs that are waiting to be filled in with meaningful code, the script will look something like the following:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;strict&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;warnings&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Sub::Genius&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$plan&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;heredoc&#34;&gt;&#38;lt;&#38;lt;EOP&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;heredoc_content&#34;&gt;  ForgeBike&lt;br /&gt;&#38;nbsp;&#38;nbsp;InitialPaint&lt;br /&gt;&#38;nbsp;&#38;nbsp;(&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;( ( RearWheel &#38;amp; Pedals &#38;amp; Gears ) ( RearBrakes &#38;amp; Chain))&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;amp;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;( Seat)&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;amp;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;( HandleBars FrontWheel FrontBrakes )&lt;br /&gt;&#38;nbsp;&#38;nbsp;)&lt;br /&gt;&#38;nbsp;&#38;nbsp;Buddy2TestBike&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;heredoc_terminator&#34;&gt;EOP&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$sg&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Sub::Genius&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;preplan&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$plan&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;init_plan&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$final_scope&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$sg&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;run_once&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;ForgeBike&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$scope&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;interpolate&#34;&gt;qq{Bike forged!\n}&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$scope&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;InitialPaint&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$scope&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;interpolate&#34;&gt;qq{Bike painted!\n}&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$scope&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;HandleBars&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$scope&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;interpolate&#34;&gt;qq{Handle bars on!\n}&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$scope&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Gears&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$scope&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;interpolate&#34;&gt;qq{Gears on!\n}&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$scope&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;RearWheel&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$scope&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;interpolate&#34;&gt;qq{Rear wheels on!\n}&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$scope&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Pedals&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$scope&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;interpolate&#34;&gt;qq{Pedals on!\n}&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$scope&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;RearBrakes&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$scope&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;interpolate&#34;&gt;qq{Rear brakes on!\n}&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$scope&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;FrontWheel&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$scope&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;interpolate&#34;&gt;qq{Front wheels on!\n}&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$scope&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Chain&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$scope&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;interpolate&#34;&gt;qq{Chain on!\n}&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$scope&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;FrontBrakes&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$scope&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;interpolate&#34;&gt;qq{Front brakes on!\n}&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$scope&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Seat&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$scope&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;interpolate&#34;&gt;qq{Seat on!\n}&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$scope&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Buddy2TestBike&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$scope&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;interpolate&#34;&gt;qq{Ready to test, Buddy!\n}&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$scope&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And each time it&#38;#39;s run, the overall ordering may change, but the ordering will always be correct based on the plan description:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    shell&#38;gt; perl bike.pl

    Bike forged!
    Bike painted!
    Handle bars on!
    Front wheels on!
    Pedals on!
    Rear wheels on!
    Gears on!
    Rear brakes on!
    Chain on!
    Seat on!
    Front brakes on!
    Ready to test, Buddy!

    $ perl bike.pl
    Bike forged!
    Bike painted!
    Pedals on!
    Handle bars on!
    Front wheels on!
    Gears on!
    Rear wheels on!
    Rear brakes on!
    Chain on!
    Front brakes on!
    Seat on!
    Ready to test, Buddy!

    $ perl bike.pl
    Bike forged!
    Bike painted!
    Pedals on!
    Rear wheels on!
    Gears on!
    Chain on!
    Handle bars on!
    Rear brakes on!
    Seat on!
    Front wheels on!
    Front brakes on!
    Ready to test, Buddy!&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note: it is worth looking more into the raw stub file created since it give some nice hints about all the interesting things one may do by giving the &lt;code&gt;sub&lt;/code&gt;s &lt;code&gt;state&lt;/code&gt; and passing along a &lt;code&gt;$scope&lt;/code&gt; reference from one &lt;code&gt;sub&lt;/code&gt; to another, as the sequential form of the plan is being executed.&lt;/p&gt;

&lt;p&gt;And to make a very long story short, Perl saved Yet Another Christmas!&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Prologue&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Lucas ended up having such a joyful time working with coding the plan of the steps for creating the bikes, that he left us this nice little program as a parting gift.&lt;/p&gt;

&lt;p&gt;But don&#38;#39;t try to run it until the clock strikes midnight on December 25!&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;strict&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;warnings&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;feature&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;state&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Sub::Genius&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$preplan&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;literal&#34;&gt;q{&lt;br /&gt;&#38;nbsp;(&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;HO &#38;amp;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;HO &#38;amp;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;HO&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;)&lt;br /&gt;&#38;nbsp;Merry Christmas To All&lt;br /&gt;}&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$sq&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Sub::Genius&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;preplan&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;interpolate&#34;&gt;qq{$preplan}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$sq&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;init_plan&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$final_scope&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$sq&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;run_once&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;scope&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;ns&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;literal&#34;&gt;q{main}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;verbose&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;#&lt;br /&gt;# S U B R O U T I N E S&lt;br /&gt;#&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;HO&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$mystate&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$mystate&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;interpolate&#34;&gt;qq{Merry Christmas to All,\nAnd }&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$mystate&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;elsif&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$mystate&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;interpolate&#34;&gt;qq{to }&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$mystate&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;elsif&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$mystate&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;interpolate&#34;&gt;qq{All, }&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$mystate&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Merry&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;interpolate&#34;&gt;qq{A }&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Christmas&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;interpolate&#34;&gt;qq{Good }&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;To&lt;/span&gt;  &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;interpolate&#34;&gt;qq{Night}&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;All&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;interpolate&#34;&gt;qq{!\n}&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The story does not end here, but it is time to conclude this chapter. Santa and Lucas successfully programmed the magick black box, and countless children received their bikes. A lucky few received a scooter and fez cap instead, but that&#38;#39;s a story for a different Advent.&lt;/p&gt;

&lt;dl&gt;

&lt;dt&gt;&lt;a href=&#34;https://metacpan.org/pod/Sub::Genius&#34;&gt;https://metacpan.org/pod/Sub::Genius&lt;/a&gt; - includes info on how this all works&lt;/dt&gt;
&lt;dd&gt;

&lt;/dd&gt;
&lt;dt&gt;&lt;a href=&#34;https://metacpan.org/pod/FLAT&#34;&gt;https://metacpan.org/pod/FLAT&lt;/a&gt; - processing engine&lt;/dt&gt;
&lt;dd&gt;

&lt;/dd&gt;
&lt;dt&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/S-expression&#34;&gt;https://en.wikipedia.org/wiki/S-expression&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;

&lt;/dd&gt;
&lt;/dl&gt;

&lt;/div&gt;</summary><updated>2023-12-17T00:00:00Z</updated><category term="Perl"/><author><name>oodler</name></author></entry><entry><title type="html">Santa&#38;rsquo;s Workshop Secrets: The Magical Test2 Suite (Part 2)</title><link href="https://perladvent.org/2023/2023-12-16.html"/><id>https://perladvent.org/2023/2023-12-16.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;Greetings, festive readers! Santa Claus here, ready to share yet another behind-the-scenes look at how we keep Christmas joyfully on track with the Magical Test2 Suite, soon to be a core test library in Perl 5.40 onwards.&lt;/p&gt;

&lt;p&gt;If you haven&#38;#39;t read &lt;a href=&#34;https://perladvent.org/2023/2023-12-15.html&#34;&gt;part 1&lt;/a&gt;, it&#38;#39;s a real treat!&lt;/p&gt;

&lt;p&gt;Just like the tinsel on your tree, mocks add that extra sparkle to our unit tests. Mocks can help us simulate certain behaviors, creating a controlled environment for unit testing. We can create mock classes, objects or methods in order to properly test others that interact with them.&lt;/p&gt;

&lt;p&gt;And with the Test 2 Suite, this has never been easier!&lt;/p&gt;

&lt;h3 id=&#34;Easily-mocking-objects-and-classes&#34;&gt;Easily mocking objects and classes&lt;/h3&gt;

&lt;p&gt;For starters, let&#38;rsquo;s say you want to create an object that will be passively called by whatever it is you&#38;rsquo;re testing:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;synStatement&#34;&gt;use &lt;/span&gt;Test2::V0;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$obj&lt;/span&gt; = mock;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, &lt;code&gt;$obj&lt;/code&gt; is a dud that will accept any method calls and return &lt;code&gt;undef&lt;/code&gt;. What about if you want it to return something specific?&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$obj&lt;/span&gt; = mock { &lt;span class=&#34;synConstant&#34;&gt;merry&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;&#39;christmas!&#39;&lt;/span&gt; };&lt;br /&gt;&lt;br /&gt;is &lt;span class=&#34;synIdentifier&#34;&gt;$obj&lt;/span&gt;-&#38;gt;merry, &lt;span class=&#34;synConstant&#34;&gt;&#39;christmas!&#39;&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;&#39;my mock works&#39;&lt;/span&gt;;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When you need to test chained calls, you can always nest your mocks():&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$obj&lt;/span&gt; = mock {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;happy&lt;/span&gt; =&#38;gt; mock {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;holidays&lt;/span&gt; =&#38;gt; mock {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;everyone&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;&#39;Ho! Ho! Ho!&#39;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;}&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;}&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;is &lt;span class=&#34;synIdentifier&#34;&gt;$obj&lt;/span&gt;-&#38;gt;happy-&#38;gt;holidays-&#38;gt;everyone, &lt;span class=&#34;synConstant&#34;&gt;&#39;Ho! Ho! Ho!&#39;&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;&#39;chained mocks&#39;&lt;/span&gt;;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;i&gt;&#38;quot;But Santa&#38;quot;&lt;/i&gt;, you may ask, &lt;i&gt;&#38;quot;What about when the class is instantiated and used somewhere inside the code I want to test? How can I use mocks to add or override methods to something out of my hands?&#38;quot;&lt;/i&gt; No worries! Just expand your mock definition for more control:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$mock_meta&lt;/span&gt; = mock &lt;span class=&#34;synConstant&#34;&gt;&#39;Some::Class&#39;&lt;/span&gt; =&#38;gt; (&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;track&lt;/span&gt; =&#38;gt; true,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;override&lt;/span&gt; =&#38;gt; [&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;some_method&lt;/span&gt;  =&#38;gt; &lt;span class=&#34;synStatement&#34;&gt;sub &lt;/span&gt;{ ... },&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;other_method&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synStatement&#34;&gt;sub &lt;/span&gt;{ ... },&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;],&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;add&lt;/span&gt; =&#38;gt; [&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;new_method&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synStatement&#34;&gt;sub &lt;/span&gt;{ ... },&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;],&lt;br /&gt;);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And now, as long as &lt;code&gt;$mock_meta&lt;/code&gt; exists, any instances of &#38;quot;&lt;code&gt;Some::Class&lt;/code&gt;&#38;quot; will have the mocked behavior. To restore them back to the original, simply undefine that &lt;code&gt;$mock_meta&lt;/code&gt; variable or call &lt;code&gt;$mock_meta-&#38;gt;reset_all()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One thing you may have noticed in the example above is the &#38;quot;&lt;code&gt;track =&#38;gt; true&lt;/code&gt;&#38;quot;. That means &lt;code&gt;$mock_meta&lt;/code&gt; will contain a lot of information ready for you to inspect regarding how many times any given method was called, and which arguments were used. This is particularly important to check if the code you&#38;rsquo;re testing is properly invoking the mocked class.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;test_something_that_uses_my_mocked_class();&lt;br /&gt;is(&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;$mock_meta&lt;/span&gt;-&#38;gt;sub_tracking-&#38;gt;{some_method}-&#38;gt;@*,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;1&lt;/span&gt;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;&#39;some_method() called only once!&#39;&lt;/span&gt;&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;like(&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;$mock_meta&lt;/span&gt;-&#38;gt;sub_tracking-&#38;gt;{some_method}[&lt;span class=&#34;synConstant&#34;&gt;0&lt;/span&gt;]{args},&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;[ &lt;span class=&#34;synConstant&#34;&gt;qr()&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;&#39;arg1&#39;&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;qr(arg2)&lt;/span&gt; ],&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;&#39;testing call arguments for method &#38;quot;some_method&#38;quot;&#39;&lt;/span&gt;&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;$mock_meta&lt;/span&gt;-&#38;gt;clear_sub_tracking(); &lt;span class=&#34;synComment&#34;&gt;# so we can go again in isolation&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that to get the mock metadata from a given variable holding an object, you can also do:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; (&lt;span class=&#34;synIdentifier&#34;&gt;$mock_meta&lt;/span&gt;) = mocked &lt;span class=&#34;synIdentifier&#34;&gt;$actual_obj&lt;/span&gt;;&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;Mocking-the-Christmas-Wishlist-Database&#34;&gt;Mocking the Christmas Wishlist Database&lt;/h3&gt;

&lt;p&gt;For a real world example, let&#38;#39;s see how the elves use Test2 Suite&#38;#39;s mocking features to test our gift delivery system. The code looks roughly like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;synStatement&#34;&gt;sub &lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;deliver_gift &lt;/span&gt;($&lt;span class=&#34;synIdentifier&#34;&gt;child_name&lt;/span&gt;, $&lt;span class=&#34;synIdentifier&#34;&gt;gift_name&lt;/span&gt;) {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$schema&lt;/span&gt; = GiftDB::Schema-&#38;gt;get_active_connection();&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$wish&lt;/span&gt; = &lt;span class=&#34;synIdentifier&#34;&gt;$schema&lt;/span&gt;-&#38;gt;resultset(&lt;span class=&#34;synConstant&#34;&gt;&#39;Wishlist&#39;&lt;/span&gt;)-&#38;gt;single({&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;name&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synIdentifier&#34;&gt;$child_name&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;gift&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synIdentifier&#34;&gt;$gift_name&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;});&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;if&lt;/span&gt; (&lt;span class=&#34;synIdentifier&#34;&gt;$wish&lt;/span&gt; &#38;amp;&#38;amp; &lt;span class=&#34;synIdentifier&#34;&gt;$wish&lt;/span&gt;-&#38;gt;update({ &lt;span class=&#34;synConstant&#34;&gt;delivered&lt;/span&gt; =&#38;gt; true })) {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;synConstant&#34;&gt;&#39;delivered!&#39;&lt;/span&gt;;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;}&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;synConstant&#34;&gt;&#39;oh, no...&#39;&lt;/span&gt;;&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The function looks simple enough: we get an active database connection, select the wishlist table/resultset, and see if we can find the child&#38;#39;s wishlist entry. If we have it, we update the entry to &#38;#39;delivered&#38;#39;.&lt;/p&gt;

&lt;p&gt;But how do we test it without actually using a database? We mock the database, that&#38;#39;s how!&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;synStatement&#34;&gt;use &lt;/span&gt;builtin &lt;span class=&#34;synConstant&#34;&gt;qw( true false weaken )&lt;/span&gt;;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;use &lt;/span&gt;Test2::V0;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synComment&#34;&gt;# mock simple resultsets and results:&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$mock_wishlist_rs&lt;/span&gt; = mock &lt;span class=&#34;synConstant&#34;&gt;&#39;obj&#39;&lt;/span&gt; =&#38;gt; (&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;track&lt;/span&gt; =&#38;gt; true,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;add&lt;/span&gt; =&#38;gt; [&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;single&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synStatement&#34;&gt;sub &lt;/span&gt;($&lt;span class=&#34;synIdentifier&#34;&gt;self&lt;/span&gt;, $) { weaken &lt;span class=&#34;synIdentifier&#34;&gt;$self&lt;/span&gt;; &lt;span class=&#34;synStatement&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$self&lt;/span&gt; },&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;update&lt;/span&gt; =&#38;gt; true,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;],&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synComment&#34;&gt;# mock the main schema, and point calls to resultset()&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synComment&#34;&gt;# to our mock_wishlist_rs:&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$mock_schema&lt;/span&gt; = mock &lt;span class=&#34;synConstant&#34;&gt;&#39;GiftDB::Schema&#39;&lt;/span&gt; =&#38;gt; (&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;track&lt;/span&gt; =&#38;gt; true,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;override&lt;/span&gt; =&#38;gt; [&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;get_active_connection&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synStatement&#34;&gt;sub &lt;/span&gt;($&lt;span class=&#34;synIdentifier&#34;&gt;class&lt;/span&gt;) { &lt;span class=&#34;synIdentifier&#34;&gt;$class&lt;/span&gt; },&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;resultset&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synStatement&#34;&gt;sub &lt;/span&gt;{ &lt;span class=&#34;synIdentifier&#34;&gt;$mock_wishlist_rs&lt;/span&gt; },&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;],&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synComment&#34;&gt;# That&#39;s it! Now let&#39;s write some tests:&lt;/span&gt;&lt;br /&gt;plan &lt;span class=&#34;synConstant&#34;&gt;5&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;is(&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;Magic::Santa::Sack::deliver_gift(&lt;span class=&#34;synConstant&#34;&gt;&#39;anna&#39;&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;&#39;starship&#39;&lt;/span&gt;),&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;&#39;delivered!&#39;&lt;/span&gt;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;works when we have the gift&#38;quot;&lt;/span&gt;&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;like(&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;$mock_schema&lt;/span&gt;-&#38;gt;sub_tracking-&#38;gt;{resultset},&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;[ { &lt;span class=&#34;synConstant&#34;&gt;args&lt;/span&gt; =&#38;gt; [ &lt;span class=&#34;synConstant&#34;&gt;&#39;GiftDB::Schema&#39;&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;&#39;Wishlist&#39;&lt;/span&gt; ] }, DNE ],&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;&#39;call to resultset() asks for the right table (wishlist)&#39;&lt;/span&gt;&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; (&lt;span class=&#34;synIdentifier&#34;&gt;$meta_wishlist_rs&lt;/span&gt;) = mocked(&lt;span class=&#34;synIdentifier&#34;&gt;$mock_wishlist_rs&lt;/span&gt;);&lt;br /&gt;like(&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;$meta_wishlist_rs&lt;/span&gt;-&#38;gt;call_tracking,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;[&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;{ &lt;span class=&#34;synConstant&#34;&gt;args&lt;/span&gt; =&#38;gt; [ D(), { &lt;span class=&#34;synConstant&#34;&gt;name&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;&#39;anna&#39;&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;gift&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;&#39;starship&#39;&lt;/span&gt; }, DNE() ], &lt;span class=&#34;synConstant&#34;&gt;sub_name&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;&#39;single&#39;&lt;/span&gt; },&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;{ &lt;span class=&#34;synConstant&#34;&gt;args&lt;/span&gt; =&#38;gt; [ D(), { &lt;span class=&#34;synConstant&#34;&gt;delivered&lt;/span&gt; =&#38;gt; true }, DNE() ], &lt;span class=&#34;synConstant&#34;&gt;sub_name&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;&#39;update&#39;&lt;/span&gt; },&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;DNE()&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;],&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;&#39;wishlist resultset properly manipulated&#39;&lt;/span&gt;&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synComment&#34;&gt;# clear tracking so we can test again:&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;$meta_wishlist_rs&lt;/span&gt;-&#38;gt;clear_call_tracking;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synComment&#34;&gt;# now let&#39;s see if it works as expected when the&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synComment&#34;&gt;# database can&#39;t find the child/gift pair. We emulate&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synComment&#34;&gt;# this in our mock by making the call to single()&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synComment&#34;&gt;# return false instead:&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;$meta_wishlist_rs&lt;/span&gt;-&#38;gt;override( &lt;span class=&#34;synConstant&#34;&gt;&#39;single&#39;&lt;/span&gt; =&#38;gt; false );&lt;br /&gt;&lt;br /&gt;is(&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;Magic::Santa::Sack::deliver_gift(&lt;span class=&#34;synConstant&#34;&gt;&#39;anna&#39;&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;&#39;starship&#39;&lt;/span&gt;),&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;&#39;oh, no...&#39;&lt;/span&gt;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;fails when we don&#39;t have the gift&#38;quot;&lt;/span&gt;&lt;br /&gt;);&lt;br /&gt;like(&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;$meta_wishlist_rs&lt;/span&gt;-&#38;gt;call_tracking,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;[&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;{ &lt;span class=&#34;synConstant&#34;&gt;args&lt;/span&gt; =&#38;gt; [ D(), { &lt;span class=&#34;synConstant&#34;&gt;name&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;&#39;anna&#39;&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;gift&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;&#39;starship&#39;&lt;/span&gt; }, DNE() ], &lt;span class=&#34;synConstant&#34;&gt;sub_name&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;&#39;single&#39;&lt;/span&gt; },&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;DNE()&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;],&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;&#39;wishlist resultset queried with proper args&#39;&lt;/span&gt;&lt;br /&gt;);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So there you have it. With the magical powers of Test2, when Christmas Eve arrives, I&#38;rsquo;ll take off on my sleigh with confidence, knowing that every toy has passed its tests. This means more smiles, laughter, and Christmas joy for people all around the world. Give it a try, too, and may your code be as merry and bright as the star on top of your tree.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;&#38;ndash; Santa, out.&lt;/i&gt;&lt;/p&gt;

&lt;/div&gt;</summary><updated>2023-12-16T00:00:00Z</updated><category term="Perl"/><author><name>Breno G. de Oliveira</name></author></entry><entry><title type="html">Santa&#38;rsquo;s Workshop Secrets: The Magical Test2 Suite (Part 1)</title><link href="https://perladvent.org/2023/2023-12-15.html"/><id>https://perladvent.org/2023/2023-12-15.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;Ho, ho, ho, dear friends! Tonight I have a little behind-the-scenes to share with you directly from the North Pole. As you all know, this season is pretty busy for me and the elves. We have to make sure every letter is received, assigned and fulfilled, and that every present is in tip-top condition and delivered on time. So, of course, our Christmas operation needs to be tested thoroughly.&lt;/p&gt;

&lt;p&gt;But writing good tests can sometimes be a coal in the stocking. Some things are hard to test, and even though Perl has many nice testing modules to help with that, I can never quite remember their names or which to use, and together they can add so many external dependencies that we mostly keep ourselves to &lt;a href=&#34;https://metacpan.org/module/Test::More&#34;&gt;Test::More&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Well, not anymore. This year we updated all our test code to use the magical &lt;a href=&#34;https://metacpan.org/pod/Test2::V0&#34;&gt;Test2-Suite&lt;/a&gt;. A single distribution that updates and replaces not just Test::More, but many other testing modules. And the best part? It will be a core distribution in Perl 5.40 onwards! Talk about a Christmas Miracle &#38;lt;3&lt;/p&gt;

&lt;p&gt;The basics work pretty much like Test::More, so if you&#38;rsquo;re used to it you&#38;rsquo;ll feel right at home. In fact, if you&#38;rsquo;re not doing anything fancy you can probably replace &#38;quot;&lt;code&gt;use Test::More&lt;/code&gt;&#38;quot; with &#38;quot;&lt;code&gt;use Test2::V0&lt;/code&gt;&#38;quot; and everything will work just fine. Check it out:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;synStatement&#34;&gt;use &lt;/span&gt;Test2::V0;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;use &lt;/span&gt;Acme::Christmas;&lt;br /&gt;&lt;br /&gt;ok &lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$xmas&lt;/span&gt; = Acme::Christmas-&#38;gt;new, &lt;span class=&#34;synConstant&#34;&gt;&#39;able to instantiate object&#39;&lt;/span&gt;;&lt;br /&gt;isa_ok &lt;span class=&#34;synIdentifier&#34;&gt;$xmas&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;&#39;Acme::Christmas&#39;&lt;/span&gt;;&lt;br /&gt;can_ok &lt;span class=&#34;synIdentifier&#34;&gt;$xmas&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;qw( read_letters make_toys )&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;is &lt;span class=&#34;synIdentifier&#34;&gt;$xmas&lt;/span&gt;-&#38;gt;date, &lt;span class=&#34;synConstant&#34;&gt;&#39;December, 25th&#39;&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;&#39;got the right date&#39;&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;note &lt;span class=&#34;synConstant&#34;&gt;&#38;quot;let&#226;~@~Ys see if the Grinch is close&#38;quot;&lt;/span&gt;;&lt;br /&gt;subtest &lt;span class=&#34;synConstant&#34;&gt;&#39;assert that the grinch is far away&#39;&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synStatement&#34;&gt;sub &lt;/span&gt;{&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;if&lt;/span&gt; (grinch()) {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;fail &lt;span class=&#34;synConstant&#34;&gt;&#39;oh, noes&#226;~@&#166;&#39;&lt;/span&gt;;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;} &lt;span class=&#34;synStatement&#34;&gt;else&lt;/span&gt; {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;pass &lt;span class=&#34;synConstant&#34;&gt;&#39;coast is clear!&#39;&lt;/span&gt;;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;}&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;SKIP:&lt;/span&gt; {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;skip &lt;span class=&#34;synConstant&#34;&gt;&#38;quot;tests for winter only&#38;quot;&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;synStatement&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$xmas&lt;/span&gt;-&#38;gt;is_winter;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;like &lt;span class=&#34;synIdentifier&#34;&gt;$xmas&lt;/span&gt;-&#38;gt;carol, &lt;span class=&#34;synConstant&#34;&gt;qr/Merry/&lt;/span&gt;, &#226;~@~Xfound the proper lyrics&#226;~@~Y;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;done_testing; &lt;span class=&#34;synComment&#34;&gt;# you can also &#38;quot;plan N;&#38;quot; if you prefer to count your tests.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;But you&#38;rsquo;ll also get some nice cranberry sauce right out of the box. For starters, &lt;code&gt;strict&lt;/code&gt; and &lt;code&gt;warnings&lt;/code&gt; are on by default (and don&#38;rsquo;t worry, you can easily disable this behavior if you want). Second, remember how you always wanted tests to print more useful debug data when they fail? Now you can! Test2::V0&#38;rsquo;s &lt;code&gt;is()&lt;/code&gt;, &lt;code&gt;ok()&lt;/code&gt;, &lt;code&gt;like()&lt;/code&gt; and most other test functions support extra arguments &lt;i&gt;after the test description&lt;/i&gt;, so you can write them as:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;ok &lt;span class=&#34;synIdentifier&#34;&gt;$xmas&lt;/span&gt;-&#38;gt;ready, &lt;span class=&#34;synConstant&#34;&gt;&#38;quot;test if christmas is ready&#38;quot;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;=&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;&#38;quot;hmm... this was not supposed to fail. Let&#39;s see...&#38;quot;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;. &lt;span class=&#34;synConstant&#34;&gt;&#38;quot; the tree is &#38;quot;&lt;/span&gt; . &lt;span class=&#34;synIdentifier&#34;&gt;$xmas&lt;/span&gt;-&#38;gt;tree&lt;br /&gt;&#38;nbsp;&#38;nbsp;. &lt;span class=&#34;synConstant&#34;&gt;&#38;quot; and we have &#38;quot;&lt;/span&gt; . &lt;span class=&#34;synIdentifier&#34;&gt;$xmas&lt;/span&gt;-&#38;gt;presents-&#38;gt;count . &lt;span class=&#34;synConstant&#34;&gt;&#38;quot; wrapped gifts.&#38;quot;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and all that extra output will be printed only if the test fails. Ho! Ho! Ho!&lt;/p&gt;

&lt;h3 id=&#34;The-all-powerful-is-and-like&#34;&gt;The all-powerful &#38;quot;is&#38;quot; and &#38;quot;like&#38;quot;&lt;/h3&gt;

&lt;p&gt;This is straight out my favorite feature. You may have noticed I did not include &#38;quot;&lt;code&gt;is_deeply()&lt;/code&gt;&#38;quot; on the list of compatibility with Test::More. Well, that&#38;rsquo;s because there is no need for it. That&#38;rsquo;s right! If the variable you&#38;rsquo;re testing is a data structure, you can simply use &lt;code&gt;is()&lt;/code&gt; and it will do a deep check, failing if values don&#38;rsquo;t match or if anything is missing:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;is &lt;span class=&#34;synIdentifier&#34;&gt;$recipe&lt;/span&gt;, {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;name&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;&#39;Fruitcake&#39;&lt;/span&gt;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;ingredients&lt;/span&gt; =&#38;gt; {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;eggs&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;5&lt;/span&gt;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;flour&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;3&lt;/span&gt;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;&#39;dried fruit&#39;&lt;/span&gt; =&#38;gt; [&lt;span class=&#34;synConstant&#34;&gt;&#39;cherries&#39;&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;&#39;apricots&#39;&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;&#39;dates&#39;&lt;/span&gt;],&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;},&lt;br /&gt;}, &lt;span class=&#34;synConstant&#34;&gt;&#39;got proper dessert!&#39;&lt;/span&gt;;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What about that time of the year when you get a data structure or object and care only about a few keys, items or attributes? Ooh, Santa&#38;rsquo;s got a gift for you, too! &lt;b&gt;Use like() with the nested structure to ignore any keys/positions you haven&#38;rsquo;t defined&lt;/b&gt; in a true non-strict (partial) match. It even lets you mix and match between exact values (by passing a string or a number) and values that match a regular expression (by providing the regexp).&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;like &lt;span class=&#34;synIdentifier&#34;&gt;$recipe&lt;/span&gt;, {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;name&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;qr(cake)i&lt;/span&gt;,  &lt;span class=&#34;synComment&#34;&gt;# must contain &#226;~@~Xcake&#226;~@~Y (case insensitive)&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;ingredients&lt;/span&gt; =&#38;gt; {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;eggs&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;qr(&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;\d+&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;)&lt;/span&gt;,   &lt;span class=&#34;synComment&#34;&gt;# any number&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;flour&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;5&lt;/span&gt;,            &lt;span class=&#34;synComment&#34;&gt;# exactly 5&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;dried fruit&#226;~@~Y =&#38;gt; [&lt;span class=&#34;synConstant&#34;&gt;qr/cherr&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;y|ies&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;/&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;&#39;apricots&#39;&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;qr/dates&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;/&lt;/span&gt;],  &lt;span class=&#34;synComment&#34;&gt;# mix and match!&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;}&lt;br /&gt;}, &lt;span class=&#34;synConstant&#34;&gt;&#39;partial match in nested variables, mixing is() and like() at any level&#39;&lt;/span&gt;;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;```&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Think the presents are over? Think again! For even more complex validations you can check your variable against a builder (and there are &lt;a href=&#34;https://metacpan.org/pod/Test2::Tools::Compare#VALUE-SPECIFICATIONS&#34;&gt;many builders available for hashes, arrays, objects, etc&lt;/a&gt;). For example, let&#38;rsquo;s say I wanted to check whether &lt;code&gt;$recipe&lt;/code&gt; has a name and ingredients, and if one of the dried fruits is raisins. Also, just to make it a little harder, let&#38;rsquo;s make sure it has no key called &#38;lsquo;microwave&#38;rsquo;. To do all that, we just write a very simple definition of our partial hash containing only the bits we care about:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;synComment&#34;&gt;# import everything we use in this test&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synComment&#34;&gt;# (the :DEFAULT label is to ensure all regular symbols are also imported)&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;use &lt;/span&gt;Test2::V0 &lt;span class=&#34;synConstant&#34;&gt;qw( :DEFAULT hash field bag item etc L DNE )&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;is &lt;span class=&#34;synIdentifier&#34;&gt;$recipe&lt;/span&gt;, hash {&lt;br /&gt;&#38;nbsp;&#38;nbsp;field &lt;span class=&#34;synConstant&#34;&gt;name&lt;/span&gt; =&#38;gt; L;  &lt;span class=&#34;synComment&#34;&gt;# the value of the &#39;name&#39; key is defined and has a L()ength.&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;field &lt;span class=&#34;synConstant&#34;&gt;ingredients&lt;/span&gt; =&#38;gt; hash {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synComment&#34;&gt;# &#39;bag&#39; is an &#39;array&#39; that doesn&#39;t care about element order.&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;field &lt;span class=&#34;synConstant&#34;&gt;&#39;dried fruit&#39;&lt;/span&gt; =&#38;gt; bag { item &lt;span class=&#34;synConstant&#34;&gt;&#39;raisins&#39;&lt;/span&gt;; etc; };&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;etc;&lt;br /&gt;&#38;nbsp;&#38;nbsp;};&lt;br /&gt;&#38;nbsp;&#38;nbsp;field &lt;span class=&#34;synConstant&#34;&gt;microwave&lt;/span&gt; =&#38;gt; DNE; &lt;span class=&#34;synComment&#34;&gt;# the &#39;microwave&#39; key Does Not Exist.&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;etc;    &lt;span class=&#34;synComment&#34;&gt;# ignore other keys. Use &#39;end&#39; to fail the test if other keys exist.&lt;/span&gt;&lt;br /&gt;}, &lt;span class=&#34;synConstant&#34;&gt;&#39;partial match from a generated definition!&#39;&lt;/span&gt;;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If that wasn&#38;rsquo;t impressive enough, here are some extra nice ways to make your tests more thorough, robust and clear without having to load external modules or fiddle with the symbol table:&lt;/p&gt;

&lt;h3 id=&#34;Test-if-loading-a-module-imports-or-doesn-t-import-a-function-or-a-variable&#34;&gt;Test if loading a module imports (or doesn&#38;rsquo;t import) a function or a variable:&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;synStatement&#34;&gt;use &lt;/span&gt;Some::Module;&lt;br /&gt;imported_ok &lt;span class=&#34;synConstant&#34;&gt;&#39;mysub&#39;&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;&#39;$myvar&#39;&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;&#39;@myothervar&#39;&lt;/span&gt;;&lt;br /&gt;not_imported_ok &lt;span class=&#34;synConstant&#34;&gt;&#39;othersub&#39;&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;&#39;$othervar&#39;&lt;/span&gt;;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;```&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;Test-if-something-warns-or-dies-raises-an-exception&#34;&gt;Test if something warns or dies / raises an exception&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;like dies { &#226;~@&#166; }, &lt;span class=&#34;synConstant&#34;&gt;qr/some error/&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;&#39;got expected exception from block&#39;&lt;/span&gt;;&lt;br /&gt;ok lives { &#226;~@&#166; }, &lt;span class=&#34;synConstant&#34;&gt;&#39;code lived!&#39;&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;&#38;quot;oh, noes! Died with error &#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;$@&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;&#38;quot;&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;ok warns { &#226;~@&#166; }, &lt;span class=&#34;synConstant&#34;&gt;&#39;at least one warning was issued in the block&#39;&lt;/span&gt;;&lt;br /&gt;is warns { &#226;~@&#166; }, &lt;span class=&#34;synConstant&#34;&gt;2&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;&#39;got the right number of warnings in block&#39;&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;is warnings { &#226;~@&#166; }, [&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;qr/first warning issued/&lt;/span&gt;,    &lt;span class=&#34;synComment&#34;&gt;# lax match&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;&#39;second warning issued in somefile.pl line 10&#39;&lt;/span&gt;,  &lt;span class=&#34;synComment&#34;&gt;# strict match,&lt;/span&gt;&lt;br /&gt;], &lt;span class=&#34;synConstant&#34;&gt;&#39;matched expected warning messages&#39;&lt;/span&gt;;&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;Stop-and-bail-out-of-testing-whenever-a-single-test-fails&#34;&gt;Stop and bail out of testing whenever a single test fails:&lt;/h3&gt;

&lt;p&gt;If you add this to the beginning of your test file, it will die and stop testing that file as soon as any test on that file fails:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;synStatement&#34;&gt;use &lt;/span&gt;Test2::Plugin::DieOnFail;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you&#38;rsquo;re running a bunch of different test files, it will not stop testing altogether, just that particular file. To truly bail out of all testing as soon as any test on a file fails, do this instead:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;synStatement&#34;&gt;use &lt;/span&gt;Test2::Plugin::BailOnFail;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you just want to bail on a single test in the file, use &#38;quot;&lt;code&gt;... or bail_out($reason)&lt;/code&gt;&#38;quot; after the test.&lt;/p&gt;

&lt;h3 id=&#34;Skip-tests-unless-we-have-a-specific-perl-or-module-version-available&#34;&gt;Skip tests unless we have a specific perl or module version available:&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;synComment&#34;&gt;# skip all tests in file unless perl is v5.38 or greater:&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;use &lt;/span&gt;Test2::Require::Perl &lt;span class=&#34;synConstant&#34;&gt;&#39;v5.38&#39;&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synComment&#34;&gt;# skip all tests in file unless &#226;~@~XSome::Module version 2.34 or greater is available.&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synComment&#34;&gt;# omit the version if you only care about whether the module is available or not.&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;use &lt;/span&gt;Test2::Require::Module &lt;span class=&#34;synConstant&#34;&gt;&#39;Some::Module&#39;&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;&#39;2.34&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now please excuse this old man because I have to feed the reindeer really well before the big day. But grab a gingerbread cookie and stay tuned for part 2 of Santa&#38;#39;s Workshop Secrets. I&#38;#39;ll be back in a jiffy with my favorite new tool in the Test2 Suite: mocks!&lt;/p&gt;

&lt;p&gt;&lt;i&gt;&#38;ndash; Santa, out.&lt;/i&gt;&lt;/p&gt;

&lt;/div&gt;</summary><updated>2023-12-15T00:00:00Z</updated><category term="Perl"/><author><name>Breno G. de Oliveira</name></author></entry><entry><title>Introduction to class feature</title><link href="https://perladvent.org/2023/2023-12-14.html"/><id>https://perladvent.org/2023/2023-12-14.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h3 id=&#34;Background&#34;&gt;Background&lt;/h3&gt;

&lt;p&gt;I have followed the last 2 releases of Perl i.e. &lt;code&gt;Perl v5.36&lt;/code&gt; and &lt;code&gt;Perl v5.38&lt;/code&gt; very closely. &lt;code&gt;Perl v5.36&lt;/code&gt; was released on &lt;code&gt;2022-05-28&lt;/code&gt; with much fanfare as it had so much nice new features introduced. If you haven&#38;#39;t had chance to play with then I have compiled some for you. Please &lt;a href=&#34;https://github.com/manwar/perl-cool-snippets?tab=readme-ov-file#perl-v536&#34;&gt;check out&lt;/a&gt; this collection for quick introduction.&lt;/p&gt;

&lt;p&gt;Following the release of &lt;code&gt;Perl v5.36&lt;/code&gt;, the discussion of new object system &lt;code&gt;Corinna&lt;/code&gt; took the limelight as it was one of the main features to be introduced with &lt;code&gt;Perl v5.38&lt;/code&gt;. Then finally on &lt;code&gt;2023-07-02&lt;/code&gt;, we had &lt;code&gt;Perl v5.38&lt;/code&gt; released.&lt;/p&gt;

&lt;p&gt;After the release, I wanted to try new class feature but never got the opportunity to play with it.&lt;/p&gt;

&lt;p&gt;I have played with &lt;a href=&#34;https://github.com/manwar/Design-Patterns&#34;&gt;Design Patterns&lt;/a&gt; using the &lt;code&gt;Moo&lt;/code&gt; based object in the past. So I thought why not pick one of the design pattern and try with the new class feature.&lt;/p&gt;

&lt;h3 id=&#34;Singleton-using-Moo&#34;&gt;Singleton using Moo&lt;/h3&gt;

&lt;p&gt;As you see the code below, it is such a lightweight implementation of &lt;code&gt;Singleton&lt;/code&gt; using &lt;a href=&#34;https://metacpan.org/module/Moo&#34;&gt;Moo&lt;/a&gt; with &lt;a href=&#34;https://metacpan.org/module/MooX::Singleton&#34;&gt;MooX::Singleton&lt;/a&gt;. The only issue I have is the dependency on non-core module.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;SingleObject&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Moo&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;MooX::Singleton&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;count&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;rw&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;});&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;counter&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;count&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;SingleObject&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;instance&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;counter&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;\n&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;SingleObject&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;instance&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;counter&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;\n&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;SingleObject&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;instance&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;counter&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;\n&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;SingleObject&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;instance&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;counter&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;\n&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;SingleObject&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;instance&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;counter&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;\n&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This gives us the following output:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    1
    2
    3
    4
    5&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;Implementation-of-Singleton-using-new-class-feature&#34;&gt;Implementation of Singleton using new class feature&lt;/h3&gt;

&lt;p&gt;With the &lt;code&gt;Perl v5.38&lt;/code&gt; release, we no longer have the dependency on external modules as seen in the code below:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;version&#34;&gt;v5.38&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;experimental&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;class&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Singleton&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;0.01&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$instance&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;instance&lt;/span&gt;&lt;span class=&#34;prototype&#34;&gt;($class)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$instance&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;//=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$class&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;label&#34;&gt;SingleObject :&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;Singleton&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;field&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$count&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;param&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;method&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;counter&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$count&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;SingleObject&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;instance&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;counter&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;SingleObject&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;instance&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;counter&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;SingleObject&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;instance&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;counter&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;SingleObject&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;instance&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;counter&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;SingleObject&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;instance&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;counter&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This gives us exactly the same output as above.&lt;/p&gt;

&lt;h3 id=&#34;How-about-some-more&#34;&gt;How about some more?&lt;/h3&gt;

&lt;p&gt;Well, I then tried to show &lt;code&gt;inheritance&lt;/code&gt; using new class feature. It looks amazingly compact and clean.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;version&#34;&gt;v5.38&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;experimental&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;class&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Animal&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;method&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;eat&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;I can eat!&#38;quot;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;label&#34;&gt;Dog :&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;Animal&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;method&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;bark&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Woof Woof!&#38;quot;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$dog&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Dog&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$dog&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;eat&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$dog&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;bark&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This gives us the following output:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    I can eat!
    Woof Woof!&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&#38;#39;s it for now until we meet again.&lt;/p&gt;

&lt;/div&gt;</summary><updated>2023-12-14T00:00:00Z</updated><category term="Perl"/><author><name>Mohammad Anwar</name></author></entry><entry><title type="html">Santa&#38;#39;s New Dispatcher</title><link href="https://perladvent.org/2023/2023-12-13.html"/><id>https://perladvent.org/2023/2023-12-13.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;St. Nick&#38;#39;s had computer problems nearly non-stop this year, and at a critical time he&#38;#39;s been unable to access any letters &#38;quot;To Santa&#38;quot; that have been emailed to him, which is quite a few considering this Internet fad doesn&#38;#39;t seem to be slowing down any time soon.&lt;/p&gt;

&lt;p&gt;To that end, at this critical hour he&#38;#39;s decided to write a Perl script that will automatically assign a toy to a child based on the starting letter of their first name and the random flip of a coin.&lt;/p&gt;

&lt;p&gt;At first pass, his code seems to do what he wants; but it&#38;#39;s a nasty set of &lt;code&gt;if-elsif-else&lt;/code&gt; statements. Mrs. Clause would most certainly not find it very nice!&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;strict&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;warnings&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@teddybear&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;    &lt;span class=&#34;symbol&#34;&gt;@rockinghorse&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;@jackinthebox&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@gijoe&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;@barbie&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;       &lt;span class=&#34;symbol&#34;&gt;@sallytalksalot&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;@teaset&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;       &lt;span class=&#34;symbol&#34;&gt;@dollhouse&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;get_child&lt;/span&gt;&lt;span class=&#34;prototype&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;words&#34;&gt;qw/al grant mary salve/&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;comment&#34;&gt;# e.g., ...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;get_child&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;m/^[a-fA-F]/&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;rand&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@teddybear&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@dollhouse&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;elsif&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;m/^[g-lG-L]/&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;rand&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@rockinghorse&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@teaset&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;elsif&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;m/^[m-rM-R]/&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;rand&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@jackinthebox&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@sallytalksalot&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;elsif&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;m/^[s-zS-Z]/&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;rand&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@gijoe&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@barbie&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After a brief pause, Santa thought that maybe he could organize this code into a more efficient and nicer to read dispatch table based on a &lt;code&gt;HASH&lt;/code&gt; structure. But alas! He could not figure out how to do it without actually having a key in place for each possible first name. There was also a lot of repeated code in the &lt;code&gt;CODE&lt;/code&gt; attached to each &lt;code&gt;HASH&lt;/code&gt; key.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;strict&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;warnings&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@teddybear&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;    &lt;span class=&#34;symbol&#34;&gt;@rockinghorse&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;@jackinthebox&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@gijoe&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;@barbie&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;       &lt;span class=&#34;symbol&#34;&gt;@sallytalksalot&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;@teaset&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;       &lt;span class=&#34;symbol&#34;&gt;@dollhouse&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;get_child&lt;/span&gt;&lt;span class=&#34;prototype&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;words&#34;&gt;qw/al grant mary salve/&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;comment&#34;&gt;# e.g., ...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;get_child&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$dispatch&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;al&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt;   &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;rand&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@teddybear&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;else&lt;/span&gt;                     &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@dollhouse&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;        # ...&lt;br /&gt;&lt;/span&gt;        &lt;span class=&#34;word&#34;&gt;grant&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt;   &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;rand&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@rockinghorse&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;else&lt;/span&gt;                     &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@teaset&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;       &lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;        # ...&lt;br /&gt;&lt;/span&gt;        &lt;span class=&#34;word&#34;&gt;mary&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt;   &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;rand&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@jackinthebox&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;   &lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;else&lt;/span&gt;                     &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@sallytalksalot&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;        # ...&lt;br /&gt;&lt;/span&gt;        &lt;span class=&#34;word&#34;&gt;salve&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt;   &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;rand&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@gijoe&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;  &lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;else&lt;/span&gt;                     &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@barbie&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;        # ...&lt;br /&gt;&lt;/span&gt;    &lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;    #  make sure key exists, if not warn and move on to next $CHILD&lt;br /&gt;&lt;/span&gt;    &lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;exists&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$dispatch&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;warn&lt;/span&gt; &lt;span class=&#34;interpolate&#34;&gt;qq{Child not found!\n}&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;next&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;    # call the CODE&lt;br /&gt;&lt;/span&gt;    &lt;span class=&#34;symbol&#34;&gt;$dispatch&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Santa was not happy with how this was going. He exclaimed in a panic, &lt;i&gt;HASH keys are static strings!&lt;/i&gt; After taking some time to collect his thoughts, he knew what to do.&lt;/p&gt;

&lt;p&gt;And that&#38;#39;s when Santa took to &lt;a href=&#34;https://metacpan.org&#34;&gt;https://metacpan.org&lt;/a&gt;, like always to search for a solution using the keyword, &lt;i&gt;dispatch&lt;/i&gt;. And he found a module that looked promising, &lt;a href=&#34;https://metacpan.org/module/Dispatch::Fu&#34;&gt;Dispatch::Fu&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This module promises that it &lt;i&gt;converts any complicated conditional dispatch situation into familiar static hash-key based dispatch&lt;/i&gt;. And that&#38;#39;s exactly what Santa needed.&lt;/p&gt;

&lt;p&gt;In a jiffy, he was able to whip out a solution that was really looking much nicer.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;strict&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;warnings&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Dispatch::Fu&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@teddybear&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;    &lt;span class=&#34;symbol&#34;&gt;@rockinghorse&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;@jackinthebox&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@gijoe&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;@barbie&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;       &lt;span class=&#34;symbol&#34;&gt;@sallytalksalot&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;@teaset&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;       &lt;span class=&#34;symbol&#34;&gt;@dollhouse&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;get_child&lt;/span&gt;&lt;span class=&#34;prototype&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;words&#34;&gt;qw/al grant mary salve/&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;comment&#34;&gt;# e.g., ...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;get_child&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;dispatch&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$_CHILD&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;literal&#34;&gt;q{A_F}&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;m/^[a-fA-F]/&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;literal&#34;&gt;q{G_L}&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;m/^[g-lG-L]/&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;literal&#34;&gt;q{M_R}&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;m/^[m-rM-R]/&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;literal&#34;&gt;q{S_Z}&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;m/^[s-zS-Z]/&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;on&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;A_F&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;rand&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;on&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;G_L&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;rand&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;on&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;M_R&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;rand&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;on&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;S_Z&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;rand&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}};&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;One last thing had to be addressed - add the coin flip as another case represented by a hash key. Once done, Santa was very pleased to present the following code to his main code reviewer and QA, Mrs. Clause.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;strict&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;warnings&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Dispatch::Fu&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@teddybear&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;    &lt;span class=&#34;symbol&#34;&gt;@rockinghorse&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;@jackinthebox&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@gijoe&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;@barbie&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;       &lt;span class=&#34;symbol&#34;&gt;@sallytalksalot&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;@teaset&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;       &lt;span class=&#34;symbol&#34;&gt;@dollhouse&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;get_child&lt;/span&gt;&lt;span class=&#34;prototype&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;words&#34;&gt;qw/al grant mary salve/&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;comment&#34;&gt;# e.g., ...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;get_child&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;dispatch&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$_CHILD&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$coinflip&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;rand&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;literal&#34;&gt;q{A_F_0}&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$_CHILD&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;m/^[a-fA-F]/&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$coinflip&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;literal&#34;&gt;q{A_F_1}&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$_CHILD&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;m/^[a-fA-F]/&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$coinflip&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;literal&#34;&gt;q{G_L_0}&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$_CHILD&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;m/^[g-lG-L]/&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$coinflip&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;literal&#34;&gt;q{G_L_1}&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$_CHILD&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;m/^[g-lG-L]/&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$coinflip&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;literal&#34;&gt;q{M_R_0}&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$_CHILD&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;m/^[m-rM-R]/&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$coinflip&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;literal&#34;&gt;q{M_R_1}&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$_CHILD&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;m/^[m-rM-R]/&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$coinflip&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;literal&#34;&gt;q{S_Z_0}&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$_CHILD&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;m/^[s-zS-Z]/&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$coinflip&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;literal&#34;&gt;q{S_Z_1}&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$_CHILD&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;m/^[s-zS-Z]/&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$coinflip&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$CHILD&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;on&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;A_F_0&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@teddybear&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;      &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;on&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;A_F_1&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@dollhouse&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;      &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;on&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;G_L_0&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@rockinghorse&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;   &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;on&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;G_L_1&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@teaset&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;         &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;on&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;M_R_0&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@jackinthebox&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;   &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;on&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;M_R_1&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@sallytalksalot&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;on&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;S_Z_0&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@gijoe&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;          &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;on&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;S_Z_1&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@barbie&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;         &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Santa also knew that even if Mrs. Clause didn&#38;#39;t like the way he used a bunch of inline &lt;code&gt;return&lt;/code&gt;s and repeated some regular expressions, he was more than content knowing the tried and true, &lt;i&gt;pull requests accepted!&lt;/i&gt; applied here for her as much as it did for anyone else!&lt;/p&gt;

&lt;p&gt;See More:&lt;/p&gt;

&lt;dl&gt;

&lt;dt&gt;&lt;a href=&#34;https://metacpan.org/pod/Dispatch::Fu&#34;&gt;https://metacpan.org/pod/Dispatch::Fu&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;

&lt;/dd&gt;
&lt;dt&gt;&lt;a href=&#34;https://blogs.perl.org/users/oodler_577/2023/09/cgitiny-dispatchfu---nearly-a-perfect-match.html&#34;&gt;https://blogs.perl.org/users/oodler_577/2023/09/cgitiny-dispatchfu---nearly-a-perfect-match.html&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;

&lt;/dd&gt;
&lt;/dl&gt;

&lt;/div&gt;</summary><updated>2023-12-13T00:00:00Z</updated><category term="Perl"/><author><name>oodler</name></author></entry><entry><title>My Top 7 Perl New Features</title><link href="https://perladvent.org/2023/2023-12-12.html"/><id>https://perladvent.org/2023/2023-12-12.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;For each version of Perl, I update my book &lt;a href=&#34;https://leanpub.com/perl_new_features&#34;&gt;Perl New Features&lt;/a&gt;. Perl v5.10 has a big change in perl development where we started to get new syntax instead of making old syntax adapt to the new world (like making things Unicode).&lt;/p&gt;

&lt;p&gt;There are so many features that I could choose from, but I looked back at those I&#38;#39;ve been using for the past year, and which ones I&#38;#39;d fight for in a code review. These aren&#38;#39;t the most clever or groundbreaking features, but they are the ones that I&#38;#39;m consistently using.&lt;/p&gt;

&lt;h3 id=&#34;Subroutine-signatures&#34;&gt;0. Subroutine signatures&lt;/h3&gt;

&lt;p&gt;Perl v5.20 added &lt;a href=&#34;https://www.effectiveperlprogramming.com/2015/04/use-v5-20-subroutine-signatures/&#34;&gt;experimental signature support&lt;/a&gt;, and v5.36 moves these out of experimental status:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;version&#34;&gt;v5.36&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;do_it&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$name&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$cost&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$age&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$limit&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It seems like a slight change, but moving the names for the arguments outside of the braces makes everything much tidier:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;version&#34;&gt;v5.36&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;do_it&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$name&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$cost&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$age&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$limit&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Some of these can have default values (all required values must come first):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;version&#34;&gt;v5.36&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;do_it&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$name&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$cost&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$where&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$limit&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;5&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;do_it&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;brian&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;NYC&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;comment&#34;&gt;# limit is the default&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And, Perl v5.38 lets me use the defined-or to set default values when I use &lt;code&gt;undef&lt;/code&gt; for a placeholder:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;version&#34;&gt;v5.38&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;do_it&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$name&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$cost&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$where&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;//=&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;NYC&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$limit&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;5&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;do_it&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;brian&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;NYC&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;comment&#34;&gt;# limit is the default&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;do_it&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;brian&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;undef&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;comment&#34;&gt;# where is the default&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Eventually, signatures will turn off &lt;code&gt;@_&lt;/code&gt; inside the braces, which has been annoying, but if that&#38;#39;s the trade-off for signatures, so be it.&lt;/p&gt;

&lt;h3 id=&#34;Substitution-returns-a-copy&#34;&gt;1. Substitution returns a copy.&lt;/h3&gt;

&lt;p&gt;Perl v5.14 added the &lt;a href=&#34;https://www.effectiveperlprogramming.com/2010/09/use-the-r-substitution-flag-to-work-on-a-copy/&#34;&gt;the r flag for the substitution operator&lt;/a&gt;. When I use that, the bound string is unmodified but I get the modified version with the replacement:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$modified&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$original&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;substitute&#34;&gt;s/PATTERN/REPLACEMENT/r&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is especially handy in a &lt;code&gt;map&lt;/code&gt;, where I have often made the mistake of transforming &lt;code&gt;@original&lt;/code&gt; into a list of &lt;code&gt;1&lt;/code&gt;s or empty strings:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@modified&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;map&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;substitute&#34;&gt;s/PATTERN/REPLACEMENT/r&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@original&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;Postfix-dereference&#34;&gt;2. Postfix dereference&lt;/h3&gt;

&lt;p&gt;Perl&#38;#39;s generalized dereferencing is a circumfix operator, which is a fancy way of saying that I have to type on both sides of the reference:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;comment&#34;&gt;	# @{ REFERENCE }&lt;br /&gt;&#38;nbsp;# @{ $hash{$key} }&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$item&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$hash&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$key&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Perl v5.20 added the &lt;a href=&#34;https://www.effectiveperlprogramming.com/2014/09/use-postfix-dereferencing/&#34;&gt;postfix dereference feature&lt;/a&gt;, and Perl v5.24 stabilized it:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;version&#34;&gt;v5.24&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$item&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$hash&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$key&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;cast&#34;&gt;@*&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;The-infix-isa&#34;&gt;3. The infix isa&lt;/h3&gt;

&lt;p&gt;Checking that a Perl object was of a particular class, or a subclass or that, was a pain. There&#38;#39;s &lt;code&gt;isa&lt;/code&gt; from &lt;a href=&#34;https://metacpan.org/module/UNIVERSAL&#34;&gt;UNIVERSAL&lt;/a&gt;, but that only works if you have an object. I do this quite a bit in testing Perl code, and since it might blow up, I have to wrap that in an &lt;code&gt;eval&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;eval&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$obj&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$target_class&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Perl v5.32 introduced the &lt;a href=&#34;https://www.effectiveperlprogramming.com/2020/01/use-the-infix-class-instance-operator/&#34;&gt;infix version of isa&lt;/a&gt; that can return false if the left-hand side is not an object. This is much more pleasing:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$obj&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$target_class&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Someday we might get infix operators for &lt;code&gt;can&lt;/code&gt; and &lt;code&gt;does&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&#34;Key-value-slices&#34;&gt;4. Key-value slices&lt;/h3&gt;

&lt;p&gt;I&#38;#39;m a big fan of slices, but for a long time (since forever), Perl didn&#38;#39;t have a way to slice a hash and get a hash back. For example, I want a sub-hash that I can use a &lt;code&gt;map&lt;/code&gt;. I&#38;#39;ve typed out something like this so often I don&#38;#39;t even feel the pain anymore:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%slice&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;map&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$hash&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@wanted_keys&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Perl v5.20 introduced &lt;a href=&#34;https://www.effectiveperlprogramming.com/2014/07/perl-5-20-introduces-keyvalue-slices/&#34;&gt;&#38;quot;key-value&#38;quot; slices&lt;/a&gt;. I know it&#38;#39;s a key-value slice because I see the &lt;code&gt;%&lt;/code&gt; in front of &lt;code&gt;hash&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;version&#34;&gt;v5.20&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%key_value_slice&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%hash&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@wanted_keys&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A hash slice with &lt;code&gt;@&lt;/code&gt; gives you back only the values:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@value_slice&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@hash&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@wanted_keys&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the last year I&#38;#39;m been particularly keen to clean up areas where I&#38;#39;m passing around too much data. Instead of using a &#38;quot;god&#38;quot; hash with lots of irrelevant keys, I extract just the parts I need so that nothing gets more than it should be allowed to use:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;version&#34;&gt;v5.20&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%sub_hash&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%hash&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@wanted_keys&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;some_function&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;%sub_hash&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If I&#38;#39;m really concerned about something changing something they shouldn&#38;#39;t, I might make a deep copy:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;version&#34;&gt;v5.20&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Storable&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%sub_hash&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%hash&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@wanted_keys&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$clone&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Storable::dclone&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;%sub_hash&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;some_function&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$sub_hash&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;Initialize-hashes-and-arrays-with-state&#34;&gt;5. Initialize hashes and arrays with state&lt;/h3&gt;

&lt;p&gt;I absolutely love &lt;code&gt;state&lt;/code&gt; and I try to put everything that matters to a subroutine inside its lexical scope. This makes it easy to move the entire subroutine and everything it needs to another place in the file, or even another file.&lt;/p&gt;

&lt;p&gt;And, while I&#38;#39;m very comfortable with references, if I can leave out all the dereferencing arrows, &lt;code&gt;-&#38;gt;&lt;/code&gt;, I will. When Perl v5.10 added &lt;code&gt;state&lt;/code&gt;, it could only initialize scalars. This wasn&#38;#39;t a big deal with anonymous arrays, it feels clunky with a hash because I often want to construct the hash to check existence of some allowed value:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;do_it&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$scalar&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;137&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$array&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;];&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$hash&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;map&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;7&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;exists&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$hash&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$args&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With v5.28, I can &lt;a href=&#34;https://www.effectiveperlprogramming.com/2018/08/initialize-array-and-hash-variables-with-state/&#34;&gt;initialize array and hash variables in state&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;do_it&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$scalar&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;137&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@array&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw( 1, 3, 7 )&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%hash&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;map&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;7&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;exists&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$hash&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$args&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;comment&#34;&gt;# leave off the -&#38;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;Indented-here-docs&#34;&gt;6. Indented here docs&lt;/h3&gt;

&lt;p&gt;I love heredocs for multi-line strings, and up to Perl v5.26 you either had to start each line at the left margin, or do clunky post-processing to remove leading whitespace:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$string&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;heredoc&#34;&gt;&#38;lt;&#38;lt;&#39;HERE&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;heredoc_content&#34;&gt;This string is flush left!&lt;br /&gt;Here&#39;s another line!&lt;br /&gt;This is insane!&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;heredoc_terminator&#34;&gt;HERE&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With Perl v5.26, Perl can strip leading whitespace for you, up to the whitespace ahead of the closing delimiter (&lt;code&gt;HERE&lt;/code&gt; in this example). Now my heredocs don&#38;#39;t have to screw up my indention:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$string&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;heredoc&#34;&gt;&#38;lt;&#38;lt;~&#39;HERE&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;heredoc_content&#34;&gt;        This string is outdented!&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;Here&#39;s another line!&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;This is nicer!&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;heredoc_terminator&#34;&gt;        HERE&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;Further-reading&#34;&gt;Further reading&lt;/h3&gt;

&lt;p&gt;You can read more about new features for free on &lt;a href=&#34;https://www.effectiveperlprogramming.com/&#34;&gt;The Effective Perler&lt;/a&gt;, or you can support my writing by buying the ePub or PDF version of &lt;a href=&#34;https://leanpub.com/perl_new_features&#34;&gt;Perl New Features&lt;/a&gt; at LeanPub.&lt;/p&gt;

&lt;/div&gt;</summary><updated>2023-12-12T00:00:00Z</updated><category term="Perl"/><author><name>brian d foy</name></author></entry><entry><title type="html">Santa&#38;#39;s Helpers&#38;#39; Helpers</title><link href="https://perladvent.org/2023/2023-12-11.html"/><id>https://perladvent.org/2023/2023-12-11.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;In past years, Santa really was that jolly old soul everyone talks about, but for the last several months, the old boy has been roaring at his staff in frustration.&lt;/p&gt;

&lt;p&gt;&#38;quot;Eight &lt;b&gt;billion&lt;/b&gt; souls on earth now! How am I to keep my lists? The old ways just aren&#38;#39;t working any more! I can&#38;#39;t tell who&#38;#39;s been naughty, and who&#38;#39;s been nice!&#38;quot;&lt;/p&gt;

&lt;p&gt;Midyear, he finally called a meeting of the entire North Pole team, elves and reindeer both. Mrs. Claus baked up a massive batch of cookies, and called the meeting to order. &#38;quot;Now, listen up, all of you! As you know, Santa has been in quite a state this year. The population of Earth hit 8 billion last November, and all those babies born since are automatically on the good list for their first year. But keeping up with the older children and adults has gotten to be quite the burden. He&#38;#39;s driving me crazy, stomping around the house with those long lists dragging around behind him. So everyone, put your thinking caps on. We need innovation, now!&#38;quot;&lt;/p&gt;

&lt;p&gt;The North Pole&#38;#39;s CEO stood up, shuffled some papers on the lectern in front of him, and said, &#38;quot;folks, I owe you all an apology. I&#38;#39;ve been a grumpy old jerk all year, with my job overwhelming me at last. Mrs. Claus and I have spent some time talking, and she&#38;#39;s convinced me to ask you all for your help. We need a better way to keep up with the lists of naughty and nice children and adults on earth. Don&#38;#39;t worry about what it&#38;#39;ll cost, I&#38;#39;ll take care of that. But it needs to be fast, flexible, and easy for us to keep up with. If there are some bits of it that we can automate, so much the better. Does anyone have an idea we can use?&#38;quot;&lt;/p&gt;

&lt;p&gt;About halfway to the back sat an elf named Otto, wearing thick glasses, and a pocket protector. He was a builder of the geeky electronic toys that had become so popular in the last thirty or forty years. He raised his hand, and when Santa called on him, he said, &#38;quot;Sir, if we can get a big enough computer, we could put all of them in a database. Some of us could write a program to help you manage it on your web browser.&#38;quot;&lt;/p&gt;

&lt;p&gt;&#38;quot;Elf Otto, that&#38;#39;s a fine idea! Come up here and let&#38;#39;s work on that. Anyone else knowledgeable in these things, please come down front to help. The rest of you, get cracking on those toy orders!&#38;quot;&lt;/p&gt;

&lt;p&gt;The new North Pole Application Group, as they dubbed themselves, quickly decided to build Santa&#38;#39;s new database manager with Perl, using &lt;a href=&#34;https://metacpan.org/module/Dancer2&#34;&gt;Dancer2&lt;/a&gt;, &lt;a href=&#34;https://metacpan.org/module/DBIx::Class&#34;&gt;DBIx::Class&lt;/a&gt;, and PostgreSQL, finding them quick and easy to use, and scalable to the size that the boss-man needed. A couple of clever elves worked with Santa to find a place to host their new application, another small group started working on the UI, a couple of grumpy older elves took up the job of testing, and Otto found himself leading a team to design the database schema, and give the UI team the tools they needed to access it.&lt;/p&gt;

&lt;p&gt;&#38;quot;DBIx::Class is massive! By itself, it can do everything we need!&#38;quot; one member of the team exclaimed, after reading just some of the documentation.&lt;/p&gt;

&lt;p&gt;&#38;quot;Yes, sure, it can,&#38;quot; Otto told him, &#38;quot;but some of it is pretty darn arcane. We need helpers.&#38;quot;&lt;/p&gt;

&lt;p&gt;The room erupted. &#38;quot;But *we* are Santa&#38;#39;s helpers!&#38;quot; one shouted.&lt;/p&gt;

&lt;p&gt;&#38;quot;Fine, fine, yes, we are,&#38;quot; Otto said, after calming the team. &#38;quot;But sometimes helpers need helpers. This is a big, big tool we&#38;#39;re building, and we want the UI and testing teams to be able to use our part of it very easily, with code they can read and understand and maintain in the future. The database is the core of the application, so it&#38;#39;s gotta be easy to work with. Call these Santa&#38;#39;s-Helpers-Helpers if you want. But DBIx::Class has a lot of helpers available on CPAN. Let&#38;#39;s look for a few that can make things easier to work with for the other teams.&#38;quot;&lt;/p&gt;

&lt;p&gt;And so they did. Here are a few that they found:&lt;/p&gt;

&lt;dl&gt;

&lt;dt&gt;&lt;a href=&#34;https://metacpan.org/module/Test::DBIx::Class&#34;&gt;Test::DBIx::Class&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;

&lt;p&gt;The grumpy testing elves found this module very useful; it let them set up and run unit and integration tests in a known-clean environment. They designed the test fixtures and wrote tests to make sure every function behaved as it was supposed to.&lt;/p&gt;

&lt;/dd&gt;
&lt;dt&gt;&lt;a href=&#34;https://metacpan.org/module/Dancer2::Plugin::DBIx::Class&#34;&gt;Dancer2::Plugin::DBIx::Class&lt;/a&gt; and &lt;a href=&#34;https://metacpan.org/module/DBIx::Class::ResultSetNames&#34;&gt;DBIx::Class::ResultSetNames&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;

&lt;p&gt;These two modules gave the elves easy access to all the tables of the database. Instead of typing long references to the name of the table to start a search, they just start it with the name of the table. Searches are quick and semantically friendly:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;symbol&#34;&gt;$schema&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;resultset&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;Person&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;search&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;({&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;});&lt;/span&gt;   &lt;span class=&#34;comment&#34;&gt;# no need for this...&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;db_person&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;search&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;({&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;})&lt;/span&gt;                         &lt;span class=&#34;comment&#34;&gt;# when you can do this.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/dd&gt;
&lt;dt&gt;&lt;a href=&#34;https://metacpan.org/module/DBIx::Class::TemporalRelations&#34;&gt;DBIx::Class::TemporalRelations&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;

&lt;p&gt;Elf Wayne used this module to write a daily cron job for the application that would update the children older than one year, so Santa could start watching their naughty/nice ratio. The heart of it lay in a single line of code:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;word&#34;&gt;db_person&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;born_before&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$dt_1_year_ago&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;update&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;({&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;auto_nice&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/dd&gt;
&lt;dt&gt;&lt;a href=&#34;https://metacpan.org/module/DBIx::Class::Helpers&#34;&gt;DBIx::Class::Helpers&lt;/a&gt; and &lt;a href=&#34;https://metacpan.org/module/DBIx::Class::MoreHelpers&#34;&gt;DBIx::Class::MoreHelpers&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;

&lt;p&gt;The elves found all sorts of useful search shortcuts in these two modules, like &lt;code&gt;rows()&lt;/code&gt; to limit the number of rows in a search for paging, and &lt;code&gt;group_by()&lt;/code&gt; and &lt;code&gt;order_by()&lt;/code&gt; which were handy for Santa&#38;#39;s reports. &lt;code&gt;is()&lt;/code&gt;, &lt;code&gt;is_not()&lt;/code&gt;, and &lt;code&gt;is_any()&lt;/code&gt; came in very handy for boolean fields, too.&lt;/p&gt;

&lt;/dd&gt;
&lt;dt&gt;&lt;a href=&#34;https://metacpan.org/module/DBIx::Class::Numeric&#34;&gt;DBIx::Class::Numeric&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;

&lt;p&gt;Elf Cynthia squealed with joy when she found this module on CPAN. She was working on the part of the application that would tally up the naughty and nice things that people do during the year. She discovered that once she declared a database field as numeric, she got baked-in methods to increment and decrement counters, increase or decrease counts, and even set boundary limits on them.&lt;/p&gt;

&lt;/dd&gt;
&lt;/dl&gt;

&lt;p&gt;Not too much later, Santa&#38;#39;s helpers launched V1.0 of eSanta, the application for the North Pole to keep track of Santa&#38;#39;s naughty and nice lists. Santa smiled happily as he watched data being entered from his lists automatically. Mrs. Claus was thrilled, too, as Santa would be less grumpy and have more time to spend with her.&lt;/p&gt;

&lt;p&gt;In the small workshop the eSanta team had set up with nice laptops, a ping-pong table, and whiteboards covering the walls, work on V2.0 is already well underway. That version will include new features to help Santa in his fall field-work sessions, when he goes to malls and stores and parades and talks to the children about what they want for Christmas. It includes a module for the North Pole Post Office to enter data from Santa&#38;#39;s letters, too, though the now-jolly fellow insists that he must still read each and every one. As the data is entered, it&#38;#39;ll be piped down to Santa&#38;#39;s workshops so that the elves could build the toys to fulfil those orders, and have the bundles of toys ready for Santa&#38;#39;s whirlwind delivery on December 25th!&lt;/p&gt;

&lt;/div&gt;</summary><updated>2023-12-11T00:00:00Z</updated><category term="Perl"/><author><name>D Ruth Holloway</name></author></entry><entry><title>Introduction to App::Timer</title><link href="https://perladvent.org/2023/2023-12-10.html"/><id>https://perladvent.org/2023/2023-12-10.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h3 id=&#34;Background&#34;&gt;Background&lt;/h3&gt;

&lt;p&gt;So what is it that I am going to talk about today?&lt;/p&gt;

&lt;p&gt;As you all know I have &lt;a href=&#34;https://metacpan.org/author/MANWAR&#34;&gt;handful of distributions&lt;/a&gt; available on &lt;code&gt;MetaCPAN&lt;/code&gt;. Although I am not actively managing any of them but I do look after them as and when needed.&lt;/p&gt;

&lt;p&gt;If you look at the list of my distributions, you would notice that some of them are just plain application i.e. something that can be executed at the command prompt. One of them, e.g. &lt;a href=&#34;https://metacpan.org/module/App::calendr&#34;&gt;App::calendr&lt;/a&gt;. Every time, I run an application, I always wanted to know how long it took to complete the execution.&lt;/p&gt;

&lt;p&gt;For many years, I used to add the following snippets at the end of my command line application script.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;END&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$time&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;time&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$^T&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$mm&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$time&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;60&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ss&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$time&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;60&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$hh&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$mm&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;60&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;The program ran for %02d:%02d:%02d.\n&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$hh&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$mm&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;60&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ss&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;Proposals&#34;&gt;Proposals&lt;/h3&gt;

&lt;p&gt;Can I do something that works for every command line applications?&lt;/p&gt;

&lt;p&gt;Well, I gave a deep thought one weekend and ended up quick and dirty solution, &lt;a href=&#34;https://metacpan.org/module/App::Timer&#34;&gt;App::Timer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To be honest, there is no &lt;code&gt;Rocket Science&lt;/code&gt; behind it. However it is very handy and help me with all my command line applications.&lt;/p&gt;

&lt;p&gt;There are &lt;code&gt;2 ways&lt;/code&gt; you can have the timer added to your application.&lt;/p&gt;

&lt;h4 id=&#34;Import-the-module&#34;&gt;Import the module&lt;/h4&gt;

&lt;p&gt;You can simply add one line &lt;code&gt;use App::Timer&lt;/code&gt; at the top and you are done.&lt;/p&gt;

&lt;h4 id=&#34;Command-line-switch&#34;&gt;Command line switch&lt;/h4&gt;

&lt;p&gt;Not always you want to touch the application source code, so you can use the command line switch instead as below:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    $ perl -MApp::Timer your-application.pl&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;Perl&lt;/code&gt; being the &lt;code&gt;Perl&lt;/code&gt;, you can get away not doing any of the above and simply do this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    $ time perl your-application.pl&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you use &lt;a href=&#34;https://metacpan.org/module/App::Timer&#34;&gt;App::Timer&lt;/a&gt;, you can expect the command line output to look something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    $ perl -MApp::Timer -E &#38;#39;sleep 1&#38;#39;
    The program ran for 00:00:01.&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&#38;#39;s it for today, have an enjoyable holiday break.&lt;/p&gt;

&lt;/div&gt;</summary><updated>2023-12-10T00:00:00Z</updated><category term="Perl"/><author><name>Mohammad Anwar</name></author></entry><entry><title>Mooish Attribute Shortcuts For Everyone!</title><link href="https://perladvent.org/2023/2023-12-09.html"/><id>https://perladvent.org/2023/2023-12-09.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;Most of us surely know &lt;a href=&#34;https://metacpan.org/module/Moose&#34;&gt;Moose&lt;/a&gt;. It is a solid piece of Perl software powering a lot of modern Perl code. It allows for very expressive definition of object attributes. This expresiveness comes at a cost, nicely explained by Curtis &#38;quot;Ovid&#38;quot; Poe &lt;a href=&#34;https://ovid.github.io/articles/introducing-moosexextended-for-perl.html#param-and-field&#34;&gt;in his blog post&lt;/a&gt;. In short: it is not immediately obvious what is the purpose of an attribute and you have to look at the option list to get the idea. In addition to that, the attributes become very verbose if you want to nail their behavior exactly right.&lt;/p&gt;

&lt;p&gt;To solve this, you just install &lt;a href=&#34;https://metacpan.org/module/MooseX::Extended&#34;&gt;MooseX::Extended&lt;/a&gt; and enjoy new &lt;code&gt;param&lt;/code&gt; and &lt;code&gt;field&lt;/code&gt;, right? Sort of... The module does a lot of things, has a lot of dependencies and only works with Moose. If you often use &lt;a href=&#34;https://metacpan.org/module/Moo&#34;&gt;Moo&lt;/a&gt; instead of Moose, you will have to find a Moo-specific module for this, and the API will likely be different.&lt;/p&gt;

&lt;p&gt;This is the exact issue solved by &lt;a href=&#34;https://metacpan.org/module/Mooish::AttributeBuilder&#34;&gt;Mooish::AttributeBuilder&lt;/a&gt;. It is a zero-dependency, module-agnostic helper for Moose family of modules letting you build your attributes more easily and give them meaning. It&#38;#39;s not by any means a replacement of MooseX::Extended. On the contrary - it focuses on a very narrow scope of features and strives to deliver them for every Moose-compatible module on CPAN.&lt;/p&gt;

&lt;p&gt;Let&#38;#39;s look at a small example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Christmas::Tree&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;version&#34;&gt;v5.38&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Moose&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Mooish::AttributeBuilder&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Types::Common&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;-types&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;param&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;height&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;PositiveInt&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;field&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ornaments&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;ArrayRef&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;Str&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;predicate&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;lazy&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The above code will have the same effect as the following vanilla Moose code:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Christmas::Tree&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;version&#34;&gt;v5.38&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Moose&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Types::Common&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;-types&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;height&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ro&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;PositiveInt&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;required&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ornaments&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ro&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;ArrayRef&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;Str&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;predicate&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;has_ornaments&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;lazy&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;init_arg&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;undef&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After importing the module you automatically get four new keywords: &lt;code&gt;param&lt;/code&gt;, &lt;code&gt;option&lt;/code&gt;, &lt;code&gt;field&lt;/code&gt; and &lt;code&gt;extended&lt;/code&gt;. &lt;code&gt;param&lt;/code&gt; and &lt;code&gt;option&lt;/code&gt; attributes will be available in the constructor, the first one being required and the second one optional (with a handy predicate). &lt;code&gt;field&lt;/code&gt; attributes are not assignable in the constructor and force no other behavior. &lt;code&gt;extended&lt;/code&gt; is used for extending parent attributes. No matter which you use, you always get &lt;code&gt;is =&#38;gt; &#38;#39;ro&#38;#39;&lt;/code&gt; for free.&lt;/p&gt;

&lt;p&gt;Each keyword is used in conjunction with &lt;code&gt;has&lt;/code&gt;. You put the keyword between &lt;code&gt;has&lt;/code&gt; and the options, and the option list will be altered to contain the target values. There is no magic of replacing &lt;code&gt;has&lt;/code&gt; for each and every module, which makes it very transparent.&lt;/p&gt;

&lt;p&gt;The module is made to work with any module compatible with core Moose. The option lists it produces should therefore be valid for Moose, Moo, Mouse, Mo, Mite and possibly others.&lt;/p&gt;

&lt;p&gt;In addition to controlling the constructor behavior, it contains some shortcuts which may come in handy. We&#38;#39;ve already seen how &lt;code&gt;lazy =&#38;gt; sub { [] }&lt;/code&gt; became &lt;code&gt;lazy =&#38;gt; 1, default =&#38;gt; sub { [] }&lt;/code&gt;. It can also reduce boilerplate with &lt;code&gt;isa + coerce&lt;/code&gt; combination, letting you write &lt;code&gt;coerce =&#38;gt; Type&lt;/code&gt;, and allow for previously incorrect &lt;code&gt;trigger =&#38;gt; &#38;#39;method_name&#38;#39;&lt;/code&gt;. In addition, &lt;code&gt;predicate =&#38;gt; 1&lt;/code&gt; became &lt;code&gt;predicate =&#38;gt; &#38;#39;has_ornaments&#38;#39;&lt;/code&gt;, which is a common shortcut delivered by &lt;a href=&#34;https://metacpan.org/module/MooseX::AttributeShortcuts&#34;&gt;MooseX::AttributeShortcuts&lt;/a&gt; (for Moose). If you used &lt;code&gt;-hidden&lt;/code&gt; instead of &lt;code&gt;1&lt;/code&gt;, the generated name would be &lt;code&gt;&#38;#39;_has_ornaments&#38;#39;&lt;/code&gt;. Specifying &lt;code&gt;1&lt;/code&gt; uses the same visibility setting as the attribute, so if the attribute name was &lt;code&gt;&#38;#39;_ornaments&#38;#39;&lt;/code&gt; then the method name would be &lt;code&gt;&#38;#39;_has_ornaments&#38;#39;&lt;/code&gt; without the need for &lt;code&gt;-hidden&lt;/code&gt;. Forcing public visibility on hidden attributes is achieved with &lt;code&gt;-public&lt;/code&gt;. The module tries pretty hard to do what you mean, but it tries equally hard not to do more than that. The full list of shortcuts is available in &lt;a href=&#34;https://metacpan.org/module/Mooish::AttributeBuilder#SHORTCUTS&#34;&gt;&#38;quot;SHORTCUTS&#38;quot; in Mooish::AttributeBuilder&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here are additional examples showcasing the behavior:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;comment&#34;&gt;# this:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;field&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;_presents&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;coerce&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;PresentType&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;lazy&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;clearer&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;-public&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# becomes:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;_presents&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ro&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;PresentType&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;coerce&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;builder&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;_build_presents&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;lazy&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;clearer&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;clear_presents&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;init_arg&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;undef&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# this:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;option&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;favourite_color&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Str&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;trigger&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# becomes:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;favourite_color&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ro&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;isa&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Str&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;trigger&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;shift&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;_trigger_favourite_color&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;predicate&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;has_favourite_color&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;required&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# and this:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;extended&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;parent_attribute&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;writer&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;-hidden&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# becomes:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;+parent_attribute&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;writer&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;_set_parent_attribute&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The module delivers some additional features, the main one being custom shortcuts, but the core functionality alone should immensely improve the code quality. You immediately know what&#38;#39;s what, and you will never overlook that pesky &lt;code&gt;init_arg =&#38;gt; undef&lt;/code&gt; again, no matter which Moose you use! So what do you say, worth giving a try?&lt;/p&gt;

&lt;p&gt;Happy Holidays!&lt;/p&gt;

&lt;/div&gt;</summary><updated>2023-12-09T00:00:00Z</updated><category term="Perl"/><author><name>Bartosz Jarzyna</name></author></entry><entry><title type="html">Who&#38;#39;s That Clicking At The Window?</title><link href="https://perladvent.org/2023/2023-12-08.html"/><id>https://perladvent.org/2023/2023-12-08.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;Life at the Grotto has finally joined the modern age. Santa has got a new Laptop. The clacketty clack of his previous rather large steam powered workstation, a keyboard and a green phosphor terminal, replaced by a sleek portable device that could easily be carried on the sleigh. But some of the elves were mystified.&lt;/p&gt;

&lt;p&gt;&#38;quot;Errr, what can you do with it?&#38;quot; asked Shinny Upatree, the aging elf.&lt;/p&gt;

&lt;p&gt;&#38;quot;Look, &#38;quot; said Sugarplum eagerly,&#38;quot;Its looks so pretty, and you can move this arrow everywhere!&#38;quot;,&lt;/p&gt;

&lt;p&gt;Shinny was not convinced.&lt;/p&gt;

&lt;p&gt;&#38;quot;I can even search for cute cat pictures&#38;quot;,&lt;/p&gt;

&lt;p&gt;Shinny knew all about gimmicks, &#38;quot;So what can you do that we NEED to do?&#38;quot;,&lt;/p&gt;

&lt;p&gt;&#38;quot;You can open up a terminal, and all our old software will work like before, I can even make the characters green&#38;quot;, said Sugarplum desperately trying to make a case for new technology, &#38;quot;You can even use Notepad to write stuff&#38;quot;&lt;/p&gt;

&lt;p&gt;Santa was passing by in a hurry, and overheard the conversation. &#38;quot;Of course, I have not got this new device just to still do things the old ways&#38;quot; he said, &#38;quot;I want a GUI&#38;quot;, as he rushed by on his high performance electric scooter.&lt;/p&gt;

&lt;p&gt;&#38;quot;Is that as messy as it sounds?&#38;quot; asked Shinny.&lt;/p&gt;

&lt;p&gt;&#38;quot;Yes,&#38;quot; groaned Sugarplum, &#38;quot;There are many GUI frameworks, it takes time to learn, and unlike terminal applications we are used to, a GUI application compiled for Santa&#38;#39;s PC may not work on your Linux machines without significant effort.&#38;quot;&lt;/p&gt;

&lt;p&gt;&#38;quot;Alabaster Elf would know, but he is on leave!&#38;quot;,&lt;/p&gt;

&lt;p&gt;&#38;quot;Creating windows, positioning buttons, text entry widgets, drop down boxes, making menus, calling up dialog boxes, file selectors, callbacks,...oh how are we going to manage?&#38;quot;&lt;/p&gt;

&lt;p&gt;Sugarplum had her head in her hands as Santa whizzed back again. &#38;quot;You can use Notepad?&#38;quot;&lt;/p&gt;

&lt;p&gt;&#38;quot;That&#38;#39;s about all I can do,&#38;quot; she sniffled, &#38;quot;and Shinny can use vim on a terminal.&#38;quot;,&lt;/p&gt;

&lt;p&gt;&#38;quot;Then try &lt;a href=&#34;https://metacpan.org/module/GUIDeFATE&#34;&gt;GUIDeFATE&lt;/a&gt;&#38;quot;, said Santa, &#38;quot;It stands for GUI Design From A Text Editor&#38;quot;,&lt;/p&gt;

&lt;p&gt;&#38;quot;Using &lt;a href=&#34;https://metacpan.org/module/GUIDeFATE&#34;&gt;GUIDeFATE&lt;/a&gt;, you simply draw the window and the widgets using ASCII characters in monospace fonts,&#38;quot; he continued, &#38;quot;with a few easy-to-learn patterns to define widgets.&#38;quot;&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;Ordinary text are &#38;quot;Static Text&#38;quot; items in the window&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Buttons are enclosed in curly braces e.g. &lt;code&gt;{Submit}&lt;/code&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Inputs are in square braces e.g.&lt;code&gt;[Default value]&lt;/code&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Drop down boxes are in carets (not carrots) e.g.&lt;code&gt;^ListName^&lt;/code&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Images and Text Panels at drawn boxes with &#38;quot;I&#38;quot; ar or &#38;quot;T&#38;quot; in the top line&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Half an hour later, after installing Tk and force installing GUIDeFATE Sugarplum Mary had already the following code:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;comment&#34;&gt;#!/usr/bin/env perl&lt;br /&gt;# A database for Santa&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;strict&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;warnings&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;GUIDeFATE&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$window&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;heredoc&#34;&gt;&#38;lt;&#38;lt;END&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;heredoc_content&#34;&gt;+-------------------------------------------+&lt;br /&gt;|T The Everybody Database                   |&lt;br /&gt;+M------------------------------------------+&lt;br /&gt;|  Making A List, Checking it twice         |&lt;br /&gt;|  Gonna find out Who&#39;s naughty and nice    |&lt;br /&gt;|                                           |&lt;br /&gt;|  {&#38;lt;} Person Index {&#38;gt;}  [Name         ]{?} |&lt;br /&gt;|  +T-----------------+  +I--------------+  |&lt;br /&gt;|  |Address           |  | Avatar.png    |  |&lt;br /&gt;|  |                  |  |               |  |&lt;br /&gt;|  |                  |  |               |  |&lt;br /&gt;|  +------------------+  +---------------+  |&lt;br /&gt;|  ^NiceOrNaughty     ^  [Present        ]  |&lt;br /&gt;|  [Chimney Access Notes                 ]  |&lt;br /&gt;|     {New}{Update}{Delete}{Read Letter}    |&lt;br /&gt;|     Person 00000000001 of 8,342,124,422   |&lt;br /&gt;|                                           |&lt;br /&gt;+-------------------------------------------+&lt;br /&gt;&lt;br /&gt;NiceOrNaughty=Nice,Naughty&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;heredoc_terminator&#34;&gt;END&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$backend&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;tk&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;                 &lt;span class=&#34;comment&#34;&gt;# one of gtk, tk, gtk3, wx, win32 or html&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$assist&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;a&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;                   &lt;span class=&#34;comment&#34;&gt;# a for autogenerate, v for verbose, q for quiet&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$gui&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;GUIDeFATE&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$window&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$backend&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$assist&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt; &lt;span class=&#34;comment&#34;&gt;# Create the interface&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$frame&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$gui&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;getFrame&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;||&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$gui&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;comment&#34;&gt;# $frame object now contains all the widgets&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$gui&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;MainLoop&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;                 &lt;span class=&#34;comment&#34;&gt;# start the GUI&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Executing this script yielded the following UIs with GTK, TK, HTML and Wx, effectively 17 &#38;quot;widgets&#38;quot; in less than 10 instructions.&lt;/p&gt;

&lt;p&gt;&lt;div style=&#34;text-align: center;&#34;&gt;&lt;img width=&#34;800&#34; src=&#34;UI.png&#34;&gt;&lt;/div&gt;

&lt;/p&gt;



&lt;p&gt;But Santas laptop ran Windows. The solution was thankfully simple. Install &lt;a href=&#34;https://metacpan.org/module/Win32::GUI&#34;&gt;Win32::GUI&lt;/a&gt; and &lt;a href=&#34;https://metacpan.org/module/Imager&#34;&gt;Imager&lt;/a&gt; on Santas laptop, and change the &lt;code&gt;$backend&lt;/code&gt; variable to &lt;code&gt;&#38;quot;win32&#38;quot;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Making a UI was one thing, but tying actions to the widgets is quite another. How would you code the functions triggered by user interactions with the interface? Well passing &#38;quot;a&#38;quot; (for autogenerate) as the &lt;code&gt;$assist&lt;/code&gt; parameter, makes &lt;a href=&#34;https://metacpan.org/module/GUIDeFATE&#34;&gt;GUIDeFATE&lt;/a&gt; to create a text file with all the detected widgets as well as the skeleton functions that represent the callbacks. This is only required once, and the assist can be switched off by reverting to &#38;quot;q&#38;quot;, afterwards to prevent generating this file at every execution.&lt;/p&gt;

&lt;p&gt;With the above UI it generates the following file:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;comment&#34;&gt;#Static text &#39;Making A List, Checking it twice&#39;  with id stattext0&lt;br /&gt;#Static text &#39;Gonna find out Who&#39;s naughty and nice&#39;  with id stattext1&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;btn2&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;comment&#34;&gt;#called using button with label &#38;lt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;  # subroutine code goes here&lt;br /&gt;&lt;/span&gt;   &lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;btn3&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;comment&#34;&gt;#called using button with label &#38;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;  # subroutine code goes here&lt;br /&gt;&lt;/span&gt;   &lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;btn4&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;comment&#34;&gt;#called using button with label ?&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;  # subroutine code goes here&lt;br /&gt;&lt;/span&gt;   &lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;textctrl5&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;comment&#34;&gt;#called using Text Control with default text &#39; Name          &#39;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;  # subroutine code goes here&lt;br /&gt;&lt;/span&gt;   &lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;#Static text &#39;Person Index&#39;  with id stattext6&lt;br /&gt;#Static text &#39;|&#39;  with id stattext7&lt;br /&gt;#SubPanel &#39;T&#39; Id 9 found position  3 height 5 width 18 at row 5 with content Address&lt;br /&gt;#SubPanel &#39;I&#39; Id 11 found position  25 height 5 width 15 at row 5 with content Avatar.png&lt;br /&gt;#Static text &#39;|&#39;  with id stattext12&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;combo13&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;comment&#34;&gt;#called using combobox with data from @NiceOrNaughty&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;  # subroutine code goes here&lt;br /&gt;&lt;/span&gt;   &lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;textctrl14&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;comment&#34;&gt;#called using Text Control with default text &#39; Present         &#39;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;  # subroutine code goes here&lt;br /&gt;&lt;/span&gt;   &lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;textctrl15&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;comment&#34;&gt;#called using Text Control with default text &#39; Chimney Access Notes                  &#39;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;  # subroutine code goes here&lt;br /&gt;&lt;/span&gt;   &lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;btn16&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;comment&#34;&gt;#called using button with label New&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;  # subroutine code goes here&lt;br /&gt;&lt;/span&gt;   &lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;btn17&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;comment&#34;&gt;#called using button with label Update&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;  # subroutine code goes here&lt;br /&gt;&lt;/span&gt;   &lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;btn18&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;comment&#34;&gt;#called using button with label Delete&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;  # subroutine code goes here&lt;br /&gt;&lt;/span&gt;   &lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;btn19&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;comment&#34;&gt;#called using button with label Read Letter&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;  # subroutine code goes here&lt;br /&gt;&lt;/span&gt;   &lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;#Static text &#39;Person 00000000001 of 8,342,124,422&#39;  with id stattext20&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Each item in the window can be accessed using the id. Each button click or input change triggers a subroutine. Static Texts can be changed by using their IDs.&lt;/p&gt;

&lt;p&gt;More information can be found at &lt;a href=&#34;https://github.com/saiftynet/GUIDeFATE&#34;&gt;GUIDEFATE&#38;#39;s Github Pages&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was a quick and dirty solution to creating a general purpose intuitive UI; something that young Alabaster, the elf with advanced graphical interface powers could easily beautify once he returns from his well earned rest.&lt;/p&gt;

&lt;/div&gt;</summary><updated>2023-12-08T00:00:00Z</updated><category term="Perl"/><author><name>Saif</name></author></entry><entry><title>HTML/XSS scrubbing and file upload validation in Catalyst</title><link href="https://perladvent.org/2023/2023-12-07.html"/><id>https://perladvent.org/2023/2023-12-07.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;At work, we needed to tighten up the security of our Catalyst-powered API, with two main requirements:&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;Stripping HTML/XSS attempts from incoming parameters&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Validating that file uploads are expected and are the expected type&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&#34;Catalyst::Plugin::HTML::Scrubber&#34;&gt;Catalyst::Plugin::HTML::Scrubber&lt;/h3&gt;

&lt;p&gt;We found &lt;a href=&#34;https://metacpan.org/module/Catalyst::Plugin::HTML::Scrubber&#34;&gt;Catalyst::Plugin::HTML::Scrubber&lt;/a&gt;, which at first glance looked like it would do at least most of what we needed, automatically scrubbing parameters using &lt;a href=&#34;https://metacpan.org/module/HTML::Scrubber&#34;&gt;HTML::Scrubber&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We&#38;#39;re not a fan of reinventing wheels when we can avoid it, so I set about adding the extra features we needed - in particular, being able to exempt particular parameters from scrubbing, by name or regex match - and raised a pull request to share that upstream. Unfortunately, the original author doesn&#38;#39;t seem to be active in the Perl community any more, and several attempts of contact failed - so I followed the usual steps to &lt;a href=&#34;https://neilb.org/2013/07/24/adopt-a-module.html&#34;&gt;adopt a module&lt;/a&gt;, approaching our friendly CPAN admins for help, obtained co-maint, and released a new version.&lt;/p&gt;

&lt;p&gt;Since then we added more - including recursive scrubbing of parameters within serialised POSTed/PUTted request bodies.&lt;/p&gt;

&lt;h3 id=&#34;Catalyst::Plugin::CheckFileUploadTypes&#34;&gt;Catalyst::Plugin::CheckFileUploadTypes&lt;/h3&gt;

&lt;p&gt;Next, we needed to add checking of uploaded files. Some API actions do expect uploaded files, but most don&#38;#39;t. We wanted to make it easy to centralise that checking so that if an action hasn&#38;#39;t specified that it expects file uploads, any attempts to upload files in requests sent to it should be rejected.&lt;/p&gt;

&lt;p&gt;It should also be easy for the action to denote which MIME types it expects to receive, without lots of boilerplate code being added to each action.&lt;/p&gt;

&lt;p&gt;Naturally you&#38;#39;d want to use something to determine the type of file you were actually sent and can&#38;#39;t just trust the &lt;code&gt;Content-Type&lt;/code&gt; header in the request, because the client could lie to us.&lt;/p&gt;

&lt;p&gt;We didn&#38;#39;t find anything that fitted our needs, so I created &lt;a href=&#34;https://metacpan.org/module/Catalyst::Plugin::CheckFileUploadTypes&#34;&gt;Catalyst::Plugin::CheckFileUploadTypes&lt;/a&gt;, using subroutine attributes on the actions to mark that they expect uploads, for instance:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Catalyst&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(CheckFileUploadTypes)&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# Actions can declare that they expect to receive file uploads:&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;upload_file&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;attribute&#34;&gt;Local&lt;/span&gt; &lt;span class=&#34;attribute&#34;&gt;ExpectUploads&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# They can also specify that any uploaded files must be of expected types&lt;br /&gt;# (determined from file content by File::MMagic, not what the client said,&lt;br /&gt;# as they could lie to us)&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;upload_file&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;attribute&#34;&gt;Local&lt;/span&gt; &lt;span class=&#34;attribute&#34;&gt;ExpectUploads(image/jpeg image/png)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There was a little bit of fun involved if the app is using &lt;a href=&#34;https://metacpan.org/module/Catalyst::Action::REST&#34;&gt;Catalyst::Action::REST&lt;/a&gt;, in which case we want to be looking for the attributes on the &lt;code&gt;_type&lt;/code&gt;-suffixed action - for e.g. &lt;code&gt;index_POST&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;More features are planned (and may well have been implemented by the time you read this!) - including:&lt;/p&gt;

&lt;dl&gt;

&lt;dt&gt;Wildcards&lt;/dt&gt;
&lt;dd&gt;

&lt;p&gt;for e.g. the ability to say e.g. &lt;code&gt;image/*&lt;/code&gt; for any type of image&lt;/p&gt;

&lt;/dd&gt;
&lt;dt&gt;Extra heuristics to distinguish more file types&lt;/dt&gt;
&lt;dd&gt;

&lt;p&gt;For example, both a shell script and an XML file are both &lt;code&gt;text/plain&lt;/code&gt; according to the underlying &lt;a href=&#34;https://metacpan.org/module/File::MMagic&#34;&gt;File::MMagic&lt;/a&gt;; that&#38;#39;s not very helpful.&lt;/p&gt;

&lt;/dd&gt;
&lt;dt&gt;More options&lt;/dt&gt;
&lt;dd&gt;

&lt;p&gt;More options to provide more control over how unexpected uploads are handled&lt;/p&gt;

&lt;/dd&gt;
&lt;dt&gt;Callbacks&lt;/dt&gt;
&lt;dd&gt;

&lt;p&gt;Callbacks to fire for each uploaded file to perform additional checks on it - for example, running it through a virus checker, generating a hash and checking online services for matches, or other checks on the content of the file.&lt;/p&gt;

&lt;/dd&gt;
&lt;/dl&gt;

&lt;p&gt;Feedback, suggestions and patches welcome!&lt;/p&gt;

&lt;/div&gt;</summary><updated>2023-12-07T00:00:00Z</updated><category term="Perl"/><author><name>David Precious</name></author></entry><entry><title>Arango::Tango, the new mammal in town</title><link href="https://perladvent.org/2023/2023-12-06.html"/><id>https://perladvent.org/2023/2023-12-06.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h3 id=&#34;Introduction&#34;&gt;Introduction&lt;/h3&gt;

&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Arango::Tango&#34;&gt;Arango::Tango&lt;/a&gt; is not properly new, as the first versions are from 2019. Nevertheless, the number of users is still quite small as other document-oriented databases, like &lt;a href=&#34;https://www.elastic.co/&#34;&gt;ElasticSearch&lt;/a&gt; or &lt;a href=&#34;https://www.mongodb.com/&#34;&gt;MongoDB&lt;/a&gt; are still quite popular. But being somehow alergic to Java, I went in the search for an alternative and found &lt;a href=&#34;https://arangodb.com/&#34;&gt;ArangoDB&lt;/a&gt;, a graph database (also able to deal with plain document collections) written in C++.&lt;/p&gt;

&lt;p&gt;ArangoDB is a graph-oriented database, making it particularly well-suited for storing network structures such as social networks, knowledge graphs, and geospatial information. To achieve this, ArangoDB utilizes two collections: one for nodes and another for edges. The nodes collection functions as a standard database of documents, similar to what you would find in MongoDB. Meanwhile, the edges collection has documents containing two special attributes: the origin and target nodes, identified by their document identifiers. Unlike MongoDB and ElasticSearch, ArangoDB employs a specific Domain-Specific Language for queries. However, unlike the former two, ArangoDB&#38;#39;s query language, named AQL (ArangoDB Query Language), is not based on JSON. This distinction makes AQL easier to write and understand.&lt;/p&gt;

&lt;p&gt;When I found out about ArangoDB, I did not find a good Perl module to interact with it, so I decided to create one. &lt;a href=&#34;https://metacpan.org/module/Arango::Tango&#34;&gt;Arango::Tango&lt;/a&gt; was born. It is, surely, the Perl module I own with a cuter name, with both a pun on dancing a Tango with Arango, but also with the similarity with orangutangus.&lt;/p&gt;

&lt;h3 id=&#34;Quick-and-Dirty-Arango::Tango&#34;&gt;Quick and Dirty Arango::Tango&lt;/h3&gt;

&lt;p&gt;The ArangoDB insterface is based on REST, and the REST API is properly documented with &lt;a href=&#34;https://docs.arangodb.com/3.11/develop/http-api/#restful-api&#34;&gt;Swagger&lt;/a&gt;. It should be possible to use any generator that, from a Swagger specification, generates an API. But, being REST, the API is stateless, and that does not help being proficient when using it. Thus, I created my own monster, that both tries to be versatile enough to allow quick implementation of new methods using a structure similar to a Swagger file, but also with an object-oriented approach, where each type of object we can manage in the ArangoDB database has a counterpart Perl object.&lt;/p&gt;

&lt;p&gt;To give a quick example on how to create a ArangoDB collection and insert a couple of documents:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Arango::Tango&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$server&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Arango::Tango&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;host&lt;/span&gt;     &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;127.0.0.1&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;username&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;root&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;password&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;123123123&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$database&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$server&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;create_database&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;database_name&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$collection&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$database&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;create_collection&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;collection_name&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$document&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;John&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;surname&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Doe&#38;quot;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$collection&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;create_document&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$document&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$documents&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;_key&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;homer&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Homer&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;surname&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Simpson&#38;quot;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;_key&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;marge&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Marge&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;surname&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Simpson&#38;quot;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;];&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$collection&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;bulk_import&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$documents&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All the methods result in an HTTP request. But note that the objects created by Arango::Tango track the current database and collection. Thus, you do not need to pass that information everytime a new request is performed. You just create documents in the collection, and the module knows where the collection is (which database) and constructs properly the request.&lt;/p&gt;

&lt;p&gt;The query of documents can be performed directly, if you know the document identifier:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$document&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$collection&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;lisa&#38;quot;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;  &lt;span class=&#34;comment&#34;&gt;# retrieve document with key &#38;quot;lisa&#38;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Usually one does not want to just fetch a document, but perform a complex query. For that we will need to use the ArangoDB&#38;#39;s query language: AQL. The method&#38;#39;s name to query a collection is not the more intuitive, as I followed the convention from the REST API. I may change that in the future. It is named &lt;code&gt;cursor&lt;/code&gt; because it returns... a cursor object, that allows you to go through a set of results.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$query&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;heredoc&#34;&gt;&#38;lt;&#38;lt;EOQ&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;heredoc_content&#34;&gt;    FOR doc IN collection_name&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;FILTER doc.surname == &#39;Simpson&#39;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;RETURN doc&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;heredoc_terminator&#34;&gt;EOQ&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$cursor&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$collection&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;cursor&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$query&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$cursor&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;has_more&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@block&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$cursor&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;next&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;    # do something with elements from @block&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that, by default, ArangoDB returns more than one document when iterating a cursor, to make it more efficient. Thus, the &lt;code&gt;next&lt;/code&gt; method returns a list of results and not just one item.&lt;/p&gt;

&lt;h3 id=&#34;The-Arango::Tango-Guts&#34;&gt;The Arango::Tango Guts&lt;/h3&gt;

&lt;p&gt;I am proud of the way this module has been designed. The code is not as polished as I would like it to be, but the idea behind it is quite interesting. I decided to give some insight into its implementation. Note this is just a quick glimpse of it. You are welcome to look into the code for more detail.&lt;/p&gt;

&lt;p&gt;Each of the modules (database, collection, etc) start by running an initialization method. It is based on a structure that specifies the available REST API requests. This initialization generates methods with the required code to execute the REST request.&lt;/p&gt;

&lt;p&gt;Two small examples for the &lt;code&gt;Arango::Tango::Collection&lt;/code&gt; module:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;word&#34;&gt;load_indexes&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;rest&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;put&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;{{database}}_api/collection/{name}/loadIndexesIntoMemory&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;inject_properties&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;database&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;name&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;rename&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;rest&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;put&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;{{database}}_api/collection/{collection}/rename&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;inject_properties&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;database&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;prop&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;name&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;collection&#39;&lt;/span&gt;  &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;signature&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;name&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;schema&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;string&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The top-level key is the name of the method to create. The value of the dictionary defines details on the method implementation:&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;For the &lt;code&gt;load_indexes&lt;/code&gt; method, there is the REST template (that specifies the HTTP verb and the route template) and the &lt;code&gt;inject_properties&lt;/code&gt; array. This array is a list of the parameters, in the REST template, that should be filled in from data in the collections object fields.&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;rename&lt;/code&gt; method has the same two properties as the previous one. But the &lt;code&gt;inject_properties&lt;/code&gt; is a little different. Basically, it has two fields from the object being injected in the template (the database and the collection name) but, for the collection, we specify that it is stored in the &lt;code&gt;name&lt;/code&gt; field of the object, but will be referred to in the template as &lt;code&gt;collection&lt;/code&gt;. This change is done because there is a parameter named &lt;code&gt;name&lt;/code&gt;, and we need to disambiguate.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;signature&lt;/code&gt; field is the list of parameters that the method will receive and the &lt;code&gt;schema&lt;/code&gt; property is the structure of the data that will be sent in the &lt;code&gt;PUT&lt;/code&gt; request. Note that there is a &lt;code&gt;name&lt;/code&gt; field in that data, that will come from the method&#38;#39;s signature.&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unfortunately not all requests are as easy to generalize and therefore there is some extra code to deal with hairy calls. Also, there is a reason why the template has two curly braces for the database parameter. But that is not relevant for being discussed here.&lt;/p&gt;

&lt;p&gt;If you found this interesting, I would appreciate your help on supporting more of the ArangoDB API!&lt;/p&gt;

&lt;/div&gt;</summary><updated>2023-12-06T00:00:00Z</updated><category term="Perl"/><author><name>Alberto Sim&#245;es</name></author></entry><entry><title type="html">Santa&#38;#39;s Christmas Dancer2 Web App - Naughty &#38;amp; Nice List Manager</title><link href="https://perladvent.org/2023/2023-12-05.html"/><id>https://perladvent.org/2023/2023-12-05.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;Ho, ho, ho! In this hilarious Christmas-themed Dancer2 web app tutorial, we&#38;#39;ll help Santa manage his Naughty &#38;amp; Nice list. This time, we&#38;#39;re using Perl&#38;#39;s Dancer2 framework, but Santa&#38;#39;s Christmas spirit is universal. Let&#38;#39;s dive in and create Santa&#38;#39;s very own web app!&lt;/p&gt;

&lt;h3 id=&#34;todo.pl&#34;&gt;todo.pl&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;operator&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;comment&#34;&gt;#/usr/bin/env perl&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Dancer2&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;set&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;template&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;mustache&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# Initialize Santa&#39;s Naughty &#38;amp; Nice List&lt;br /&gt;# See next steps below for making list persistent with a Planetscale Database&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$list&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;list&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;get&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;/&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;send_file&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;/index.html&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;any&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;/delete&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$q&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;params&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$index&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;    # Find the naughty or nice kid to remove&lt;br /&gt;&lt;/span&gt;    &lt;span class=&#34;symbol&#34;&gt;$index&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;++&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;until&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$list&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}[&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$index&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;task&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$q&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;task&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;splice&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;cast&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$list&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$index&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;    # Display the updated list&lt;br /&gt;&lt;/span&gt;    &lt;span class=&#34;word&#34;&gt;template&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;list&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$list&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;any&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;/add&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$q&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;params&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;    # Add a new kid to the list&lt;br /&gt;&lt;/span&gt;    &lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$list&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;list&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$q&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;    # Display the updated list&lt;br /&gt;&lt;/span&gt;    &lt;span class=&#34;word&#34;&gt;template&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;list&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$list&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;any&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;/list&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;    # Display the current list&lt;br /&gt;&lt;/span&gt;    &lt;span class=&#34;word&#34;&gt;template&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;list&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$list&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;start&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here&#38;#39;s what Santa&#38;#39;s Christmas Dancer2 web app does:&lt;/p&gt;

&lt;ol&gt;

&lt;li&gt;&lt;p&gt;We set up our Dancer2 app with Mustache templates.&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Santa initializes his Naughty &#38;amp; Nice List as an empty array of tasks.&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When you visit the root URL /, it serves an index.html file. Make sure to create this HTML file for a nice, festive interface.&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To delete a naughty or nice kid, we look for the kid&#38;#39;s task in the list and remove them. Then, we display the updated list using the &#38;#39;list&#38;#39; template.&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To add a kid to the list, we take the kid&#38;#39;s name from the request parameters, push them onto the list, and display the updated list using the &#38;#39;list&#38;#39; template. List is freeform text. Eg &#38;quot;Nancy - Naughty - coal&#38;quot;. See Next steps below to expand into multiple database fields&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The /list route simply displays the current Naughty &#38;amp; Nice List.&lt;/p&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, Santa can keep a digital record of all the good and naughty children, and you can help him manage it with this fun Dancer2 web app. Merry Christmas and happy coding! &#38;#x1F385;&#38;#x1F384;&#38;#x1F31F;&lt;/p&gt;

&lt;h3 id=&#34;public-index.html&#34;&gt;public/index.html&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;    &#38;lt;!DOCTYPE html&#38;gt;
    &#38;lt;html&#38;gt;
     &#38;lt;head&#38;gt;
        &#38;lt;title&#38;gt;TODO app&#38;lt;/title&#38;gt;
        &#38;lt;!-- Include the htmx.js library for AJAX interactions --&#38;gt;
        &#38;lt;script src=&#38;quot;https://unpkg.com/htmx.org@1.9.6&#38;quot;&#38;gt;&#38;lt;/script&#38;gt;
        &#38;lt;!-- Include a stylesheet (Water.css in dark mode) for styling --&#38;gt;
        &#38;lt;link rel=&#38;quot;stylesheet&#38;quot; href=&#38;quot;https://cdn.jsdelivr.net/npm/water.css@2/out/dark.css&#38;quot;&#38;gt;
     &#38;lt;/head&#38;gt;
     &#38;lt;body&#38;gt;
        &#38;lt;!-- Create a form for adding tasks --&#38;gt;
        &#38;lt;form hx-post=&#38;quot;/add&#38;quot; hx-target=&#38;quot;#list&#38;quot; hx-on::after-request=&#38;quot;this.reset()&#38;quot;&#38;gt;
            &#38;lt;fieldset&#38;gt;
                &#38;lt;!-- Input field for entering a task --&#38;gt;
                &#38;lt;input type=&#38;quot;text&#38;quot; name=&#38;quot;task&#38;quot; placeholder=&#38;quot;enter task&#38;quot; /&#38;gt;
                &#38;lt;!-- Button to submit the task --&#38;gt;
                &#38;lt;button type=&#38;quot;submit&#38;quot;&#38;gt;Add Task&#38;lt;/button&#38;gt;
            &#38;lt;/fieldset&#38;gt;
        &#38;lt;/form&#38;gt;
        &#38;lt;fieldset&#38;gt;
            &#38;lt;!-- Display the list of tasks here using AJAX --&#38;gt;
            &#38;lt;div id=&#38;quot;list&#38;quot; hx-get=&#38;quot;/list&#38;quot; hx-trigger=&#38;quot;load&#38;quot;&#38;gt;&#38;lt;/div&#38;gt;
        &#38;lt;/fieldset&#38;gt;
     &#38;lt;/body&#38;gt;
    &#38;lt;/html&#38;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;img src=&#34;12-05-naughty.northpole.io.png&#34; /&gt;

&lt;p&gt;This HTML code provides a simple web interface to add and view tasks. When a user adds a task, it&#38;#39;s sent to the server using htmx via the hx-post attribute, and the response updates the task list on the page. Santa can now manage his Naughty &#38;amp; Nice list with a modern touch. Merry Christmas and happy coding! &#38;#x1F385;&#38;#x1F384;&#38;#x1F31F;&lt;/p&gt;

&lt;p&gt;The provided template uses htmx, a library for building modern web applications with HTML, to create a list of tasks with some interactive behavior. Let&#38;#39;s break down the template step by step:&lt;/p&gt;

&lt;h3 id=&#34;views-list.mustache&#34;&gt;views/list.mustache&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;     &#38;lt;ul&#38;gt;
         {{#list}} &#38;lt;!-- This is a loop that iterates through the &#38;#39;list&#38;#39; array --&#38;gt;
             &#38;lt;li hx-post=&#38;quot;/delete&#38;quot; hx-target=&#38;quot;#list&#38;quot; hx-vals=&#38;#39;{&#38;quot;task&#38;quot;:&#38;quot;{{task}}&#38;quot;}&#38;#39;&#38;gt;{{task}}&#38;lt;/li&#38;gt;
             &#38;lt;!-- For each item in &#38;#39;list&#38;#39;, create an &#38;lt;li&#38;gt; element --&#38;gt;
             &#38;lt;!-- &#38;#39;hx-post&#38;#39; specifies an HTTP POST request when this &#38;lt;li&#38;gt; element is clicked --&#38;gt;
             &#38;lt;!-- &#38;#39;hx-target&#38;#39; designates where the response will be placed (in this case, back into the list) --&#38;gt;
             &#38;lt;!-- &#38;#39;hx-vals&#38;#39; defines the data to send with the POST request --&#38;gt;
             &#38;lt;!-- The data consists of a key &#38;quot;task&#38;quot; with the value being the task name from the list --&#38;gt;
             &#38;lt;!-- The {{task}} within the hx-vals is a placeholder for the task name from the loop --&#38;gt;
             {{task}}
             &#38;lt;!-- Display the task name within the &#38;lt;li&#38;gt; element --&#38;gt;
         {{/list}}
     &#38;lt;/ul&#38;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here&#38;#39;s how this template works:&lt;/p&gt;

&lt;ol&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;&#38;lt;ul&#38;gt;&lt;/code&gt;: This creates an unordered list where each task will be represented as a list item &lt;code&gt;&#38;lt;li&#38;gt;&lt;/code&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;{{#list}}&lt;/code&gt;: and &lt;code&gt;{{/list}}&lt;/code&gt;: These tags denote a loop that iterates through the &#38;#39;list&#38;#39; array. For each item in the &#38;#39;list&#38;#39;, it performs the following operations.&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;&#38;lt;li&#38;gt;&lt;/code&gt;: This creates an &lt;code&gt;&#38;lt;li&#38;gt;&lt;/code&gt; element for each task in the &#38;#39;list&#38;#39;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;hx-post=&#38;quot;/delete&#38;quot;: When an &lt;code&gt;&#38;lt;li&#38;gt;&lt;/code&gt; element is clicked, htmx sends an HTTP POST request to the URL specified in the hx-post attribute. In this case, it&#38;#39;s /delete, indicating a task deletion action.&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;hx-target=&#38;quot;#list&#38;quot;: This attribute specifies where the response of the HTTP POST request should be placed. In this example, it replaces the content of the element with the ID &#38;quot;list,&#38;quot; effectively updating the list after a task is deleted.&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;hx-vals=&#38;#39;{&#38;quot;task&#38;quot;:&#38;quot;{{task}}&#38;quot;}&#38;#39;: This attribute defines the data to send with the POST request. It includes a key &#38;quot;task&#38;quot; with a value equal to the task name. The {{task}} is a placeholder that gets replaced with the actual task name from the loop during execution.&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;{{task}}: Inside the &lt;code&gt;&#38;lt;li&#38;gt;&lt;/code&gt; element, this placeholder displays the task name from the loop in the list item.&lt;/p&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In summary, this template generates a list of tasks, and each task has a delete button. When a delete button is clicked, htmx sends a POST request to the server to delete the corresponding task and updates the list without requiring a full page refresh.&lt;/p&gt;

&lt;h3 id=&#34;Next-Steps&#34;&gt;Next Steps&lt;/h3&gt;

&lt;p&gt;View this repo to see the Planetscale database and fly.io edge deploy. This works great on the free tier of both. &lt;a href=&#34;https://github.com/perladvent/2023-todoapp&#34;&gt;https://github.com/perladvent/2023-todoapp&lt;/a&gt;&lt;/p&gt;

&lt;/div&gt;</summary><updated>2023-12-05T00:00:00Z</updated><category term="Perl"/><author><name>Ken Town</name></author></entry><entry><title>Trimming your holiday tree</title><link href="https://perladvent.org/2023/2023-12-04.html"/><id>https://perladvent.org/2023/2023-12-04.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;It&#38;#39;s time to pull out your holiday decorations. If you are like me, you probably have a couple of new decorations to add to your collection.&lt;/p&gt;

&lt;p&gt;Perl v5.36 has some new ornaments too. The new pragma &lt;a href=&#34;https://metacpan.org/module/builtin&#34;&gt;builtin&lt;/a&gt; defines several new functions in Perl&#38;#39;s core. I go through these in &lt;a href=&#34;https://leanpub.com/perl_new_features&#34;&gt;Perl New Features&lt;/a&gt;, but there&#38;#39;s one I want to show you this holiday season.&lt;/p&gt;

&lt;h3 id=&#34;Remove-surrounding-whitespace&#34;&gt;Remove surrounding whitespace&lt;/h3&gt;

&lt;p&gt;Typically I get rid of the annoying whitespace with an inefficient global substitution that I can&#38;#39;t make my fingers not type:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;version&#34;&gt;v5.10&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$dirty_string&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;   Happy Holidays   &#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Dirty:   &#38;lt;$dirty_string&#38;gt;&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$dirty_string&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;substitute&#34;&gt;s/\A\s+|\s+\z//ug&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Trimmed: &#38;lt;$dirty_string&#38;gt;&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That &lt;code&gt;/u&lt;/code&gt; tells the substitution to use the Unicode rules, which means this also trims all the &lt;a href=&#34;https://www.effectiveperlprogramming.com/2011/01/know-your-character-classes/&#34;&gt;other whitespace that Unicode defines&lt;/a&gt;. I&#38;#39;m especially fond of that one after chasing down a bug caused by a someone using an en space (U+2002) instead of a regular space (likely from an export from layout software).&lt;/p&gt;

&lt;p&gt;Or, more likely, I keep the original as is and make a copy with the &lt;code&gt;/r&lt;/code&gt; flag from v5.14. This way I can log the original value later when I&#38;#39;m trying to figure out why some inputs don&#38;#39;t work right (or someone is passing bad data):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;version&#34;&gt;v5.26&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$dirty_string&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;   Happy Holidays   &#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$trimmed&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$dirty_string&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;substitute&#34;&gt;s/\A\s+|\s+\z//ugr&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;heredoc&#34;&gt;&#38;lt;&#38;lt;~&#38;quot;HERE&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;heredoc_content&#34;&gt;	Dirty:   &#38;lt;$dirty_string&#38;gt;&lt;br /&gt;&#38;nbsp;Trimmed: &#38;lt;$trimmed&#38;gt;&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;heredoc_terminator&#34;&gt;	HERE&lt;br /&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is such a common operation that it deserves its own name&#38;mdash; &lt;code&gt;trim&lt;/code&gt;. The &lt;a href=&#34;https://metacpan.org/module/builtin&#34;&gt;builtin&lt;/a&gt; pragma is still experimental, so I turn off those warnings with &lt;a href=&#34;https://metacpan.org/module/experimental&#34;&gt;experimental&lt;/a&gt; before I enable &lt;code&gt;trim&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;version&#34;&gt;v5.36&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;experimental&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(builtin)&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;builtin&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(trim)&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$dirty_string&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;   Happy Holidays   &#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$trimmed&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;trim&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$dirty_string&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;heredoc&#34;&gt;&#38;lt;&#38;lt;~&#38;quot;HERE&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;heredoc_content&#34;&gt;	Dirty:   &#38;lt;$dirty_string&#38;gt;&lt;br /&gt;&#38;nbsp;Trimmed: &#38;lt;$trimmed&#38;gt;&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;heredoc_terminator&#34;&gt;	HERE&lt;br /&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All of these get you to the same output:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;        Dirty:   &#38;lt;   Happy Holidays   &#38;gt;
        Trimmed: &#38;lt;Happy Holidays&#38;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;More-ornaments&#34;&gt;More ornaments&lt;/h3&gt;

&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/builtin&#34;&gt;builtin&lt;/a&gt; provides other new ornaments. I give detailed examples of these in &lt;a href=&#34;https://leanpub.com/perl_new_features&#34;&gt;Perl New Features&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;blessed&lt;/code&gt;, &lt;code&gt;refaddr&lt;/code&gt;, &lt;code&gt;reftype&lt;/code&gt;, &lt;code&gt;is_tainted&lt;/code&gt; (as &lt;code&gt;tainted&lt;/code&gt;), &lt;code&gt;is_weak&lt;/code&gt; (as &lt;code&gt;isweak&lt;/code&gt;), &lt;code&gt;weaken&lt;/code&gt;, and &lt;code&gt;unweaked&lt;/code&gt; functions have so far been part of the &lt;a href=&#34;https://metacpan.org/module/Scalar::Util&#34;&gt;Scalar::Util&lt;/a&gt; module. Now they are directly in core and do the same job.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ceil&lt;/code&gt; and &lt;code&gt;floor&lt;/code&gt; functions move from the heavyweight &lt;a href=&#34;https://metacpan.org/module/POSIX&#34;&gt;POSIX&lt;/a&gt; module directly into core.&lt;/p&gt;

&lt;p&gt;More excitingly, &lt;a href=&#34;https://metacpan.org/module/builtin&#34;&gt;builtin&lt;/a&gt; adds &lt;code&gt;true&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt;: no more &lt;code&gt;!!1&lt;/code&gt; floating around your code confusing everyone. These &#38;quot;distinguished&#38;quot; booleans know that they are booleans rather than comparing themselves to Perl&#38;#39;s idea of truthiness. These are useful for turning data into formats that have special keywords for those ideas, such as JSON&#38;#39;s &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;. You can check if you have one these distinguished values with &lt;code&gt;is_bool&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Along with that, &lt;a href=&#34;https://metacpan.org/module/builtin&#34;&gt;builtin&lt;/a&gt; knows if something is a string or a number based on the last thing that happened to it. With &lt;code&gt;created_as_number&lt;/code&gt; or &lt;code&gt;created_as_string&lt;/code&gt;, you know if you need to create the JSON string value &lt;code&gt;{&#38;quot;value&#38;quot;: 137}&lt;/code&gt; or the JSON string value &lt;code&gt;{&#38;quot;value&#38;quot;: &#38;quot;137&#38;quot;}&lt;/code&gt;. This should work going the other way too. Eventually the various libraries will catch up to Perl so we don&#38;#39;t have to do weird acrobatics to figure out what sort of value we are supposed to have.&lt;/p&gt;

&lt;p&gt;There are a few other interesting features for you to discover in &lt;a href=&#34;https://metacpan.org/module/builtin&#34;&gt;builtin&lt;/a&gt;, and I hope many of these lose their experimental status soon.&lt;/p&gt;

&lt;/div&gt;</summary><updated>2023-12-04T00:00:00Z</updated><category term="Perl"/><author><name>brian d foy</name></author></entry><entry><title>Santa tackles Bitcoin, part two</title><link href="https://perladvent.org/2023/2023-12-03.html"/><id>https://perladvent.org/2023/2023-12-03.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;It was a new day in Lapland! Well, sort of... it was still dark outside due to polar night, but our elf friend McJingles was well-rested and full of energy! &lt;a href=&#34;https://perladvent.org/2023/2023-12-02.html&#34;&gt;Yesterday&lt;/a&gt; he learned all about how to make a transaction using &lt;a href=&#34;https://metacpan.org/module/Bitcoin::Crypto&#34;&gt;Bitcoin::Crypto&lt;/a&gt;, but he forgot to prepare the private keys to be gifted by Santa. Elves may be very hard-working, but they are also forgetful!&lt;/p&gt;

&lt;p&gt;He quickly came up with a plan: the private keys will probably be printed on lovely decorated Christmas gift cards. All he had to do is provide printable representations of the private keys and the other elves can do all the printing. McJingles decided it will for now be enough to print all the keys as those Wallet Import Format (WIF) things he had used before to get access to the initial 50 BTC. The standard output of the script can be redirected to a file with no additional effort.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;version&#34;&gt;v5.36&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Bitcoin::Crypto&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(btc_extprv)&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# Ask for mnemonic and password. Keeping them in a file makes them much easier&lt;br /&gt;# target for malware and hackers!&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Please provide the mnemonic and password, each in separate lines:&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$mnemonic&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;readline&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;STDIN&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$password&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;readline&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;STDIN&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# Remove the newline from readline&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;chomp&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$mnemonic&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;chomp&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$password&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# recover a key from input&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$master_key&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;btc_extprv&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;from_mnemonic&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$mnemonic&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$password&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# how many presents?&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$number_of_kids&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;346&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# print all the keys in WIF format&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$index&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;..&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$number_of_kids&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;  # same derivation scheme as before&lt;br /&gt;&lt;/span&gt;  &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$key&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$master_key&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;derive_key_bip44&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;purpose&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;84&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;account&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;index&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$index&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;get_basic_key&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;  # print it to standard output&lt;br /&gt;&lt;/span&gt;  &lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$key&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;to_wif&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This script was much more straightforward than the previous one! It was time to see if the key recovery worked:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;        Please provide the mnemonic and password, each in separate lines:
        brown bulk hire culture capital hill trim turkey  gossip artefact door media argue basic execute slam minute try number daughter music gauge vocal wink
        Christmas
        L1pn6bRKUY1dMXg6XvURHNCrm9CDByFehQPHmnfTKQXCxRktUAqN
        L3dhFVe8BgjgGGbu2Rm72fcgyB3SgVZ2ee8fsoezSA47QxhDAng5
        L2TZEBZJ2yTb2JxcxbUippr3DBAkZopLFrXSGGZRRzfH78RFcTnj
        (...)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It worked indeed, but it was not yet clear whether the private keys were the correct ones. McJingles crafted a one-liner to test the first key he got:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;        $ perl -MBitcoin::Crypto=btc_prv -e \
        &#38;#39;print btc_prv-&#38;gt;from_wif(&#38;quot;L1pn6bRKUY1dMXg6XvURHNCrm9CDByFehQPHmnfTKQXCxRktUAqN&#38;quot;)-&#38;gt;get_public_key-&#38;gt;get_address&#38;#39;
        bc1qls9ffahaa5kezk0zvq2hh58nn6yfv8uehdq7dp&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Something was wrong. That&#38;#39;s not the address which was generated before! How is that possible? After thorough investigation McJingles found out he typed two spaces while providing the mnemonic for the program. A quick scan through &lt;a href=&#34;https://metacpan.org/module/Bitcoin::Crypto::Key::ExtPrivate&#34;&gt;Bitcoin::Crypto::Key::ExtPrivate&lt;/a&gt;&#38;#39;s documentation has revealed that &lt;code&gt;from_mnemonic&lt;/code&gt; method usage without the language argument is not only whitespace-sensitive but also doesn&#38;#39;t check if the words exist in the dictionary. It is pretty unsafe to use it like that unless you nail it exactly right! He modified the script to add &lt;code&gt;&#38;#39;en&#38;#39;&lt;/code&gt; language as the last argument to &lt;code&gt;from_mnemonic&lt;/code&gt;...&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$master_key&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;btc_extprv&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;from_mnemonic&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$mnemonic&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$password&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;en&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;... and then tried again, making the same mistake:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;        Please provide the mnemonic and password, each in separate lines:
        brown bulk hire culture capital hill trim turkey  gossip artefact door media argue basic execute slam minute try number daughter music gauge vocal wink
        Christmas
        L4DrMfpZRp5P6szTGqWQHnYDBJaAwTRN8NHRkTM3Kc79U14wi5Li
        L3rpcJdvNynUCWWaQEEAXkS7FPpCrz1HnCiHT4VYcmm4oWct5Fd8
        KwzsywmntPwwnEMTbd9jw7wPjeM4PKx52KeSLU9cZ4o1Qx7AFyTD
        (...)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The output was different, but was it the right key this time?&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;        $ perl -MBitcoin::Crypto=btc_prv -e \
        &#38;#39;print btc_prv-&#38;gt;from_wif(&#38;quot;L4DrMfpZRp5P6szTGqWQHnYDBJaAwTRN8NHRkTM3Kc79U14wi5Li&#38;quot;)-&#38;gt;get_public_key-&#38;gt;get_address&#38;#39;
        bc1qum6sd22rmsewwd75lzlynuve8wz0ah2uw2gltu&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Yes, that&#38;#39;s correct! This was the first address printed in the transaction dump yesterday. If he was able to obtain the same address then surely he will be able to move the coins. And so will the children! When they wake up in the morning and find the gift cards, they will have an option of keeping it or sweeping it. Sweeping is a function commonly found in mobile Bitcoin wallets and when used the coins will be transferred away to a different wallet. To spare the kids all the retyping of WIFs it&#38;#39;s best to also provide a QR code, but that&#38;#39;s a problem for another day (or another elf). If they don&#38;#39;t sweep it the coins will still be spendable by Santa and his helpers, but it&#38;#39;s safe to assume they would never steal a Christmas present back!&lt;/p&gt;

&lt;p&gt;He ran the script again with output redirected to a file and e-mailed it to Santa. &#38;quot;Here Father Christmas, I made it!&#38;quot; - he typed in excitement. He added all the other elves as CC to the e-mail so they could start printing the gift cards. It was a job well done indeed.&lt;/p&gt;

&lt;p&gt;Now the last question remains: will he remember to publish the transaction before the Silent Night? We are about to find out very, very soon.&lt;/p&gt;

&lt;/div&gt;</summary><updated>2023-12-03T00:00:00Z</updated><category term="Perl"/><author><name>Bartosz Jarzyna</name></author></entry><entry><title>Santa tackles Bitcoin, part one</title><link href="https://perladvent.org/2023/2023-12-02.html"/><id>https://perladvent.org/2023/2023-12-02.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;p&gt;Santa is facing a new problem. Year after year, an increasing number of kids list Bitcoin as a thing they want to find under the Christmas Tree. This new trend comes much to the displeasure of the Kriss Kringle.&lt;/p&gt;

&lt;p&gt;&#38;quot;This is outrageous!&#38;quot;, he yelled in annoyance. &#38;quot;How can this thing even have value? Hasn&#38;#39;t it died like five hundred times already? It&#38;#39;s not even real!&#38;quot;&lt;/p&gt;

&lt;p&gt;He started stroking his beard, thinking. His white moustache danced like waves on a beach as he tried to understand the new reality of 2023. If the good kids want it, then he must oblige. But how could something be left in someone&#38;#39;s house if it isn&#38;#39;t physical? He asked his most tech-savvy elf, McJingles, to research the subject.&lt;/p&gt;

&lt;p&gt;McJingles is a hacker. He knows a bunch of programming languages but Perl is his favourite. He&#38;#39;s a walking reference book for all things software. But Bitcoin? That&#38;#39;s relatively new and not really something he paid attention to. Moreover, the nasty things he heard about it and the criminals has put him off a great deal. But to be tasked to research it from the Father Christmas himself? That&#38;#39;s a completely new level of incentive!&lt;/p&gt;

&lt;p&gt;So he searched the Web for the term, but most of what he got were rubbish price speculation articles. The &lt;a href=&#34;https://en.bitcoin.it&#34;&gt;Bitcoin wiki&lt;/a&gt; was of some help, but it was partially outdated. The &lt;a href=&#34;https://github.com/bitcoin/bips&#34;&gt;Bitcoin Improvement Proposal&lt;/a&gt; documents were good, but a bit too specific for his level. So maybe books? He read &lt;i&gt;Mastering Bitcoin&lt;/i&gt; by Andreas Antropolus, which gave him a nice insight into the technical side of Bitcoin. He pressed ahead with &lt;i&gt;The Bitcoin Standard&lt;/i&gt; by Saifedean Ammous, which provided all the economic details he needed.&lt;/p&gt;

&lt;p&gt;It quickly became obvious the new task couldn&#38;#39;t be performed in the current modus operandi. The Elves were used to crafting everything themselves and often resorting to magic in their toy factory. They can&#38;#39;t counterfeit Bitcoin - not because it&#38;#39;s a bad thing to do, but rather because it&#38;#39;s impossible. Even the strongest Elf Magic won&#38;#39;t do. They could either try to mine it or obtain it by providing high quality goods and services on the market. Luckily, one of the elves remembered he had played with Bitcoin back in 2011 and still had the old hard drive, from which they were able to reclaim keys to 50 bitcoins, enough for a big juicy present for &lt;i&gt;a lot&lt;/i&gt; of kids. The unspent transaction ID for their coins is &lt;a href=&#34;https://mempool.space/tx/a4e407ba6b54106e4bd209704666a2b541b9b03d04ef8cb779aafe18238744e1&#34;&gt;a4e407ba6b54106e4bd209704666a2b541b9b03d04ef8cb779aafe18238744e1&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now the next step was to split the big chunk of 50 bitcoins into smaller pieces. This means you need to create a transaction with one input (the unspent previous transaction output of 50 bitcoins) and N + 1 outputs (one output for each of N kids, plus an additional one for the change). Since Santa said the number N is well into the hundreds this year, crafting this transaction by hand in a wallet software was out of question and they needed some kind of programmable library. McJingles, being a Perl lover, decided to give the module &lt;a href=&#34;https://metacpan.org/module/Bitcoin::Crypto&#34;&gt;Bitcoin::Crypto&lt;/a&gt; a go. He started a new script to create the transaction:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;version&#34;&gt;v5.36&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Bitcoin::Crypto&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(btc_prv btc_utxo)&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# first, import the 50 BTC output from previous transaction hex&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;btc_utxo&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;extract&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;([&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;hex&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;&lt;br /&gt;&#38;nbsp;&#38;nbsp;010000000100000000000000000000&lt;br /&gt;&#38;nbsp;&#38;nbsp;000000000000000000000000000000&lt;br /&gt;&#38;nbsp;&#38;nbsp;00000000000000ffffffff07045285&lt;br /&gt;&#38;nbsp;&#38;nbsp;021b0151ffffffff0100f2052a0100&lt;br /&gt;&#38;nbsp;&#38;nbsp;000043410452b58be18046f78a0045&lt;br /&gt;&#38;nbsp;&#38;nbsp;fe49df56387a03f994ba2ac7a26e17&lt;br /&gt;&#38;nbsp;&#38;nbsp;f7d01dc6d346f1bed3979ad35d32a7&lt;br /&gt;&#38;nbsp;&#38;nbsp;5bb625f6e521f75a1c5983d303ea04&lt;br /&gt;&#38;nbsp;&#38;nbsp;bfb43c8b72203a68eeac00000000&lt;br /&gt;&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# second, import the private key to these BTC&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$priv&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;btc_prv&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;from_wif&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;&#38;lt;SUPER SECRET KEY TO 50 BTC&#38;gt;&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So far so good, but there were some decisions to be made before continuing. The old private key was in &lt;i&gt;WIF&lt;/i&gt;, short for Wallet Import Format, which is only capable of holding a single private key. Now hundreds of private keys needed to be generated, and the most important one of them all would be the change address for the unspent BTC. You may just send back to the address you&#38;#39;ve taken from, but since it was the effectively obsolete P2PK (pay to public key) address they figured it was smarter to generate a new type of address and send there. McJingles decided to generate a new mnemonic phrase capable of providing as many private keys as needed:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Bitcoin::Crypto&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(btc_extprv)&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Bitcoin::Crypto::Util&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(generate_mnemonic)&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# generate a new random mnemonic with 256 bits of entropy&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$mnemonic&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;generate_mnemonic&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;256&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$password&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Christmas&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# create a new master master key from the mnemonic&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$master_key&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;btc_extprv&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;from_mnemonic&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$mnemonic&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$password&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# instruct the user to backup the mnemonic&lt;br /&gt;# (say function is a part of 5.36 version bundle)&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Your mnemonic is &#38;lt;$mnemonic&#38;gt;&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;and your password is &#38;lt;$password&#38;gt;&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Back them up!&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Mnemonic phrases are sets of words which encode the wallet&#38;#39;s entropy in a human (or elf!) readable way. In case of 256 bits, the mnemonic will contain 24 words. The optional password makes sure it&#38;#39;s not that easy for anyone who gets the mnemonic to take hold of all the Bitcoin. It is a secondary security feature. McJingles knew it was best to store the mnemonic offline, for example written on paper.&lt;/p&gt;

&lt;p&gt;The created &lt;code&gt;$master_key&lt;/code&gt; can be used to derive many keys from it using Hierarchical Deterministic derivation schemes. The clever elf decided to use the most widely supported &lt;a href=&#34;https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki&#34;&gt;BIP44 scheme&lt;/a&gt; with &lt;a href=&#34;https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki&#34;&gt;purpose 84&lt;/a&gt;. By using this purpose number, &lt;a href=&#34;https://en.wikipedia.org/wiki/SegWit&#34;&gt;Segregated Witness&lt;/a&gt; addresses were created. It&#38;#39;s a modern type of address which makes the on-chain fees lower.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;comment&#34;&gt;# cuz Santa said so&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$number_of_kids&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;346&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# get the master key for the BIP44 account with purpose 84&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$account_key&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$master_key&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;derive_key_bip44&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;purpose&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;84&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;get_account&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;!!&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;account&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;comment&#34;&gt;# to be bumped up next Christmas!&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# get the basic private key for the unused coins&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$change_key&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$account_key&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;derive_key_bip44&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;get_from_account&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;!!&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;change&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;index&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;get_basic_key&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# get basic keys for all the kids!&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@kids_keys&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;map&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$account_key&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;derive_key_bip44&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;get_from_account&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;!!&lt;/span&gt;&lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;index&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;get_basic_key&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;..&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$number_of_kids&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;McJingles now had all the essential parts needed to create the transaction. He asked the Santa how juicy the presents should be, but all he heard in return was some mumbling about the economy being tough and the need to cut the expenses. He figured 100,000 satoshi (the smallest units) for each kid should do. Adding these outputs turned out to be much simpler than he had anticipated:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Bitcoin::Crypto&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(btc_transaction)&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# create the transaction object&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;btc_transaction&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# add the input from the UTXO&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;add_input&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;utxo&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[[&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;hex&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;a4e407ba6b54106e4bd209704666a2b541b9b03d04ef8cb779aafe18238744e1&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# add all the gift outputs&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;foreach&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$key&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@kids_keys&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;add_output&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;locking_script&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;address&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$key&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;get_public_key&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;get_address&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;100_000&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The last thing to do was to add the output for unused funds and adjust the fee. The difference between input and output values is what the miner gets paid to include the transaction in a block. Without adding the change output, the fee paid would be 49.654 BTC! The higher it is the faster the transaction will be mined, but paying over $1.5 million for a transfer was simply too much. The fee must be proportional to the size of a transaction, so McJingles assumed 100 satoshi per output should be enough. He also set his transaction up for RBF (replace-by-fee), so that he could always bump it later if the blockchain got clogged:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;comment&#34;&gt;# calculate the value of the change output&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$currently_unspent&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;fee&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$wanted_fee&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;100&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@kids_keys&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$change_value&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$currently_unspent&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$wanted_fee&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# add the change output as the last output of the transaction&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;add_output&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;locking_script&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;address&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$change_key&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;get_public_key&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;get_address&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$change_value&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# set replace-by-fee&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;set_rbf&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The transaction object was complete! Now all he had to do was to sign it and print it to the console. The transaction was not yet sent, but the serialized hex string can be broadcast to the Bitcoin network at any time, since the validity of the transaction won&#38;#39;t ever expire!&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Bitcoin::Crypto::Util&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(to_format)&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# sign the only input&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$priv&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;sign_transaction&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;signing_index&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# just to make sure everything is okay - try to verify&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;verify&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;dump&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;to_format&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;hex&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$tx&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;to_serialized&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;];&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When run, the program printed the mnemonic phrase to backup, a user-friendly summary of the transaction and the hex representation of the transaction. But something was missing... Of course, the outputs were supposed to be presents! The list of private keys was left behind in a variable, and without it there was no way to give the outputs to the children.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;        Your mnemonic is &#38;lt;brown bulk hire culture capital hill trim turkey gossip artefact door media argue basic execute slam minute try number daughter music gauge vocal wink&#38;gt;
        and your password is &#38;lt;Christmas&#38;gt;
        Back them up!
        Transaction eed9ce72f2ee78c1f2a675172f7694f400e36ead0591b28b662a5e40fb4b20e1
        version: 1
        size: 10883vB, 43532WU
        fee: 34600 sat (~3.17 sat/vB)
        replace-by-fee: yes
        locktime: 0

        1 inputs:
        P2PK Input
        spending output #0 from a4e407ba6b54106e4bd209704666a2b541b9b03d04ef8cb779aafe18238744e1
        value: 5000000000
        sequence: 0xFFFFFFFD
        locking script: 410452b58be18046f78a0045fe49df56387a03f994ba2ac7a26e17f7d01dc6d346f1bed3979ad35d32a75bb625f6e521f75a1c5983d303ea04bfb43c8b72203a68eeac
        signature script: 483045022100b145a5f46f1fb69a3c7b4d55e1fdc5c2a4556129c2517816f4d8b5cc691414c20220055e5a4649021d26974c1b3b981bfecce9ba05cfae0be10ac136ff02e3e9319601

        347 outputs:
        P2WPKH Output to bc1qum6sd22rmsewwd75lzlynuve8wz0ah2uw2gltu
        value: 100000
        locking script: 0014e6f506a943dc32e737d4f8be49f1993b84fedd5c

        (...)

        P2WPKH Output to bc1qyx43gm2rpdrgk0r70xhpt6ru5sk2xg7xs7lvga
        value: 4965365400
        locking script: 001421ab146d430b468b3c7e79ae15e87ca42ca323c6

        0100000001e144872318feaa79b78cef043db0b941b5a266467009d24b6e10546bba07e4a400(...)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;McJingles had already safely backed up the mnemonic on a piece of paper, so he decided to write another script to print all the private keys generated. Running the same script again would produce a new mnemonic phrase for him. He couldn&#38;#39;t do it as there was always a paper shortage in the toys factory. It should not come as a surprise since all the presents must be wrapped thoroughly, company policy.&lt;/p&gt;

&lt;p&gt;It was getting late and he felt exhausted from deciphering all this output. It would be silly to work with Bitcoin being this tired! Any error you make may cause the coins to be lost forever! Well, with great power... yeah yeah, it was best if he just went to bed and left the rest for another day. Still plenty of time before Christmas!&lt;/p&gt;

&lt;p&gt;... or is there?&lt;/p&gt;

&lt;/div&gt;</summary><updated>2023-12-02T00:00:00Z</updated><category term="Perl"/><author><name>Bartosz Jarzyna</name></author></entry><entry><title>Ornamenting Jingle Bells</title><link href="https://perladvent.org/2023/2023-12-01.html"/><id>https://perladvent.org/2023/2023-12-01.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h3 id=&#34;SITUATION&#34;&gt;SITUATION&lt;/h3&gt;

&lt;p&gt;Santa was growing tired of the music piped into his workshop.&lt;/p&gt;

&lt;p&gt;For example, Jingle Bells was just too ordinary sounding to his ears. It needed a bit of Christmas cheer to pep up the Elves!&lt;/p&gt;

&lt;p&gt;And here is a bit of that tune, that plays at the workshop:&lt;/p&gt;

&lt;audio controls&gt;&lt;source src=&#34;https://github.com/ology/Music/raw/master/jingle-bells-plain.mp3&#34; type=&#34;audio/mp3&#34;&gt;&lt;/audio&gt;

&lt;p&gt;Ordinary to say the least!&lt;/p&gt;

&lt;h3 id=&#34;ASSESSMENT&#34;&gt;ASSESSMENT&lt;/h3&gt;

&lt;p&gt;Santa asked a couple of his more creative elves to come up with a way to brighten things up musically. And they tinkered, the way elves do.&lt;/p&gt;

&lt;p&gt;The cowbell was proposed, but that got shot down quick. Eventually, the most musically experienced elf suggested adding &#38;quot;ornamentation&#38;quot; to certain notes. This she said, included commonly heard things like &#38;quot;trills.&#38;quot; (And it is said that she toured as a roadie, in the 60s with Hendrix, CSN, and others.)&lt;/p&gt;

&lt;p&gt;After some thinking about exactly how to add ornaments to Christmas tunes, a young guitarist elf pointed to &lt;a href=&#34;https://metacpan.org/&#34;&gt;CPAN&lt;/a&gt; and the &lt;a href=&#34;https://metacpan.org/pod/Music::MelodicDevice::Ornamentation&#34;&gt;Music::MelodicDevice::Ornamentation&lt;/a&gt; module, that seemed to fit the bill perfectly.&lt;/p&gt;

&lt;p&gt;Then after reading the examples, the team modified the source and gave it a try... They listened to each of the ornaments and decided to trigger them from a dispatch table, based for the moment, on a loop counter. More sophisticated triggers based on advanced music theory concepts were considered, but Christmas was fast approaching!&lt;/p&gt;

&lt;h3 id=&#34;PROTOTYPE&#34;&gt;PROTOTYPE&lt;/h3&gt;

&lt;p&gt;Here is the prototype code they came up with for Santa. (And it has too much ornamentation for just 16 bars, on purpose for illustration purposes.)&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;code-listing&#34;&gt;&lt;span class=&#34;comment&#34;&gt;#!/usr/bin/env perl&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;strict&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;warnings&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;MIDI::Util&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(setup_score midi_format)&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Music::MelodicDevice::Ornamentation&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# The number of notes before resetting the note counter&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;constant&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;MAX&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;16&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# Sixteen measure fragment of &#38;quot;duration.pitch&#38;quot; notes&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@notes&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;qn.E4 qn.E4 hn.E4&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;qn.E4 qn.E4 hn.E4&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;qn.E4 qn.G4 qn.C4 qn.D4&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;wn.E4&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;qn.F4 qn.F4 qn.F4 qn.F4&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;qn.F4 qn.E4 qn.E4 qn.E4&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;qn.E4 qn.D4 qn.D4 qn.E4&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;hn.D4       hn.G4&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;qn.E4 qn.E4 hn.E4&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;qn.E4 qn.E4 hn.E4&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;qn.E4 qn.G4 qn.C4 qn.D4&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;wn.E4&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;qn.F4 qn.F4 qn.F4 qn.F4&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;qn.F4 qn.E4 qn.E4 qn.E4&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;qn.G4 qn.G4 qn.F4 qn.D4&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;wn.C4&lt;br /&gt;)&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# Setup a new MIDI score&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$melody&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;setup_score&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;bpm&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;140&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# Setup a new musical ornament maker&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ornament&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Music::MelodicDevice::Ornamentation&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;scale_note&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;C&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;scale_name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;major&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# Dazzle with musical ornamentation (based on beat position for now)&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%dazzle&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;number&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ornament&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;mordent&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;number&#34;&gt;7&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ornament&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;trill&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;number&#34;&gt;10&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ornament&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;turn&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;number&#34;&gt;13&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$ornament&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;grace_note&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;-1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# For each duration.note pair...&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$counter&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$note&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@notes&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@note&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;split&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;/\./&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$note&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;    # Add either an ornamented or a &#38;quot;plain&#38;quot; note to the score&lt;br /&gt;&lt;/span&gt;    &lt;span class=&#34;keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;exists&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$dazzle&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$counter&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;})&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$fancy&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$dazzle&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$counter&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@note&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@fancy&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;map&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;midi_format&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;cast&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$fancy&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;comment&#34;&gt;# turn &#39;#&#39; into &#39;s&#39; and &#39;b&#39; into &#39;f&#39;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$melody&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;cast&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@fancy&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$melody&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;midi_format&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@note&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;));&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;    # Increment the counter, or start over if we&#39;ve reached the max&lt;br /&gt;&lt;/span&gt;    &lt;span class=&#34;symbol&#34;&gt;$counter&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$counter&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;MAX&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$counter&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# Write out the fancy score as a MIDI file&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$melody&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;write_score&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;$0-fancy.mid&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;RESULT&#34;&gt;RESULT&lt;/h3&gt;

&lt;p&gt;And here is the result:&lt;/p&gt;

&lt;audio controls&gt;&lt;source src=&#34;https://github.com/ology/Music/raw/master/jingle-bells-fancy.mp3&#34; type=&#34;audio/mp3&#34;&gt;&lt;/audio&gt;

&lt;p&gt;Santa approved the MIDI and the code review, and the team of intrepid elves went to work &lt;b&gt;tastefully&lt;/b&gt; implementing ornamentation into the rest of the music system - all driven by Perl, of course!&lt;/p&gt;

&lt;h3 id=&#34;SYNOPSIS&#34;&gt;SYNOPSIS&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;      $ perl jingle-bells.pl
      $ timidity jingle-bells.pl-fancy.mid  # for unix-like systems&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;PLAYBACK&#34;&gt;PLAYBACK&lt;/h3&gt;

&lt;h4 id=&#34;On-Windows&#34;&gt;On Windows&lt;/h4&gt;

&lt;p&gt;On Microsoft Windows, use the Legacy Media Player. This app just works. MIDI support was removed from the current Microsoft Media Player app.&lt;/p&gt;

&lt;h4 id=&#34;On-unix-like-systems&#34;&gt;On unix-like systems&lt;/h4&gt;

&lt;p&gt;TiMidity++ is a brilliant software synthesizer that can play MIDI files without a hardware synthesizer. It was written in 1995 by elf, Tuukka Toivonen. A file called a SoundFont tells TiMidity what sounds to play for each MIDI note.&lt;/p&gt;

&lt;p&gt;The excellent player, VLC can be used to render MIDI files, too.&lt;/p&gt;

&lt;p&gt;Either should be available from your system package manager (apt, homebrew, etc.).&lt;/p&gt;

&lt;h3 id=&#34;SEE-ALSO&#34;&gt;SEE ALSO&lt;/h3&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://github.com/ology/Music/blob/master/jingle-bells.pl&#34;&gt;The Jingle Bells code!&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/pod/MIDI::Util&#34;&gt;MIDI::Util&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/pod/Music::MelodicDevice::Inversion&#34;&gt;Music::MelodicDevice::Inversion&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/pod/Music::MelodicDevice::Transposition&#34;&gt;Music::MelodicDevice::Transposition&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://timidity.sourceforge.net/&#34;&gt;TiMidity++&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://www.videolan.org/vlc/&#34;&gt;VLC&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;</summary><updated>2023-12-01T00:00:00Z</updated><category term="Perl"/><author><name>Gene Boggs</name></author></entry></feed>