<?xml version="1.0" encoding="us-ascii"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>RJBS Advent Calendar 2010</title><id>http://advent.rjbs.manxome.org/2010/</id><link href="http://advent.rjbs.manxome.org/2010/atom.xml" rel="self"/><updated>2011-10-07T19:53:43-04:00</updated><author><name>Ricardo Signes</name></author><generator uri="http://search.cpan.org/dist/XML-Atom-SimpleFeed/" version="0.86">XML::Atom::SimpleFeed</generator><entry><title>Advent is over!  Go home!</title><link href="http://advent.rjbs.manxome.org/2010/2010-12-25.html"/><id>http://advent.rjbs.manxome.org/2010/2010-12-25.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h2 id=&#34;Merry-Christmas-&#34;&gt;Merry Christmas!&lt;/h2&gt;

&lt;p&gt;It&#38;#39;s Christmas day, folks! Advent is over, and there is no new writing about code for you today.&lt;/p&gt;

&lt;p&gt;I had a lot of fun writing these articles this year. It&#38;#39;s helped me think about why (and whether!) the code I write is useful or usable. Sometimes, I found that the code was too hard to explain, which led to improvements to the code. That&#38;#39;s a frequent side-benefit to writing about code.&lt;/p&gt;

&lt;p&gt;The side-benefit to writing the code itself is realizing all the ways that the code you&#38;#39;ve written up until now could have been better if you had been able to use the thing you&#38;#39;re writing now in writing your old code. Every time I have a new idea, or learn about someone else&#38;#39;s great idea, I want to go back and rewrite all my old code to incorporate it. Fortunately, I can usually resist that temptation.&lt;/p&gt;

&lt;p&gt;A number of articles this year have been about libraries that use frequently discouraged features: global variables and dynamic scope, &lt;code&gt;AUTOLOAD&lt;/code&gt;, operator overloading, Moose&#38;#39;s &lt;a href=&#34;http://en.wikipedia.org/wiki/BETA&#34;&gt;BETA&lt;/a&gt;-style method augmentation, and probably other things I don&#38;#39;t even realize I shouldn&#38;#39;t have used. Perl provides an excellent core language for a lot of general programming problems, but some problems become overcomplex to solve if you stick to the usually-recommended features. By understanding just what all the weird tools do, and when to reach for one of the weird tools, you can avoid getting mired down trying to avoid features that somebody told you were &#38;quot;bad.&#38;quot;&lt;/p&gt;

&lt;p&gt;The scariest weird tools are the ones you have to build yourself. When you announce, &#38;quot;I&#38;#39;m thinking of writing a weird tool to solve a weird edge-case problem that is only 70% solved by existing tools,&#38;quot; the answer you get is usually either &#38;quot;huh?&#38;quot; or &#38;quot;you aren&#38;#39;t going to need it.&#38;quot; Sometimes you still get that when it&#38;#39;s done, but sometimes you&#38;#39;ll have the great joy of seeing people come to understand the problem you were having and how you solved it, and having those people think your idea makes sense.&lt;/p&gt;

&lt;p&gt;So my suggestion is this: when you find yourself trying to solve a new problem, talk to everybody you can about it. If nobody gives you a great solution, settle for great ideas. If you can get one of those, settle for a decent idea. Write about it and ask for feedback. Even if you get a lot of blank stares, implement it anyway and then write about that. You&#38;#39;ll end up a better programmer for it, and the rest of the world might end up with useful code -- or at least an interesting post mortem report.&lt;/p&gt;

&lt;h2 id=&#34;See-Also&#34;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/CPAN&#34;&gt;CPAN&lt;/a&gt;, &lt;a href=&#34;https://metacpan.org/module/App::cpanminus&#34;&gt;App::cpanminus&lt;/a&gt;, &lt;a href=&#34;https://metacpan.org/module/CPANPLUS&#34;&gt;CPANPLUS&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/ExtUtils::MakeMaker&#34;&gt;ExtUtils::MakeMaker&lt;/a&gt;, &lt;a href=&#34;https://metacpan.org/module/Module::Build&#34;&gt;Module::Build&lt;/a&gt;, &lt;a href=&#34;https://metacpan.org/module/Dist::Zilla&#34;&gt;Dist::Zilla&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Test::More&#34;&gt;Test::More&lt;/a&gt;, &lt;a href=&#34;https://metacpan.org/module/TAP::Harness&#34;&gt;TAP::Harness&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;http://www.amazon.com/wishlist/327IWB0NH2TTM&#34;&gt;My Wishlist&lt;/a&gt;&lt;/p&gt;

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

&lt;/div&gt;</summary><updated>2010-12-25T00:00:00-05:00</updated><category term="Perl"/><category term="RJBS"/></entry><entry><title>Rolling Your Own Method Dispatch</title><link href="http://advent.rjbs.manxome.org/2010/2010-12-24.html"/><id>http://advent.rjbs.manxome.org/2010/2010-12-24.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h3 id=&#34;EXPERIMENTAL-CODE-AHEAD&#34;&gt;EXPERIMENTAL CODE AHEAD&lt;/h3&gt;

&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/2010-12-17.html&#34;&gt;Last week&lt;/a&gt;, I wrote about the dangerously experimental Global::Context. This week, I&#38;#39;ll be talking about the transcendentally experimental MRO::Magic.&lt;/p&gt;

&lt;h2 id=&#34;Merry-Christmas-Perl-sucks-&#34;&gt;Merry Christmas! Perl sucks!&lt;/h2&gt;

&lt;p&gt;Lately, just a little more than usual, we&#38;#39;ve been talking at work about the reasons that Perl sucks. That&#38;#39;s not because we think that it&#38;#39;s a terrible language, or that it&#38;#39;s a mistake to use it, or that we don&#38;#39;t like it. Let&#38;#39;s face it, though: all programming languages suck. Sometimes, they suck in subtle and interest ways, and sometimes they&#38;#39;re just absolute stinkers. Most languages that I&#38;#39;ve dealt with have some big problems and some little problems, and learning about them all is lots of fun.&lt;/p&gt;

&lt;p&gt;For a good long while now, I&#38;#39;ve been feeling pretty strongly that one of Perl&#38;#39;s biggest failings, within its own design aesthetic, is that you can&#38;#39;t write per-instance methods. That is, whenever you write &lt;code&gt;$thing-&#38;gt;method&lt;/code&gt;, the method is resolved entirely based on the package associated with &lt;code&gt;$thing&lt;/code&gt; (well, or via &lt;code&gt;UNIVERSAL&lt;/code&gt;). Either &lt;code&gt;$thing&lt;/code&gt; is a package name or it is a reference associated with (&#38;quot;blessed into&#38;quot;) a package name. When you call the &lt;code&gt;method&lt;/code&gt; on it, something like the following happens:&lt;/p&gt;

&lt;ol&gt;

&lt;li&gt;&lt;p&gt;if there&#38;#39;s a subroutine named &lt;code&gt;method&lt;/code&gt; in the package, call it&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;otherwise, check all the packages listed in this package&#38;#39;s &lt;code&gt;@ISA&lt;/code&gt;, recursing through their &lt;code&gt;@ISA&lt;/code&gt;s too&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;otherwise check in &lt;code&gt;UNIVERSAL&lt;/code&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;otherwise, try to call any relevant &lt;code&gt;AUTOLOAD&lt;/code&gt; (via the search path described in 1-3)&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;otherwise, throw an exception&lt;/p&gt;

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

&lt;p&gt;So, imagine you had a &lt;code&gt;Christmas::Present&lt;/code&gt; class, and you wanted to make an instance of it that would be fatal to open before December 25. You &lt;i&gt;can&#38;#39;t&lt;/i&gt; do something like this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$present&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Christmas::Present&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;&lt;span class=&#34;word&#34;&gt;to&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$impatient_relative&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;from&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$self&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;symbol&#34;&gt;$present&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;ADD_METHOD&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;open&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;&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;&#38;nbsp;&#38;nbsp;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;die&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;It isn&#39;t Christmas yet!&#38;quot;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;time&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;&#38;gt;=&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1293256800&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&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;SUPER::open&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;For one thing, &lt;code&gt;ADD_METHOD&lt;/code&gt; doesn&#38;#39;t exist. Then there&#38;#39;s the fact that &lt;code&gt;SUPER&lt;/code&gt; is incredibly tightly bound to packages. To make this work, we need to do something like:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;br /&gt;16:&#38;nbsp;&lt;br /&gt;17:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&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;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Christmas::Present::FatalToPeekers&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;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;base&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Christmas::Present&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;open&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;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;die&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;It isn&#39;t Christmas yet!&#38;quot;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;time&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;&#38;gt;=&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1293256800&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;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;SUPER::open&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;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$present&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Christmas::Present::FatalToPeekers&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;&lt;span class=&#34;word&#34;&gt;to&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$impatient_relative&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;from&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$self&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;This works reasonably well, but only if we know, when writing our code, all the permutations of behavior we might need, so we can make explicit classes. This isn&#38;#39;t always acceptable; sometimes we need special behavior to be figured out at runtime, which means we need to do something like this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$i&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;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$base&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Anonymous::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;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;ADD_METHOD&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;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$object&lt;/span&gt;&lt;span class=&#34;operator&#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;$code&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;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$new_package_name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;join&lt;/span&gt; &lt;span class=&#34;literal&#34;&gt;q{::}&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$base&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$i&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;&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;no&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;strict&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;refs&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;cast&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$new_package_name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;::ISA&#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;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;ref&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$object&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;cast&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$new_package_name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;::$name&#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;span class=&#34;symbol&#34;&gt;$code&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;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;bless&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$object&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$new_package_name&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;..and that means that we end up with a bunch of horribly-named packages being populated, potentially forming weird, long chains of inheritance. Because packages are not garbage collected, these weird-o packages will stick around in memory long after the only instances blessed into them are gone. Some metaprogramming frameworks (like Moose, to name the most important example) build abstractions over this so that you can forget about the horrible crap going on behind the scenes. Furthermore, you can&#38;#39;t call &lt;code&gt;-&#38;gt;SUPER::method&lt;/code&gt; in the &lt;code&gt;$code&lt;/code&gt; passed to &lt;code&gt;ADD_METHOD&lt;/code&gt;, because &lt;code&gt;SUPER::&lt;/code&gt; is broken. Instead, you need to use something like the &lt;a href=&#34;https://metacpan.org/module/SUPER&#34;&gt;SUPER&lt;/a&gt; module to fix the problem -- another abstraction over a colossal hack. When we abstract a colossal hack to fix a stupid language design issue, this is what is commonly called a &#38;quot;design pattern.&#38;quot;&lt;/p&gt;

&lt;h3 id=&#34;Who-cares-&#34;&gt;Who cares?&lt;/h3&gt;

&lt;p&gt;At first, this could seem like a really esoteric problem, only likely to bother people who are doing weird stuff at the edges of good behavior. That&#38;#39;s because Perl&#38;#39;s object model is at least barely adequate for common use -- but it&#38;#39;s not &lt;i&gt;great&lt;/i&gt; for common use, because of the &#38;quot;everything relates to the package&#38;quot; paradigm.&lt;/p&gt;

&lt;p&gt;For example, a very common implementation for objects in Perl is &#38;quot;blessed hashref.&#38;quot; This is convenient, because the object&#38;#39;s attribute values can be stored in the hash. Sometimes, though, people want to store class attributes, too. There&#38;#39;s not a clear place to put this state. At first, you might want to put things in the package itself, in a package variable -- but then it would be visible in global scope, &lt;i&gt;and&lt;/i&gt; as subclasses added new attributes, the state associated with a class is scattered over more and more places, which is just frustrating.&lt;/p&gt;

&lt;p&gt;&#38;quot;Stop!&#38;quot; some purists cry! &#38;quot;Classes shouldn&#38;#39;t really have state! They&#38;#39;re just templates for instances!&#38;quot;&lt;/p&gt;

&lt;p&gt;That&#38;#39;s true, but if it&#38;#39;s true, then it&#38;#39;s also true that they shouldn&#38;#39;t have &lt;code&gt;new&lt;/code&gt; methods. When you write a class, you need two things: a template for new objects and a handle for constructing them. Perl doesn&#38;#39;t provide a &lt;code&gt;new&lt;/code&gt; operator the way that some languages do. Instead, we write &lt;code&gt;new&lt;/code&gt; method that get called on classes -- which are packages -- so that classes are acting both as classes and as factories, but (and this is the problematic part) using the same mechanism. This is what leads to the age-old and always-annoying question:&lt;/p&gt;



&lt;blockquote&gt;

&lt;p&gt;What should we do if somebody calls &lt;code&gt;new&lt;/code&gt; on an object?&lt;/p&gt;



&lt;/blockquote&gt;

&lt;p&gt;In an ideal world, instances and classes wouldn&#38;#39;t share one namespace for methods, so calling a class method on an instance or an instance method on a class would have the same, obvious answer: an &#38;quot;unknown method&#38;quot; exception could be raised.&lt;/p&gt;

&lt;p&gt;If classes were instances (presumably of the notional class Class) then it would make plenty of sense to give them attributes, and it would be easy to dump them, because our classes wouldn&#38;#39;t have to be packages identified by strings. They could be blessed references with attribute state in their guts.&lt;/p&gt;

&lt;h3 id=&#34;Cant-you-just...&#34;&gt;Can&#38;#39;t you just...&lt;/h3&gt;

&lt;p&gt;Yes. Of course. You can get around the template/factory conflation by making two classes and having the &#38;quot;factory&#38;quot; class bless things into the &#38;quot;template&#38;quot; class. This is somewhat clumsy, but it works... but it only solves this problem. It doesn&#38;#39;t help with the &#38;quot;per-instance methods.&#38;quot; In fact, it compounds that problem by doubling the number of classes that might get pseudo-anonymous subclasses generated at runtime and then forgotten about. Those classes might not be generated with the same name in future program runs using the same libraries, so object serialization tools won&#38;#39;t always (ever?) be able to restore objects like this properly. It&#38;#39;s a big mess.&lt;/p&gt;

&lt;h2 id=&#34;Overloading-the-Arrow&#34;&gt;Overloading the Arrow&lt;/h2&gt;

&lt;p&gt;The solution I&#38;#39;d proposed to this quite some time ago was to make it possible to overload the method invocation arrow, so that when an instance method was called like this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;symbol&#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;some_method&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;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;...and we had defined:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Class&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;pragma&#34;&gt;overload&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;method&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;invoke_method&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;...then this would happen:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;word&#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;invoke_method&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;double&#34;&gt;&#38;quot;some_method&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;cast&#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;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;This never happened, mostly because nobody had my passion for the idea &lt;i&gt;and&lt;/i&gt; the necessary ability to add the feature to Perl. Instead, Florian Ragwitz approached me with a number of strategies for implementing it, all of them quite excellent, and he and I have been playing with a real solution on and off for over a year now. It&#38;#39;s called &lt;a href=&#34;https://metacpan.org/module/MRO::Magic&#34;&gt;MRO::Magic&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;MRO::Magic-in-Action&#34;&gt;MRO::Magic in Action&lt;/h2&gt;

&lt;p&gt;MRO::Magic&#38;#39;s goal is to let you &lt;i&gt;totally replace&lt;/i&gt; what happen when a method is called via the arrow operator. As a simple demonstration of it in action, this package implements &lt;a href=&#34;http://en.wikipedia.org/wiki/Prototype-based_programming&#34;&gt;classless OO&lt;/a&gt;:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;br /&gt;16:&#38;nbsp;&lt;br /&gt;17:&#38;nbsp;&lt;br /&gt;18:&#38;nbsp;&lt;br /&gt;19:&#38;nbsp;&lt;br /&gt;20:&#38;nbsp;&lt;br /&gt;21:&#38;nbsp;&lt;br /&gt;22:&#38;nbsp;&lt;br /&gt;23:&#38;nbsp;&lt;br /&gt;24:&#38;nbsp;&lt;br /&gt;25:&#38;nbsp;&lt;br /&gt;26:&#38;nbsp;&lt;br /&gt;27:&#38;nbsp;&lt;br /&gt;28:&#38;nbsp;&lt;br /&gt;29:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&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;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Classless::Root&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;%STATIC&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;MRO::Magic&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;passthru&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;words&#34;&gt;qw(import export DESTROY AUTOLOAD)&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;metamethod&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;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$invocant&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$method&lt;/span&gt;&lt;span class=&#34;operator&#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;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;unless&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;ref&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$invocant&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;die&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;no metaclass method $method on $invocant&#38;quot;&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;unless&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$code&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$STATIC&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$method&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;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$code&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;$invocant&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;cast&#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;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;&#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;$curr&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$invocant&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;while&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$curr&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;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$curr&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;$method&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;$invocant&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;cast&#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;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;exists&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$curr&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;$method&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;symbol&#34;&gt;$curr&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$curr&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;parent&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;&#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;$class&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;ref&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$invocant&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;die&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;unknown method $method called on $class object&#38;quot;&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;comment&#34;&gt;# ...continued below...&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;We use MRO::Magic and tell it that some methods -- primarily important internal Perl-recognized methods -- are passed through to be called normally via package entries. That&#38;#39;s the &lt;code&gt;passthru&lt;/code&gt; argument.&lt;/p&gt;

&lt;p&gt;The rest of the call sets up the code that&#38;#39;s called when somebody calls a method, just as I described above. If it was called on the class name (a &#38;quot;static&#38;quot; method, as some call it) then we look for an entry in &lt;code&gt;%STATIC&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Otherwise, we assume that the object instance is a hashref, and we look for a named entry in the hash. If we find one, that&#38;#39;s the method and we call it. If not, we look for a parent object in the &lt;code&gt;parent&lt;/code&gt; entry and start looking there. In other words, this works almost exactly like JavaScript. So, just like in JavaScript, we might want a basic universal parent object. We just set it up like this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;br /&gt;16:&#38;nbsp;&lt;br /&gt;17:&#38;nbsp;&lt;br /&gt;18:&#38;nbsp;&lt;br /&gt;19:&#38;nbsp;&lt;br /&gt;20:&#38;nbsp;&lt;br /&gt;21:&#38;nbsp;&lt;br /&gt;22:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$Object&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;&lt;span class=&#34;word&#34;&gt;get&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;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$attr&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;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$curr&lt;/span&gt; &lt;span class=&#34;operator&#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;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&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;$curr&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;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$curr&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;$attr&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;exists&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$curr&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;$attr&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;symbol&#34;&gt;$curr&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$curr&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;parent&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;return&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;undef&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;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;set&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;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$attr&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$value&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;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;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$attr&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;$value&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;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;new_child&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;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$parent&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%attrs&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;word&#34;&gt;bless&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%attrs&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;parent&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$parent&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;symbol&#34;&gt;$class&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;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;parent&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;word&#34;&gt;bless&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$Object&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;__PACKAGE__&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Then all we need is a static &lt;code&gt;new&lt;/code&gt; method so we can call &lt;code&gt;Classless::Root-&#38;gt;new&lt;/code&gt;:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;symbol&#34;&gt;$STATIC&lt;/span&gt;&lt;span class=&#34;structure&#34;&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;operator&#34;&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;&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;$class&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%attrs&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;&lt;span class=&#34;symbol&#34;&gt;$Object&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;new_child&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;%attrs&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;h3 id=&#34;Is-this-awesome-&#34;&gt;Is this awesome?&lt;/h3&gt;

&lt;p&gt;Yes, this is awesome. In about fifty lines, we&#38;#39;ve implemented a pretty decent prototype based OO system that isn&#38;#39;t really too shabby. It won&#38;#39;t be affected by &lt;code&gt;UNIVERSAL&lt;/code&gt; or &lt;code&gt;AUTOLOAD&lt;/code&gt; abuse. It won&#38;#39;t ever require polluting the global namespace with throwaway packages or code.&lt;/p&gt;

&lt;p&gt;Best of all, MRO::Magic isn&#38;#39;t just a prototype based OO system, it&#38;#39;s a toolkit for building your own OO systems with different tradeoffs than those made by the standard Perl OO toolkit. With MRO::Magic, there&#38;#39;s more than one way to do it.&lt;/p&gt;

&lt;h3 id=&#34;So-why-isnt-everybody-using-it-&#34;&gt;So why isn&#38;#39;t everybody using it?&lt;/h3&gt;

&lt;p&gt;Well, MRO::Magic isn&#38;#39;t quite &lt;i&gt;done&lt;/i&gt; yet. As Florian and I have looked at other ways to do this, we&#38;#39;ve found a number of places where perl&#38;#39;s internals have gotten in the way. Generally these relate to the way that the method resolution cache works. It isn&#38;#39;t quite fair to call them bugs, since they don&#38;#39;t cause problems with any existing use of Perl, but they sure are weird. One implementation of MRO::Magic worked around these bugs by globally invalidating the entire method resolution cache every time a method was called. Obviously, that&#38;#39;s pretty nuts.&lt;/p&gt;

&lt;p&gt;Beyond that, it will take a while to figure out just how to build a good MRO::Magic kit. The Classless::Root example is a nice example, but it&#38;#39;s kludgy, and would be hard to extend. Things like passing through universal methods or extending the implementation of OO toolkits need to be seriously thought out, which is hard to do when the basics aren&#38;#39;t quite usable.&lt;/p&gt;

&lt;p&gt;In the end, I think that if MRO::Magic become a viable way to write code, almost no one will use it. Instead, a few alternate OO systems will be written using it, and people will use that. I look forward to implementing a few of those myself, even if only for fun. &lt;a href=&#34;https://metacpan.org/module/Data::Hive&#34;&gt;Data::Hive&lt;/a&gt; sure could benefit from it, though, to eliminate its use of &lt;code&gt;AUTOLOAD&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you&#38;#39;re going to play with MRO::Magic, I suggest you do so using the versions of code on GitHub, linked below, rather than the outdated release currently on CPAN. Be warned, though: both are pretty broken, and you might want to ask on IRC what&#38;#39;s supposed to work and what&#38;#39;s known to be busted.&lt;/p&gt;

&lt;h2 id=&#34;See-Also&#34;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/MRO::Magic&#34;&gt;MRO::Magic&lt;/a&gt; - on CPAN; slightly broken, extremely hacky&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://github.com/rjbs/mro-magic&#34;&gt;MRO::Magic&lt;/a&gt; - on Github; very broken, much less hacky&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/MRO::Define&#34;&gt;MRO::Define&lt;/a&gt; - the basis of the CPAN version of MRO::Magic&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://github.com/rafl/object-anon&#34;&gt;Object::Anon&lt;/a&gt; - the basis of the current dev version of MRO::Magic&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Class::Classless&#34;&gt;Class::Classless&lt;/a&gt; - an earlier, &lt;code&gt;AUTOLOAD&lt;/code&gt;-based prototype OO system&lt;/p&gt;

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

&lt;/div&gt;</summary><updated>2010-12-24T00:00:00-05:00</updated><category term="Perl"/><category term="RJBS"/></entry><entry><title>Rolling Your Own Composition</title><link href="http://advent.rjbs.manxome.org/2010/2010-12-23.html"/><id>http://advent.rjbs.manxome.org/2010/2010-12-23.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h2 id=&#34;Beyond-Method-Modifiers&#34;&gt;Beyond Method Modifiers&lt;/h2&gt;

&lt;p&gt;Moose offers a few different kinds of &lt;a href=&#34;https://metacpan.org/module/Moose::Manual::MethodModifiers&#34;&gt;method modifier&lt;/a&gt;, or &#38;quot;advice.&#38;quot; They are before, after, and around. (There&#38;#39;s also &#38;quot;augment&#38;quot; and &#38;quot;override,&#38;quot; which are only sorta kinda method modifiers.) Advice lets you change the behavior of classes in very useful ways, and you can put advice in roles. The problem is that it is often more limited than you might think.&lt;/p&gt;

&lt;p&gt;For example, subclasses of classes with advice can entirely clobber the advice applied to the superclasses&#38;#39; methods. Methods that collect output from multiple pieces of advice are a bit painful to write. &lt;code&gt;augment&lt;/code&gt; solves that fairly well, but can&#38;#39;t be used in roles, greatly limiting that behavior&#38;#39;s usefulness. I wanted to write methods in which all the roles in a class could contribute behavior -- but subclasses-clobber-advice, combined with no-augment-in-roles made this a really annoying problem.&lt;/p&gt;

&lt;p&gt;Sure, it could all be done with &lt;code&gt;around&lt;/code&gt; modifiers, or by doing a lot of crawling of the meta objects, but that would be really annoying to implement over and over, and would be pretty confusing to skim. I wanted to write a library that made the &lt;i&gt;pattern&lt;/i&gt; simple to use, not to just solve my current problem once.&lt;/p&gt;

&lt;p&gt;This calls for specific example.&lt;/p&gt;

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

&lt;p&gt;A very simple example is tagging. We want our objects to have a &lt;code&gt;tags&lt;/code&gt; method that returns a list of tags or keywords that apply to an object, and any roll or subclass can add more without affecting the tags added by anyone else.&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;br /&gt;16:&#38;nbsp;&lt;br /&gt;17:&#38;nbsp;&lt;br /&gt;18:&#38;nbsp;&lt;br /&gt;19:&#38;nbsp;&lt;br /&gt;20:&#38;nbsp;&lt;br /&gt;21:&#38;nbsp;&lt;br /&gt;22:&#38;nbsp;&lt;br /&gt;23:&#38;nbsp;&lt;br /&gt;24:&#38;nbsp;&lt;br /&gt;25:&#38;nbsp;&lt;br /&gt;26:&#38;nbsp;&lt;br /&gt;27:&#38;nbsp;&lt;br /&gt;28:&#38;nbsp;&lt;br /&gt;29:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&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;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Role::Gratis&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;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Moose::Role&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;add_tags&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(free zero-cost)&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;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Role::GiftWrapped&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;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Moose::Role&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;add_tags&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(wrapped brown-paper)&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;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Gift&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;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;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;with&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;Role::Gratis&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Role::GiftWrapped&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;add_tags&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(gift present)&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;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Gift::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;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;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;extends&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Gift&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;add_tags&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(christmas yule)&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;With this class, we&#38;#39;d expect this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;word&#34;&gt;Gift::Christmas&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;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;tags&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;comment&#34;&gt;# return: free, zero-cost, wrapped, brown-paper, gift, present, christmas, yule&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;We can&#38;#39;t just use &lt;code&gt;sub&lt;/code&gt; in classes and &lt;code&gt;around&lt;/code&gt; in the roles, because the subroutine in Gift::Christmas would blow away the advice applied in Gift. We can&#38;#39;t just use around everywhere, because if we tried to apply Role::Gratis to a class without a &lt;code&gt;tags&lt;/code&gt; method, we&#38;#39;d get an error. We can&#38;#39;t even do a silly &#38;quot;provide an empty &lt;code&gt;tags&lt;/code&gt; method&#38;quot; trick, because Role::GiftWrapped would have to do it, too, and they would conflict. (If none of this is clear, consider reading about &lt;a href=&#34;http://rjbs.manxome.org/rubric/entry/1864&#34;&gt;roles, advice, and BUILD in Moose&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;Instead, we can use MooseX::ComposedBehavior to make that &lt;code&gt;add_tags&lt;/code&gt; thing above actually do just what we want. First, we write a TagProvider library:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;TagProvider&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;List::MoreUtils&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(uniq)&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;MooseX::ComposedBehavior&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;-compose&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;sugar_name&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;add_tags&#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;context&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;list&#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;compositor&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;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$results&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;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;uniq&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;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;cast&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$results&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;wantarray&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;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;method_name&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;tags&#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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Then, we add &lt;code&gt;use TagProvider&lt;/code&gt; to each of the classes. That&#38;#39;s it! &lt;code&gt;add_tags&lt;/code&gt; will exist, adding more things to the list of stuff to return. When the &lt;code&gt;tags&lt;/code&gt; method is called (notice it named by the &lt;code&gt;method_name&lt;/code&gt; parameter, above) it calls all the &lt;code&gt;add_tags&lt;/code&gt; blocks and uses the &lt;code&gt;compositor&lt;/code&gt; to combine them. Here, the compositor just makes a big set of all the tags returned by every unit of composition -- roles and classes alike. There&#38;#39;s no need to worry about overriding or clobbering anything.&lt;/p&gt;

&lt;h3 id=&#34;Event-Handling&#34;&gt;Event Handling&lt;/h3&gt;

&lt;p&gt;We&#38;#39;ve been working one some code that generates and responds to events. When an object does the HandlesEvents role, it will have a registry of event names, and each name will have a bunch of handlers, also registered by name. So, we might have a registry like this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;symbol&#34;&gt;$registry&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;&lt;span class=&#34;word&#34;&gt;got_signal&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;log_signal&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;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;die_horribly&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;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;&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;When an object with that registry get a &lt;code&gt;got_signal&lt;/code&gt; event, it calls each of the event handlers.&lt;/p&gt;

&lt;p&gt;A lot of these handlers are going to be really common. For example, every object should be able to respond to a heartbeat event, even if only to respond by making note of it. We want to be able to put implicit event handlers on roles, so that when we compose together actual objects, they start off with all the event handlers that they should. For example, we might write these two packages:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;br /&gt;16:&#38;nbsp;&lt;br /&gt;17:&#38;nbsp;&lt;br /&gt;18:&#38;nbsp;&lt;br /&gt;19:&#38;nbsp;&lt;br /&gt;20:&#38;nbsp;&lt;br /&gt;21:&#38;nbsp;&lt;br /&gt;22:&#38;nbsp;&lt;br /&gt;23:&#38;nbsp;&lt;br /&gt;24:&#38;nbsp;&lt;br /&gt;25:&#38;nbsp;&lt;br /&gt;26:&#38;nbsp;&lt;br /&gt;27:&#38;nbsp;&lt;br /&gt;28:&#38;nbsp;&lt;br /&gt;29:&#38;nbsp;&lt;br /&gt;30:&#38;nbsp;&lt;br /&gt;31:&#38;nbsp;&lt;br /&gt;32:&#38;nbsp;&lt;br /&gt;33:&#38;nbsp;&lt;br /&gt;34:&#38;nbsp;&lt;br /&gt;35:&#38;nbsp;&lt;br /&gt;36:&#38;nbsp;&lt;br /&gt;37:&#38;nbsp;&lt;br /&gt;38:&#38;nbsp;&lt;br /&gt;39:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&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;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;HandlesEvents&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;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Moose::Role&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;implicit_event_handlers&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;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;heartbeat&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;inc_last_beat&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;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;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;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Accruer&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;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Moose::Role&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;with&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;HandlesEvents&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;implicit_event_handlers&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;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;heartbeat&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;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;accrue_value&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;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$self&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;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&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;value&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;value&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;float&#34;&gt;1.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;&#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;&#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;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;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Historian&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;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;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;HandlesEvents&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;implicit_event_handlers&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;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;log_message&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;write_log&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;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;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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Then, say we produce this class:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Historian::Profitable&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;word&#34;&gt;extends&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Historian&#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;with&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Accrurer&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;It will have the following set of handlers implicitly:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&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;log_message&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;write_log&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;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;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;heartbeat&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;inc_last_beat&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;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;accrue_value&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;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;&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;If there&#38;#39;s ever a conflicting set of entries, we should throw an exception. This turns out to be easy with MooseX::ComposedBehavior, too. We just write a ImplicitEventHandlers package and use it in all the packages above. This is what goes in it:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;br /&gt;16:&#38;nbsp;&lt;br /&gt;17:&#38;nbsp;&lt;br /&gt;18:&#38;nbsp;&lt;br /&gt;19:&#38;nbsp;&lt;br /&gt;20:&#38;nbsp;&lt;br /&gt;21:&#38;nbsp;&lt;br /&gt;22:&#38;nbsp;&lt;br /&gt;23:&#38;nbsp;&lt;br /&gt;24:&#38;nbsp;&lt;br /&gt;25:&#38;nbsp;&lt;br /&gt;26:&#38;nbsp;&lt;br /&gt;27:&#38;nbsp;&lt;br /&gt;28:&#38;nbsp;&lt;br /&gt;29:&#38;nbsp;&lt;br /&gt;30:&#38;nbsp;&lt;br /&gt;31:&#38;nbsp;&lt;br /&gt;32:&#38;nbsp;&lt;br /&gt;33:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;MooseX::ComposedBehavior&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;-compose&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;method_name&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;composed_implicit_event_handlers&#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;sugar_name&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;implicit_event_handlers&#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;context&lt;/span&gt;      &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;scalar&#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;compositor&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;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$results&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;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%composed&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;    # Each result is a HOH; first keys, event names; second keys, handler&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;# names&lt;br /&gt;&lt;/span&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;$result&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;$results&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;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;$event_name&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;keys&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$result&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;$this_event&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;symbol&#34;&gt;$composed&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$event_name&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;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&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;$handler_name&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;keys&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;$result&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;$event_name&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;&#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;$this_event&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;$handler_name&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;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;Throwable::X&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;throw&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;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;ident&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;implicit handler composition conflict&#38;quot;&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;&lt;span class=&#34;word&#34;&gt;payload&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;&#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;handler_name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$handler_name&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;&lt;span class=&#34;word&#34;&gt;event_name&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$event_name&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;&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;&#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;br /&gt;&#38;nbsp;&#38;nbsp;&#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;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;&lt;span class=&#34;symbol&#34;&gt;$this_event&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;$handler_name&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;$result&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;$event_name&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}{&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$handler_name&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;br /&gt;&#38;nbsp;&#38;nbsp;&#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;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;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;%composed&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;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;When we want to know an object&#38;#39;s composed event handlers, we just call its &lt;code&gt;composed_implicit_event_handlers&lt;/code&gt; method. We can even make that method a builder for a lazy attribute, if we want to avoid recalculating.&lt;/p&gt;

&lt;h2 id=&#34;Wacky-New-Composition-is-a-Strategy-of-Last-Resort&#34;&gt;Wacky New Composition is a Strategy of Last Resort&lt;/h2&gt;

&lt;p&gt;Building new ways of combining methods across compositional structures is neat. It solves a number of problems that might be hard to solve without it, and it&#38;#39;s a very shiny little tool. It&#38;#39;s also &lt;i&gt;weird&lt;/i&gt;. Code that does this becomes harder to skim, and harder to explain, and more tied to a wonky library implemented in a &lt;a href=&#34;https://github.com/rjbs/moosex-composedbehavior/blob/44532ab8503c5c414d4ac02f7c705bfdf89f839f/lib/MooseX/ComposedBehavior.pm&#34;&gt;clever but unfortunate way&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The existing tools for re-use provided by Moose are very powerful, and can address a huge array of problems. MooseX::ComposedBehavior is useful only when you&#38;#39;re quite sure that you&#38;#39;ve exhausted simple-enough solutions wiht Moose.&lt;/p&gt;

&lt;h2 id=&#34;See-Also&#34;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/MooseX::ComposedBehavior&#34;&gt;MooseX::ComposedBehavior&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;http://rjbs.manxome.org/rubric/entry/1864&#34;&gt;roles, advice, and BUILD in Moose&lt;/a&gt; - an introductory blog post about why composed behavior can be confusing&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;http://rjbs.manxome.org/rubric/entry/1865&#34;&gt;composing your own behavior across Moose class structures&lt;/a&gt; - a more detailed follow-up about MooseX::ComposedBehavior&lt;/p&gt;

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

&lt;/div&gt;</summary><updated>2010-12-23T00:00:00-05:00</updated><category term="Perl"/><category term="RJBS"/></entry><entry><title>A Lousy Locker (...because Worse is Better!)</title><link href="http://advent.rjbs.manxome.org/2010/2010-12-22.html"/><id>http://advent.rjbs.manxome.org/2010/2010-12-22.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h2 id=&#34;Optimizing-for-Failure&#34;&gt;Optimizing for Failure&lt;/h2&gt;

&lt;p&gt;A long, long time ago, we had some services that ran only on one server. This was fine, because they produced minimal load and we never needed to scale up their volume. This was terrible, because it meant that if that server went down, all those services stopped. Even though the load was very low, we had to run redundant servers to avoid having single points of failure. We found ourselves doing this over and over as we identified more weird old pieces of architecture that worked this way.&lt;/p&gt;

&lt;p&gt;When you take a job that you know can only run one at a time and make it redundant, you need to be really careful about race conditions and other kinds of contention. For example, say you&#38;#39;re going to send out digests of mailing lists, and you&#38;#39;re going to do it something like this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$lists&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;MLM::List&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;get_iterator&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;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;$mailing_list&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$lists&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;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@undigested_messages&lt;/span&gt; &lt;span class=&#34;operator&#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;word&#34;&gt;messages&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;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;has_been_digested&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;&lt;span class=&#34;structure&#34;&gt;});&lt;/span&gt;&lt;br /&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;$digest&lt;/span&gt; &lt;span class=&#34;operator&#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;word&#34;&gt;build_digest&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@undigested_messages&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$digest&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;sent&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&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;word&#34;&gt;mark_digested&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@undigested_messages&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;This is pretty reasonable, as long as it&#38;#39;s only running once, in one place. Once we&#38;#39;ve got it running in two places at once, there&#38;#39;s the possibility that the two services hit the same list at the same time, or nearly the same time, and each send out a digest -- maybe identical, or maybe not. The pattern that had been used to block this sort of condition in some places in the code base had been to get a &lt;a href=&#34;http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_get-lock&#34;&gt;MySQL lock&lt;/a&gt;:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;br /&gt;16:&#38;nbsp;&lt;br /&gt;17:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$lists&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;MLM::List&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;get_iterator&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;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;$mailing_list&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$lists&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;symbol&#34;&gt;$DB&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;get_mysql_lock&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;digest &#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$mailing_list&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&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;@undigested_messages&lt;/span&gt; &lt;span class=&#34;operator&#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;word&#34;&gt;messages&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;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;has_been_digested&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;&lt;span class=&#34;structure&#34;&gt;});&lt;/span&gt;&lt;br /&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;$digest&lt;/span&gt; &lt;span class=&#34;operator&#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;word&#34;&gt;build_digest&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@undigested_messages&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$digest&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;sent&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&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;word&#34;&gt;mark_digested&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@undigested_messages&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$DB&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;release_mysql_lock&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;digest &#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$mailing_list&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;id&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;...and the &lt;code&gt;get_mysql_lock&lt;/code&gt; call would become a MySQL &lt;code&gt;GET_LOCK&lt;/code&gt; call, and so on. Unfortunately, in quite a few situations, including the one above, this is not a useful locking strategy. For one thing, in MySQL you can only hold one named lock at once, any accidental nesting of locks will be a catastrophe. More generally, native database locks usually associate with a database connection. If the database handle dies during the execution of &lt;code&gt;$digest-&#38;gt;build_digest&lt;/code&gt;, nothing will happen in reaction to that until we try to mark the posts digested in the database. So, before we&#38;#39;ve even begun sending mail, another service elsewhere may begin work on this job -- because we&#38;#39;ve lost our lock. Native database locks are only safe when the only changes that the service may affect are inside a transaction on the same connection as the lock.&lt;/p&gt;

&lt;p&gt;What this really means is that you should take advantage of that, and put all your units of work into correctly-sized transactions, and you should take advantage of the &lt;i&gt;incredible&lt;/i&gt; safety provided by database transactions. Sometimes, though, that&#38;#39;s just a lot more work than you can afford to do. Sometimes you need a quick and dirty solution to contention, even in the face of unsafe code. After all, you might not be able to prevent every problem with not-quite-transactional code, but at least you can ensure that it won&#38;#39;t be run four times at once!&lt;/p&gt;

&lt;h2 id=&#34;The-Simplest-Test-That-Could-Possibly-Work&#34;&gt;The Simplest Test That Could Possibly Work&lt;/h2&gt;

&lt;p&gt;What we needed, for dealing with these contentious services, was a simple network-visible semaphore that would say &#38;quot;I have locked &lt;code&gt;X&lt;/code&gt;; attempt no work there.&#38;quot; It had to be impossible to get a lock if someone else had a lock, and it had to be really cheap to add locks to exisiting code -- no significant rearchitecture could be required. Everything else was secondary. Lingering locks, for example, were not a big problem, we could purge them as needed. We didn&#38;#39;t want to worry about lock granularity (locking a whole resource or only part of it). Either a resource was locked, or not.&lt;/p&gt;

&lt;p&gt;The solution was dead simple. We made this table:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;synStatement&#34;&gt;CREATE&lt;/span&gt; &lt;span class=&#34;synSpecial&#34;&gt;TABLE&lt;/span&gt; semaphores (&lt;br /&gt;&#38;nbsp;&#38;nbsp;id int PRIMARY KEY AUTO_INCREMENT,&lt;br /&gt;&#38;nbsp;&#38;nbsp;lockstring &lt;span class=&#34;synType&#34;&gt;varchar&lt;/span&gt;(&lt;span class=&#34;synConstant&#34;&gt;128&lt;/span&gt;) &lt;span class=&#34;synSpecial&#34;&gt;UNIQUE&lt;/span&gt;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;created datetime &lt;span class=&#34;synStatement&#34;&gt;NOT&lt;/span&gt; &lt;span class=&#34;synSpecial&#34;&gt;NULL&lt;/span&gt;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;expires datetime &lt;span class=&#34;synStatement&#34;&gt;NOT&lt;/span&gt; &lt;span class=&#34;synSpecial&#34;&gt;NULL&lt;/span&gt;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;locked_by text &lt;span class=&#34;synStatement&#34;&gt;NOT&lt;/span&gt; &lt;span class=&#34;synSpecial&#34;&gt;NULL&lt;/span&gt;&lt;br /&gt;);&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;To get a lock, you&#38;#39;d insert a row into the table. If a row for that lockstring already existed, the unique constraint would prevent the insertion. That&#38;#39;s it! It&#38;#39;s almost ridiculously simple, but it works:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;br /&gt;16:&#38;nbsp;&lt;br /&gt;17:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$locker&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;MLM::Locker&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;$lists&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;MLM::List&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;get_iterator&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;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;$mailing_list&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$lists&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;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$lock&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$locker&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;lock&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;digest &#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$mailing_list&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&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;@undigested_messages&lt;/span&gt; &lt;span class=&#34;operator&#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;word&#34;&gt;messages&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;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;has_been_digested&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;&lt;span class=&#34;structure&#34;&gt;});&lt;/span&gt;&lt;br /&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;$digest&lt;/span&gt; &lt;span class=&#34;operator&#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;word&#34;&gt;build_digest&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@undigested_messages&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$digest&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;sent&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&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;word&#34;&gt;mark_digested&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@undigested_messages&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;We don&#38;#39;t even need to clear the lock. It will be automatically released when we finish marking messages digested and &lt;code&gt;$lock&lt;/code&gt; goes out of scope:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;br /&gt;16:&#38;nbsp;&lt;br /&gt;17:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;DESTROY&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;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;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;local&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;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;unless&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;locked_by&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;pid&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;&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;unlock&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;unlock&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;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;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$dbh&lt;/span&gt;   &lt;span class=&#34;operator&#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;locker&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;dbh&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;$table&lt;/span&gt; &lt;span class=&#34;operator&#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;locker&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;table&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&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;$rows&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$dbh&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;do&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;DELETE FROM $table WHERE id=?&#38;quot;&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;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;lock_id&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;Carp::confess&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;error releasing lock&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$rows&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;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;In reality, we&#38;#39;d have some exception handling to deal with failure to lock, so that we could continue on gracefully to the next list. That wouldn&#38;#39;t cover every case, though. What if we hit an entirely unexpected error after getting our lock, and perl exited without releasing the lock. To take an extreme example, what if the server lost power? If we&#38;#39;d been using a database lock that was tied to our database connection, everything would be fine: our connection&#38;#39;s death would let the lock die, and the work would now be available to anyone. The same thing would apply if we were using filesystem locks or, heaven help us, network filesystem locks. The death of our client would release the lock.&lt;/p&gt;

&lt;p&gt;We don&#38;#39;t have any concept of an active locking client, though. That&#38;#39;s part of the strength of the design: failure of one connection doesn&#38;#39;t prevent an otherwise healthy service from continuing to work. The trade off is that now, even though the server is dead, its lock it sitting there, preventing other services from picking up the work. That&#38;#39;s why every lock has an expiration time. Every once in a while a cron job runs and just deletes expired locks.&lt;/p&gt;

&lt;p&gt;This means that sometimes resources are locked for quite a lot longer than they should be. Sometimes seconds, sometimes minutes, or even an hour. That&#38;#39;s okay, because we knew that could happen going in, we planned for it, and &lt;i&gt;we don&#38;#39;t care&lt;/i&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/DBIx::Locker&#34;&gt;DBIx::Locker&lt;/a&gt; is a really crude tool that is often exactly the wrong thing for the job -- but sometimes it&#38;#39;s not. Sometimes the right tool is a big, dumb hammer. Part of the challenge (and fun) of writing reasonable systems is knowing when a big, dumb hammer is good enough, and knowing when you need something better.&lt;/p&gt;

&lt;h2 id=&#34;See-Also&#34;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/DBIx::Locker&#34;&gt;DBIx::Locker&lt;/a&gt;&lt;/p&gt;

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

&lt;/div&gt;</summary><updated>2010-12-22T00:00:00-05:00</updated><category term="Perl"/><category term="RJBS"/></entry><entry><title>Testing with Classes, Roles, and Antlers</title><link href="http://advent.rjbs.manxome.org/2010/2010-12-21.html"/><id>http://advent.rjbs.manxome.org/2010/2010-12-21.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h2 id=&#34;Reuse-reuse-reuse&#34;&gt;Reuse, reuse, reuse&lt;/h2&gt;

&lt;p&gt;Sometimes, I hear the advice that it&#38;#39;s okay to write absolutely horrible, terrible, copy and paste code in your tests, because hey, they&#38;#39;re just tests. I would like, tentatively, to call that bad advice.&lt;/p&gt;

&lt;p&gt;There&#38;#39;s definitely wisdom in the idea that you don&#38;#39;t usually want to spend all your time building elegantly constructed test suites when you&#38;#39;re still trying to get your start-up off the ground. Getting working code out the door is a laudable goal, but it has to be balanced against your ability to get &lt;i&gt;more&lt;/i&gt; working code out the door &lt;i&gt;later&lt;/i&gt;, and that means that every part of your project needs to be maintainable.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;http://en.wikipedia.org/wiki/Extreme_Programming&#34;&gt;Extreme Programming&lt;/a&gt; exhorts us to &lt;a href=&#34;http://www.extremeprogramming.org/rules/refactor.html&#34;&gt;refactor mercilessly&lt;/a&gt;, and if we&#38;#39;re going to accept that advice (as I think we should) then we need to write code that&#38;#39;s planning to be refactored later. That means that as often as possible we should even our sloppy testing code into units that are at least sort of suitable for refactoring. At the start that might just mean putting &lt;code&gt;sub{}&lt;/code&gt; around a bunch of code instead of copying it over and over. Later, maybe it means putting that sub into a shared file instead of copying it between files. These are the same tools we use when making our non-test code reusable and refactorable.&lt;/p&gt;

&lt;p&gt;Another technique we use all the time to make code easy to maintain, reuse, and extend is object orientation. Classes are pretty good units of abstraction. Why don&#38;#39;t we see them all that often in our tests, in Perl? I think the basic reason is that it&#38;#39;s too hard to get started writing our tests as classes. Object orientation in Perl has traditionally been a bit of a drag, object-oriented testing moreso. You have to write a class, put it somewhere under &lt;i&gt;./t/lib&lt;/i&gt;, load it somewhere else, and do something to make it run. Since the class needs special facilities to be a test, you end up using some framework for writing test classes, and that&#38;#39;s another class building system you need to learn.&lt;/p&gt;

&lt;p&gt;In the last few years, &lt;a href=&#34;http://moose.perl.org/&#34;&gt;Moose&lt;/a&gt; has helped usher in a revolution in how we write OO code in Perl, giving us one class-building system that&#38;#39;s good enough for just about everything. Staring at some lousy tests and wishing for a good way to write reusable object oriented test code, I realized that Moose was probably good enough for writing tests, too. I ran with the idea and produced Test::Routine.&lt;/p&gt;

&lt;h2 id=&#34;The-Simplest-Test-That-Could-Possibly-Work&#34;&gt;The Simplest Test That Could Possibly Work&lt;/h2&gt;

&lt;p&gt;To give you an example of how easy it is to write an object-oriented test with Test::Routine, here&#38;#39;s a trivial test without Test::Routine:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&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;Test::More&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;subtest&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;everything_is_okay&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;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$x&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;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;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$x&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;double&#34;&gt;&#38;quot;everything is okay&#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;done_testing&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;...and here it is, using Test::Routine:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Test::Routine&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;Test::Routine::Util&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;Test::More&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;test&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;everything_is_okay&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;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$x&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;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;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$x&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;double&#34;&gt;&#38;quot;everything is okay&#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;test_me&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;done_testing&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;So, we&#38;#39;ve added one line of code to go from an entirely imperative test to an object-oriented test. Of course, you can&#38;#39;t really tell, because we&#38;#39;re not getting any benefit from it. What if we did this, though:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Test::Routine&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;Test::Routine::Util&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;Test::More&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;x&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;ro&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &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;single&#34;&gt;&#39;Int&#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;number&#34;&gt;100&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;test&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;everything_is_okay&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;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$self&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;&lt;span class=&#34;word&#34;&gt;is&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;x&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;double&#34;&gt;&#38;quot;everything is okay&#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;test_me&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;test_me&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;({&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;10&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;});&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;done_testing&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Now we&#38;#39;re getting somewhere! We&#38;#39;ve given our test object an attribute, and we use that attribute in our tests, rather than a constant. Then when we run &lt;code&gt;test_me&lt;/code&gt; twice, we&#38;#39;re constructing two test objects and running their all their tests. In other words, we&#38;#39;ll run the &lt;code&gt;everything_is_okay&lt;/code&gt; test twice, once an object where &lt;code&gt;x&lt;/code&gt; is 100 (the default) and once where it is 10.&lt;/p&gt;

&lt;p&gt;We could also add methods to our tests and use those just like you&#38;#39;d expect:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;x&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;ro&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &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;single&#34;&gt;&#39;Int&#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;number&#34;&gt;100&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;is_square&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;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$value&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;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;sqrt&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$value&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;sqrt&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$value&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;test&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;everything_is_okay&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;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$self&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;&lt;span class=&#34;word&#34;&gt;is&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;x&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;double&#34;&gt;&#38;quot;everything is okay&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;ok&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;is_square&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;x&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;double&#34;&gt;&#38;quot;x is square&#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;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;h3 id=&#34;Combining-Routines&#34;&gt;Combining Routines&lt;/h3&gt;

&lt;p&gt;Something that I haven&#38;#39;t mentioned yet is that when we use Test::Routine, it doesn&#38;#39;t mean we&#38;#39;re writing a class. It means we&#38;#39;re writing a &lt;i&gt;role&lt;/i&gt;. That means we can write multiple routines and combine them. Here are three packages we might write:&lt;/p&gt;

&lt;p&gt;&lt;i&gt;t/lib/Factory/Gift.pm&lt;/i&gt;:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;br /&gt;16:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;t::lib::Factory::Gift&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::Role&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;Gift&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;requires&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;giver&#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;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;gift&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;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;&lt;span class=&#34;word&#34;&gt;Gift&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;from&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;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;giver&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;name&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;to&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Gift Recipient&#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;value&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;rand&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;giver&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;budget&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;structure&#34;&gt;});&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;&lt;i&gt;t/lib/Routine/Giver.pm&lt;/i&gt;:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;br /&gt;16:&#38;nbsp;&lt;br /&gt;17:&#38;nbsp;&lt;br /&gt;18:&#38;nbsp;&lt;br /&gt;19:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Test::Routine&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;Test::Tolerant&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;requires&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;build_giver&#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;word&#34;&gt;giver&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;does&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Gift::Giver&#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;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_giver&#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;word&#34;&gt;test&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;giver_is_acceptable&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;&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;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$giver&lt;/span&gt; &lt;span class=&#34;operator&#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;giver&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;is_tol&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$giver&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;budget&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;words&#34;&gt;qw(5 or_more)&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;double&#34;&gt;&#38;quot;giver is not cheapskate&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;ok&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$giver&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;celebrates_christmas&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;humbugs need not apply&#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;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;&lt;i&gt;t/basic.t&lt;/i&gt;:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Test::Routine&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;Test::Routine::Util&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;Test::More&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;build_giver&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;Gift::Giver&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;name&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Scott Calvin&#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;budget&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;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;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;celebrates_christmas&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;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;with&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;t::lib::Factory::Gift&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;t::Routine::Giver&#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;run_me&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;The test file that gets run by &lt;code&gt;make test&lt;/code&gt; is the last one, but you might notice that it doesn&#38;#39;t actually have any tests in it! It gets its tests from the other roles it composes -- namely, &lt;code&gt;t::Routine::Giver&lt;/code&gt;. That role gives the test object a &lt;code&gt;giver&lt;/code&gt; attribute and sets up a test to make sure the giver is acceptable, but it doesn&#38;#39;t set up a default. Instead, it requires that the default be provided by a builder method implemented elsewhere. We&#38;#39;ve implemented it in &lt;i&gt;t/basic.t&lt;/i&gt;.&lt;/p&gt;

&lt;p&gt;We also compose &lt;code&gt;t::lib::Factory::Gift&lt;/code&gt;, which isn&#38;#39;t even a Test::Routine role, but just a plain old Moose role. If we add more tests later, they can use the factory&#38;#39;s &lt;code&gt;gift&lt;/code&gt; method to get gifts built based on the fixture (the &lt;code&gt;giver&lt;/code&gt;) provided by the rest of the composed test.&lt;/p&gt;

&lt;h2 id=&#34;Theres-More-Than-One-Way-to-Do-It-&#34;&gt;There&#38;#39;s More Than One Way to Do It!&lt;/h2&gt;

&lt;p&gt;I&#38;#39;ve shown two pretty extreme use cases of Test::Routine: using it for almost nothing, and using it for fairly complex composition. One of the things that makes it such a useful library is that it can be used in lots of different ways not seen here. It doesn&#38;#39;t have many opinions on how it should be used, it&#38;#39;s just a simple tool with lots of possible applications.&lt;/p&gt;

&lt;p&gt;Better yet, it&#38;#39;s not much more than plain old Moose roles, with all the same rules in play. The extra bit of code that makes Test::Routine roles testable is very small and easy to understand. You can start by writing test files that look almost exactly like what you&#38;#39;re doing now, but later, when you want to refactor or update your tests, you&#38;#39;ll have far more options available to do it.&lt;/p&gt;

&lt;h2 id=&#34;See-Also&#34;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Test::Routine&#34;&gt;Test::Routine&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;http://rjbs.manxome.org/rubric/entry/1858&#34;&gt;more on Test::Routine&lt;/a&gt;&lt;/p&gt;

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

&lt;/div&gt;</summary><updated>2010-12-21T00:00:00-05:00</updated><category term="Perl"/><category term="RJBS"/></entry><entry><title>Shuffle Smarter, Not Harder</title><link href="http://advent.rjbs.manxome.org/2010/2010-12-20.html"/><id>http://advent.rjbs.manxome.org/2010/2010-12-20.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h3 id=&#34;NOT-ON-THE-CPAN&#34;&gt;NOT ON THE CPAN&lt;/h3&gt;

&lt;p&gt;Today&#38;#39;s article is about code not found on the CPAN. In fact, this code won&#38;#39;t even work anymore on many new compiles of &lt;code&gt;perl&lt;/code&gt;. It&#38;#39;s still an interesting idea, and maybe I will rewrite it to use the scripting bridge in some other way -- either via PerlObjCBridge or some non-Perl language with a working scripting bridge.&lt;/p&gt;

&lt;h2 id=&#34;Albums-as-Atomic-Units&#34;&gt;Albums as Atomic Units&lt;/h2&gt;

&lt;p&gt;Some recording artists are still refusing to be sold through the iTunes music store, in part because they can&#38;#39;t restrict shoppers from buying single tracks. That is, some artists want to say, &#38;quot;I made an album. You can buy the whole album, or you can go buy something else. You can&#38;#39;t just buy track nine.&#38;quot; I can really get behind that. These guys are artists, and they don&#38;#39;t want people to &lt;i&gt;think&lt;/i&gt; they&#38;#39;ve experienced their work if they&#38;#39;ve really just experienced part of it, out of context.&lt;/p&gt;

&lt;p&gt;Unfortunately, the idea that &#38;quot;music is organized into tracks, and tracks can be shuffled arbitrarily&#38;quot; is getting more and more popular with the rise of MP3 players. Years ago, I realized that because of the way I built my &#38;quot;smart playlists&#38;quot; in iTunes, I was very rarely hearing large parts of albums that I liked, and that I was almost &lt;i&gt;never&lt;/i&gt; listening to whole albums. When I realized this, I spent a few days only listening to whole albums, and it was fantastic. After that, I felt sad that it was so hard to keep doing that daily.&lt;/p&gt;

&lt;p&gt;iTunes didn&#38;#39;t have a way to make smart playlists that included whole albums. The iPod had recently lost the ability to shuffle by albums, too -- making listening to classical music much harder.&lt;/p&gt;

&lt;p&gt;After sulking for a while, I realized that this would be really easy to fix by stepping outside the smart playlist editor and reaching for &lt;a href=&#34;https://metacpan.org/module/Mac::Glue&#34;&gt;Mac::Glue&lt;/a&gt; to analyze my library and build a playlist by hand.&lt;/p&gt;

&lt;p&gt;The code that follows does this, and I will sprinkle annotations explaining how it all works.&lt;/p&gt;

&lt;h2 id=&#34;albumen&#34;&gt;&lt;i&gt;albumen&lt;/i&gt;&lt;/h2&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&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;Getopt::Long::Descriptive&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;List::Util&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(sum)&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;Mac::Glue&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(:glue)&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;$opt&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$usage&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;describe_options&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;%c %o&#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;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;interactive|i!&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;prompt for each album&#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;br /&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$itunes&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Mac::Glue&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;single&#34;&gt;&#39;iTunes&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;So far, we&#38;#39;ve prepared to run our program, and gotten our handle on the iTunes automation &#38;quot;glue.&#38;quot;&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$pl&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$itunes&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;obj&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;playlist&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;whose&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;word&#34;&gt;equals&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Regularer&#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;get&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;$albumen&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$itunes&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;obj&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;playlist&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;whose&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;word&#34;&gt;equals&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Albumen&#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;get&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;die&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;couldn&#39;t find target playlist&#38;quot;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$albumen&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;We&#38;#39;re going to consider as our input tracks in the &#38;quot;Regularer&#38;quot; playlist, which is a smart playlists that filters out stuff that, more or less, isn&#38;#39;t really music, like spoken word, podcasts, and jazz. When we build our playlist out, it will go into the playlist &#38;quot;Albumen.&#38;quot;&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&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;$tracks&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$itunes&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;obj&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;track&lt;/span&gt;     &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;gAll&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;playlist&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$albumen&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;prop&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;index&#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;get&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;br /&gt;&#38;nbsp;&#38;nbsp;&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;word&#34;&gt;delete&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$tracks&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;get&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;double&#34;&gt;&#38;quot;getting tracks\n&#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;@tracks&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$pl&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;obj&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;tracks&#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;get&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;We empty out the old playlist from Album and get our new set of tracks to consider adding.&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;br /&gt;16:&#38;nbsp;&lt;br /&gt;17:&#38;nbsp;&lt;br /&gt;18:&#38;nbsp;&lt;br /&gt;19:&#38;nbsp;&lt;br /&gt;20:&#38;nbsp;&lt;br /&gt;21:&#38;nbsp;&lt;br /&gt;22:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%album&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;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;$track&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;symbol&#34;&gt;@tracks&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;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$trackid&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$track&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;prop&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;database ID&#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;get&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;$album&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$track&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;prop&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;album&#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;get&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;$artist&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$track&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;prop&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;compilation&#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;get&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;&lt;span class=&#34;operator&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;-&#39;&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;&lt;span class=&#34;operator&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$track&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;prop&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;artist&#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;get&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;next&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;defined&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$album&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;defined&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$artist&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;next&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;length&lt;/span&gt;  &lt;span class=&#34;symbol&#34;&gt;$album&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;length&lt;/span&gt;  &lt;span class=&#34;symbol&#34;&gt;$artist&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&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;$rec&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$album&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$album&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$artist&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;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;printf&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;storing record of $trackid ($album/$artist); %s left\n&#38;quot;&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;@tracks&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&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;symbol&#34;&gt;$rec&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;word&#34;&gt;id&lt;/span&gt;     &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$trackid&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;rating&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;scalar&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$track&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;prop&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;rating&#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;get&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;played&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;scalar&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$track&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;prop&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;played date&#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;get&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;comment&#34;&gt;# epoch sec&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Here, we build up &lt;code&gt;%album&lt;/code&gt;, a hash in which keys are album/artist pairs (using the justly-maligned list-in-hash-subscript-means-join-with-&lt;code&gt;$;&lt;/code&gt; feature) and values are arrayrefs of tracks. Now that we&#38;#39;ve got a data structure suitable for building our playlist, we can really get to work.&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$DEFAULT_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;number&#34;&gt;30&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;86_400&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;%avg_age&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;label&#34;&gt;ALBUM:&lt;/span&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;$key&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;keys&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%album&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;my&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$album&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$artist&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;split&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;symbol&#34;&gt;$key&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;printf&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;considering (%s/%s)\n&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$album&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$artist&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&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;@tracks&lt;/span&gt; &lt;span class=&#34;operator&#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;$album&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;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@tracks&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;4&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;printf&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;skipping (%s/%s); too few tracks\n&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$album&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$artist&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;delete&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$album&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;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;next&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;ALBUM&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;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;We start iterating through all the albums we&#38;#39;ve got to consider, and skip any album with fewer than four tracks available. Once, I skipped any album that didn&#38;#39;t have all of its tracks available, but this ended up causing problems with albums with some tracks that were not &#38;quot;Regularer&#38;quot; music, like hip hop albums with &#38;quot;spoken word&#38;quot; tracks, or with albums that had no &#38;quot;total tracks&#38;quot; tags.&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@lp_dates&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;core&#34;&gt;undef&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;$_&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;msng&#39;&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;symbol&#34;&gt;$DEFAULT_TIME&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;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&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;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;played&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;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;@tracks&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&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;$avg_age&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;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;sum&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@lp_dates&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;@lp_dates&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;$avg_age&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;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$avg_age&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&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;$avg_age&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;&#38;lt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;86_400&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;30&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;printf&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;skipping (%s/%s); too recent\n&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$album&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$artist&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;delete&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$album&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;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;next&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;ALBUM&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;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Next, we figure out the average &#38;quot;last listened to&#38;quot; of the album. If we&#38;#39;ve listened to the whole thing recently, or to a lot of its tracks recently, we remove it from the playlist. This works really well, because iPod and iTunes will update the &#38;quot;last played,&#38;quot; so the next time you sync your iPod and run &lt;i&gt;albumen&lt;/i&gt;, the albums you&#38;#39;ve listened to since your last sync will be replaced.&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@ratings&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;grep&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;number&#34;&gt;0&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;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;rating&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;@tracks&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;$avg_rating&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;sum&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@ratings&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;@ratings&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@ratings&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&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;$avg_rating&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$avg_rating&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;&#38;lt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;65&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;printf&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;skipping (%s/%s); too lousy\n&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$album&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$artist&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;delete&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$album&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;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;next&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;ALBUM&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;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;printf&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;keeping (%s/%s) @ %s\n&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$album&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$artist&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$avg_rating&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;(n/a)&#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;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;After removing albums we&#38;#39;ve heard too recently, we remove albums we don&#38;#39;t want to hear ever again. We get an average of ratings, skipping unrated tracks, and drop the album if it&#38;#39;s got under a three and a quarter star rating. (The stars displayed in iTunes are counted as 20 &#38;quot;rating points&#38;quot; in the scripting interface.)&lt;/p&gt;

&lt;p&gt;Now we&#38;#39;ve gotten down to just albums we&#38;#39;ll consider putting in the playlist: nothing we&#38;#39;ve just listened to, and nothing we dislike. Now it&#38;#39;s time to start building the playlist:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$total_size&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;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%seen_artist&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;%included_track&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;label&#34;&gt;ADDITION:&lt;/span&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;$key&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;sort&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$avg_age&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$b&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;&#38;lt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$avg_age&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$a&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;keys&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%album&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;my&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$album&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$artist&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;split&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;symbol&#34;&gt;$key&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;$artist&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;ne&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;-&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$seen_artist&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$artist&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;printf&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;skipping (%s/%s); already have album by this artist\n&#38;quot;&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;&lt;span class=&#34;symbol&#34;&gt;$album&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$artist&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;next&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;ADDITION&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;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;We&#38;#39;ll use &lt;code&gt;%seen_artist&lt;/code&gt; to keep track of artists whom we&#38;#39;ve added to our playlist already. If we&#38;#39;ve already added a &lt;a href=&#34;http://en.wikipedia.org/wiki/Negativland&#34;&gt;Negativland&lt;/a&gt; album, we won&#38;#39;t add another one. I had to add this feature after I ended up, one day, with a playlist of nothing but Elvis Costello. It wasn&#38;#39;t &lt;i&gt;bad&lt;/i&gt; so much as overwhelming.&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&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;$opt&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;interactive&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;local&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;magic&#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;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;for&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;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;print&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;include ($album by $artist)? &#38;quot;&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;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$line&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;readline&#34;&gt;&#38;lt;STDIN&#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;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;next&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;ADDITION&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$line&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;/^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;&lt;span class=&#34;word&#34;&gt;redo&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$line&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;/^y/&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;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Sometimes, you just want to be able to veto something that would otherwise show up. Maybe it&#38;#39;s time for me to listen to Tragic Kingdom again, but I&#38;#39;m just not ready to hear it again. Interactive mode lets me tell &lt;i&gt;albumen&lt;/i&gt; to wait for next time.&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;br /&gt;16:&#38;nbsp;&lt;br /&gt;17:&#38;nbsp;&lt;br /&gt;18:&#38;nbsp;&lt;br /&gt;19:&#38;nbsp;&lt;br /&gt;20:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$seen_artist&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$artist&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;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@tracks&lt;/span&gt; &lt;span class=&#34;operator&#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;$album&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;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&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;$track&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@tracks&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;$t&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$itunes&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;obj&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;track&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;whose&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;database id&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;equals&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$track&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;id&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;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;get&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;symbol&#34;&gt;$total_size&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;+=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$t&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;prop&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;size&#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;get&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;comment&#34;&gt;# in bytes&lt;/span&gt;&lt;br /&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;$dupe_track&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$itunes&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;duplicate&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$t&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$albumen&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;unless&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$dupe_track&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;warn&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;could not dupe track\n&#38;quot;&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;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;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$included_track&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$dupe_track&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;prop&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;database id&#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;get&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;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;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;last&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;ADDITION&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$total_size&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1_000_000_000&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Finally, we add the tracks and make a record of adding them. If we&#38;#39;ve gotten our playlist up to a gig, we&#38;#39;re done. Otherwise, we go ahead and look for another album.&lt;/p&gt;

&lt;h2 id=&#34;The-Gift-of-Music&#34;&gt;The Gift of Music&lt;/h2&gt;

&lt;p&gt;I can honestly say that writing this program improved the quality of my life. Maybe not by leaps and bounds, but it made me remember how albums sounded. I found that many albums in my library were &lt;i&gt;much&lt;/i&gt; better taken as a whole than as individual tracks, and that means that I was now enjoying my music collection much more than I had in years.&lt;/p&gt;

&lt;p&gt;It&#38;#39;s the ability to keep &#38;quot;last played&#38;quot; and &#38;quot;play count&#38;quot; data synced with my mobile device that&#38;#39;s kept me hooked on iTunes, despite its numerous, crushing flaws. I encourage anybody who uses other music software to reproduce this program for his software, just to see how nice it can be.&lt;/p&gt;

&lt;h2 id=&#34;See-Also&#34;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://github.com/rjbs/misc/blob/master/itunes/albumen&#34;&gt;albumen&lt;/a&gt; - you&#38;#39;ll need to tweak it for your own use&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Mac::Glue&#34;&gt;Mac::Glue&lt;/a&gt; - once again making OS X a pretty cool place to live&lt;/p&gt;

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

&lt;/div&gt;</summary><updated>2010-12-20T00:00:00-05:00</updated><category term="Perl"/><category term="RJBS"/></entry><entry><title>Exporting Globs for Fun and Profit</title><link href="http://advent.rjbs.manxome.org/2010/2010-12-19.html"/><id>http://advent.rjbs.manxome.org/2010/2010-12-19.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h2 id=&#34;Whats-a-glob-&#34;&gt;What&#38;#39;s a glob?&lt;/h2&gt;

&lt;p&gt;A glob (or typeglob) is a kind of scalar in Perl. It is a weird, pretty horrible thing. There really isn&#38;#39;t any need for them in Perl 5, but instead of being jettisoned, typeglobs were enshrined in the construction of packages and classes. Anyway, that doesn&#38;#39;t really explain what a glob is.&lt;/p&gt;

&lt;p&gt;A glob is a scalar that may contain a reference to one variable of each type: scalar, array, hash, code, I/O handle, and format. In Perl, packages (and therefore classes) are just hashes with identifiers as keys and globs as values. So, given the following program:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;comment&#34;&gt;# we would have been in &#38;quot;main&#38;quot; anyway, but let&#39;s be explicit&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;version&#34;&gt;5.12.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;our&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$x&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;keyword&#34;&gt;our&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@x&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(foo bar baz)&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;x&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&#39;m in a glob!&#38;quot;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;This program sets up a typeglob in &lt;code&gt;$main::{x}&lt;/code&gt; with references to a scalar, a hash, and code so that we can get the following results in the debugger:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&#38;nbsp;&#38;nbsp;DB&#38;lt;1&#38;gt; x $main::{x}&lt;br /&gt;0  *main::x&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;We&#38;#39;ve got a glob there, just as we said.&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&#38;nbsp;&#38;nbsp;DB&#38;lt;2&#38;gt; x *{ $main::{x} }&lt;br /&gt;0  *main::x&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;The &lt;code&gt;*&lt;/code&gt; isn&#38;#39;t a dereference, because we don&#38;#39;t have a glob reference. It just means we want to use it &lt;i&gt;as&lt;/i&gt; a glob.&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&#38;nbsp;&#38;nbsp;DB&#38;lt;3&#38;gt; x ${ $main::{x} }&lt;br /&gt;0  1&lt;br /&gt;&#38;nbsp;&#38;nbsp;DB&#38;lt;4&#38;gt; x @{ $main::{x} }&lt;br /&gt;0  &#38;#39;foo&#38;#39;&lt;br /&gt;1  &#38;#39;bar&#38;#39;&lt;br /&gt;2  &#38;#39;baz&#38;#39;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;We can dereference the glob as a scalar or array (or anything else) to dereference the scalar or array (or whatever) in the slot for that type in the glob. We can also access those slots as if the glob was a hash; if we do that, we see the reference itself:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&#38;nbsp;&#38;nbsp;DB&#38;lt;5&#38;gt; x *{ $main::{x} }{ARRAY}&lt;br /&gt;0  ARRAY(0x1008ad4d8)&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;0  &#38;#39;foo&#38;#39;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;1  &#38;#39;bar&#38;#39;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;2  &#38;#39;baz&#38;#39;&lt;br /&gt;&#38;nbsp;&#38;nbsp;DB&#38;lt;6&#38;gt; x *{ $main::{x} }{SCALAR}&lt;br /&gt;0  SCALAR(0x100829658)&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;-&#38;gt; 1&lt;br /&gt;&#38;nbsp;&#38;nbsp;DB&#38;lt;7&#38;gt; x *{ $main::{x} }{CODE}&lt;br /&gt;0  CODE(0x10083b518)&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;-&#38;gt; &#38;amp;main::x in -:7-7&lt;br /&gt;&#38;nbsp;&#38;nbsp;DB&#38;lt;8&#38;gt; x *{ $main::{x} }{CODE}-&#38;gt;()&lt;br /&gt;I&#38;#39;m in a glob!&lt;br /&gt;0  1&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;It gets weirder, though. When we said &lt;code&gt;*$x&lt;/code&gt; above, we said we weren&#38;#39;t dereferencing, because there was no reference. What if there is?&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&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;br /&gt;&lt;span class=&#34;keyword&#34;&gt;our&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$x&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;This is X!&#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;our&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$y&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;*x&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Then, in the debugger...&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&#38;nbsp;&#38;nbsp;DB&#38;lt;1&#38;gt; x $x&lt;br /&gt;0  &#38;#39;This is X!&#38;#39;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;DB&#38;lt;2&#38;gt; x *x&lt;br /&gt;0  *main::x&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;DB&#38;lt;3&#38;gt; x ${ *x }&lt;br /&gt;0  &#38;#39;This is X!&#38;#39;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;DB&#38;lt;4&#38;gt; p ref $y&lt;br /&gt;GLOB&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;None of this is very surprising, so far. What do we do to get the string out of &lt;code&gt;$y&lt;/code&gt;, though? Well, &lt;code&gt;$y&lt;/code&gt; is a GLOB ref, and a GLOB is a kind of scalar, so we can dereference it with a dollar sign:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&#38;nbsp;&#38;nbsp;DB&#38;lt;7&#38;gt; x $y&lt;br /&gt;0  GLOB(0x1008297a8)&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;-&#38;gt; *main::x&lt;br /&gt;&#38;nbsp;&#38;nbsp;DB&#38;lt;8&#38;gt; x $$y&lt;br /&gt;0  *main::x&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;...and if you want to get at the string, we know we can scalar-dereference a glob to get its scalar entry:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&#38;nbsp;&#38;nbsp;DB&#38;lt;11&#38;gt; x $$$y&lt;br /&gt;0  &#38;#39;This is X!&#38;#39;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;And just to make sure there are more ways to do it, we can use a &lt;code&gt;*&lt;/code&gt; instead of a &lt;code&gt;$&lt;/code&gt; for some of these dereferences.&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&#38;nbsp;&#38;nbsp;DB&#38;lt;15&#38;gt; x $y&lt;br /&gt;0  GLOB(0x1008297a8)&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;-&#38;gt; *main::x&lt;br /&gt;&#38;nbsp;&#38;nbsp;DB&#38;lt;16&#38;gt; x *$y&lt;br /&gt;0  *main::x&lt;br /&gt;&#38;nbsp;&#38;nbsp;DB&#38;lt;17&#38;gt; x *{$y}{SCALAR}&lt;br /&gt;0  SCALAR(0x100829700)&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;-&#38;gt; &#38;#39;This is X!&#38;#39;&lt;br /&gt;&#38;nbsp;&#38;nbsp;DB&#38;lt;21&#38;gt; x ${ *$y }&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;...and that all makes sense. Then there&#38;#39;s:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;0  &#38;#39;This is X!&#38;#39;&lt;br /&gt;&#38;nbsp;&#38;nbsp;DB&#38;lt;22&#38;gt; x $*$y&lt;br /&gt;$* is no longer supported at (eval 26)&lt;br /&gt;&#38;nbsp;&#38;nbsp;[/Users/rjbs/perl5/perlbrew/perls/perl-5.12.2/lib/5.12.2/perl5db.pl:638] line 2.&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Oh. Right, because there used to be a &lt;code&gt;$*&lt;/code&gt; magic variable, we need to be clearer about our line noise:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&#38;nbsp;&#38;nbsp;DB&#38;lt;23&#38;gt; x ${ *$y }&lt;br /&gt;0  &#38;#39;This is X!&#38;#39;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;h3 id=&#34;That-Looks-Really-Dumb&#34;&gt;That Looks Really Dumb&lt;/h3&gt;

&lt;p&gt;Well, it is -- and the above is really just the goofy syntax around globs. In case you&#38;#39;re wondering: yes, they &lt;i&gt;do&lt;/i&gt; have goofy semantics as well. So, why would you ever go out of your way to deal with globs?&lt;/p&gt;

&lt;p&gt;There are basically two reasons. The first is simple: you install subroutines in packages at runtime by putting code into globs. &lt;a href=&#34;http://advent.rjbs.manxome.org/2009/2009-12-01.html&#34;&gt;I wrote about this&lt;/a&gt; last year. This is how &lt;a href=&#34;https://metacpan.org/module/Sub::Exporter&#34;&gt;Sub::Exporter&lt;/a&gt; and &lt;a href=&#34;https://metacpan.org/module/Exporter&#34;&gt;Exporter&lt;/a&gt; work.&lt;/p&gt;

&lt;p&gt;The other reason is more complicated. Globs in symbol tables are public, globally shared variables, so you can use them to share a variable everywhere. For example:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;symbol&#34;&gt;*Target::variable&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$Source::variable&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;This makes &lt;code&gt;$variable&lt;/code&gt; in &lt;code&gt;Target&lt;/code&gt; an alias to &lt;code&gt;$variable&lt;/code&gt; in &lt;code&gt;$source&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You could do pretty easily with a reference, though:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;package&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;&lt;br /&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;wishlist&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;%wishlist&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;%wishlist&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;...and then anywhere else in the program:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;word&#34;&gt;Christmas&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;wishlist&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;$person&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;span class=&#34;structure&#34;&gt;];&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;That gets us a shared variable with much tighter control over the interface than just a global variable name. So why would we do it with globs? There&#38;#39;s one really good reason: &lt;i&gt;localization&lt;/i&gt;. If we don&#38;#39;t just alias one part of the glob (like we aliased the scalar part above), but assign the whole glob, then we can use Perl&#38;#39;s &lt;code&gt;&lt;a href=&#34;https://metacpan.org/module/perlfunc#local&#34;&gt;local&lt;/a&gt;&lt;/code&gt; keyword to localize values within a dynamic scope.&lt;/p&gt;

&lt;p&gt;Dynamic scope lets you save the value of a global variable and overwrite it, and when you exit the current block the old value is restored. The usual (and excellent) document explaining scoping in Perl, including &lt;code&gt;local&lt;/code&gt;, is Mark Jason Dominus&#38;#39;s &lt;a href=&#34;http://perl.plover.com/FAQs/Namespaces.html&#34;&gt;Coping with Scoping&lt;/a&gt;. If you&#38;#39;re not clear on what dynamic scoping is, you should read it.&lt;/p&gt;

&lt;p&gt;If you &lt;i&gt;are&lt;/i&gt; clear, then what you need to know is that if you localize an imported variable, but you didn&#38;#39;t import the whole glob, other things that imported that variable &lt;i&gt;will not see your changes&lt;/i&gt;. Let that sink in.&lt;/p&gt;

&lt;p&gt;Here&#38;#39;s an example of how importing variables can make localization fail:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;br /&gt;16:&#38;nbsp;&lt;br /&gt;17:&#38;nbsp;&lt;br /&gt;18:&#38;nbsp;&lt;br /&gt;19:&#38;nbsp;&lt;br /&gt;20:&#38;nbsp;&lt;br /&gt;21:&#38;nbsp;&lt;br /&gt;22:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&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;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Source&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;our&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$variable&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;10&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;BEGIN&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;symbol&#34;&gt;*User_1::variable&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$Source::variable&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;symbol&#34;&gt;*User_2::variable&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$Source::variable&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;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;User_1&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;var&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$variable&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;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;User_2&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$variable&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;   &lt;span class=&#34;comment&#34;&gt;# 10, as expected&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;User_1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;comment&#34;&gt;# 10, as expected&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$variable&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$variable&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;   &lt;span class=&#34;comment&#34;&gt;# 20, as expected&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;say&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;User_1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;comment&#34;&gt;# 10, no good!&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Because we only imported the scalar part of &lt;code&gt;*Source::variable&lt;/code&gt;, it isn&#38;#39;t localized the way we might expect. If we replace the &lt;code&gt;$&lt;/code&gt; on lines 5 and 6 with &lt;code&gt;*&lt;/code&gt; then the final two &lt;code&gt;say&lt;/code&gt; statements will both print 20.&lt;/p&gt;

&lt;h3 id=&#34;I-Never-Want-to-Think-About-This-Again-&#34;&gt;I Never Want to Think About This Again!&lt;/h3&gt;

&lt;p&gt;This isn&#38;#39;t the kind of thing you need to think about very often, and once you&#38;#39;ve been forced to think about it enough, you might realize that you don&#38;#39;t want to think about it again. One way to do that is to never have shared, localized variables. That&#38;#39;s kind of a bummer, because it&#38;#39;s a useful thing to do. Another tactic would be to always use fully-qualified variable names to localize them. That&#38;#39;s a bummer, too, because local names are both easier to type and a layer of indirection in front of the real variable. That is: if you only use your package&#38;#39;s &lt;code&gt;$variable&lt;/code&gt;, and later you want to make it point to &lt;code&gt;$Other::variable&lt;/code&gt; instead of &lt;code&gt;$Source::variable&lt;/code&gt;, it&#38;#39;s only one line to update. If you had to type out &lt;code&gt;$Source::variable&lt;/code&gt; each time, it&#38;#39;s a much hairier problem.&lt;/p&gt;

&lt;p&gt;So, this is a fairly esoteric problem that isn&#38;#39;t encountered very often -- but it came up in the construction of two libraries mentioned earlier in this advent calendar: &lt;a href=&#34;http://advent.rjbs.manxome.org/2010/2010-12-01.html&#34;&gt;Log::Dispatchouli::Global&lt;/a&gt; and &lt;a href=&#34;http://advent.rjbs.manxome.org/2010/2010-12-17.html&#34;&gt;Global::Context&lt;/a&gt;. To avoid thinking about the grotty details of the problem, I built a library abstract the idea of a exported, shared glob.&lt;/p&gt;

&lt;h2 id=&#34;Sub::Exporter::GlobExporter&#34;&gt;Sub::Exporter::GlobExporter&lt;/h2&gt;

&lt;p&gt;Finally, today&#38;#39;s actual code!&lt;/p&gt;

&lt;p&gt;Here&#38;#39;s the Sub::Exporter setup for Global::Context, which exports a shared global:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Sub::Exporter&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;-setup&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;exports&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;ctx_init&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;single&#34;&gt;&#39;_build_ctx_init&#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;ctx_push&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;single&#34;&gt;&#39;_build_ctx_push&#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;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;collectors&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;single&#34;&gt;&#39;$Context&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Sub::Exporter::GlobExporter::glob_exporter&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;Context&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;single&#34;&gt;&#39;common_globref&#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;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;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;&lt;code&gt;ctx_init&lt;/code&gt; and &lt;code&gt;ctx_push&lt;/code&gt; are set up like plain old exports that you might see in any other use of Sub::Exporter. It&#38;#39;s &lt;code&gt;$Context&lt;/code&gt; that&#38;#39;s more interesting. Because it doesn&#38;#39;t just export a subroutine, it has to be a &#38;quot;collector,&#38;quot; which is Sub::Exporter jargon for &#38;quot;some weird hunk of behavior.&#38;quot; When someone uses &lt;code&gt;$Context&lt;/code&gt; in their import statement, like this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Global::Context&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;$Context&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;...then the &lt;code&gt;glob_exporter&lt;/code&gt; routine kicks in. It&#38;#39;s been passed two arguments. One is the name under which to install the exported glob. We used &lt;code&gt;Context&lt;/code&gt;, so it will be installed in &lt;code&gt;*Context&lt;/code&gt;. The other is a reference to a name of a method that will return the globref to install. In other words, the above import will result something like this happening:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$globref&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Global::Context&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;common_globref&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;*Importer::Context&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$globref&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;If we wanted, we could have done this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Global::Context&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;$Context&#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;-as&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ctx&#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;# ...which would have meant:&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;$globref&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Global::Context&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;common_globref&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;*Importer::ctx&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$globref&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;That&#38;#39;s how we can pick a different name in our package for a global that goes by another name elsewhere. This isn&#38;#39;t the big benefit, though. The big benefit is that because &lt;code&gt;common_globref&lt;/code&gt; is a &lt;i&gt;method&lt;/i&gt;, subclasses of Global::Context can provide a different globref. We could have two different global contexts that would never interfere with one another by writing the following code:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&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;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Context::Alpha&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;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;parent&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Global::Context&#39;&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;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;common_globref&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;*Context&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;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Context::Bravo&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;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;parent&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Global::Context&#39;&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;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;common_globref&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;*Context&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;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Context::Alpha&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;$Context&#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;-as&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ctx_a&#39;&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;Context::Bravo&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;$Context&#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;-as&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ctx_b&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;We&#38;#39;d end up with &lt;code&gt;$ctx_a&lt;/code&gt; and &lt;code&gt;$ctx_b&lt;/code&gt;, both properly shared with other things using the Alpha or Bravo contexts, and neither interfering. In other words, by using &lt;code&gt;glob_exporter&lt;/code&gt;, we write libraries that use global variables but less strictly limited in terms of reuse.&lt;/p&gt;

&lt;h2 id=&#34;See-Also&#34;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Sub::Exporter::GlobExporter&#34;&gt;Sub::Exporter::GlobExporter&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Sub::Exporter&#34;&gt;Sub::Exporter&lt;/a&gt; - the core exporter that the glob exporter builds on&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Log::Dispatchouli::Global&#34;&gt;Log::Dispatchouli::Global&lt;/a&gt; - this uses the glob exporter!&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Global::Context&#34;&gt;Global::Context&lt;/a&gt; - so does this!&lt;/p&gt;

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

&lt;/div&gt;</summary><updated>2010-12-19T00:00:00-05:00</updated><category term="Perl"/><category term="RJBS"/></entry><entry><title type="html">We&#38;#39;ll Have a Blue Christmas Without del.icio.us</title><link href="http://advent.rjbs.manxome.org/2010/2010-12-18.html"/><id>http://advent.rjbs.manxome.org/2010/2010-12-18.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h2 id=&#34;What-Color-is-Your-Datas-Parachute-&#34;&gt;What Color is Your Data&#38;#39;s Parachute?&lt;/h2&gt;

&lt;p&gt;Multi-master synchronization of an application&#38;#39;s data across multiple computers is hard -- &lt;i&gt;really&lt;/i&gt; hard. More and more, services spring up to keep all your data in just one place, accessible from all your computers. As more and more of your personal belongings become always-on parts of the Internet, all able to access more and more of your on-the-Internet data, it&#38;#39;s like you&#38;#39;re constantly surrounded by a cloud of all your information, always available but never weighing you down. The problem is that when your data is only supported by clouds, the clouds might dissipate at any time, leaving all your precious data in free fall.&lt;/p&gt;

&lt;p&gt;If you&#38;#39;re going to rely on cloud-backed systems, it&#38;#39;s always a good idea to make sure that you&#38;#39;ve got a regularly updated backup copy safely on the ground, even if it&#38;#39;s only on one system and inconvenient to use. After all, &#38;quot;inconvenient&#38;quot; will still be pretty good compared to &#38;quot;totally lost.&#38;quot;&lt;/p&gt;

&lt;p&gt;As a lot of people probably know by now, Yahoo! recently laid off quite a lot of staff, including (reportedly) the entire &lt;a href=&#34;http://del.icio.us/&#34;&gt;http://del.icio.us/&lt;/a&gt; team. Other widely-reported leaks said that Delicious would be shut down for good. If you long ago replaced all your other bookmarks with Delicious, and Delicious went away, you would suddenly be without your bookmarks.&lt;/p&gt;

&lt;p&gt;I started using Delicious back in 2004, when it was still pretty new, and was immediately gripped with fear that it would go away, leaving me bookmarkless. Eventually, too, I knew I&#38;#39;d want to migrate to my personal blog and bookmark manager, &lt;a href=&#34;https://metacpan.org/module/Rubric&#34;&gt;Rubric&lt;/a&gt;. To do that, I&#38;#39;d need my bookmarks in some kind of intermediate form.&lt;/p&gt;

&lt;p&gt;Fortunately, Delicious even then provided a good API for getting at your data, and &lt;a href=&#34;https://metacpan.org/author/ASCOPE&#34;&gt;Aaron Straup Cope&lt;/a&gt; wrote a nice &lt;a href=&#34;https://metacpan.org/module/Net::Delicious&#34;&gt;Perl interface&lt;/a&gt; to it. It was pretty easy for me to write a stripped down version and a &lt;a href=&#34;http://search.cpan.org/dist/delicious-backup/bin/delbackup&#34;&gt;simple &#38;quot;dump my bookmarks&#38;quot; program&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&#34;Using-delbackup&#34;&gt;Using &lt;i&gt;delbackup&lt;/i&gt;&lt;/h3&gt;

&lt;p&gt;First, create a &lt;i&gt;.delicious&lt;/i&gt; file in your home directory with your Delicious credentials in it:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;user: username&lt;br /&gt;pswd: password&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Then, run &lt;i&gt;delbackup&lt;/i&gt; with one of two switches:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;rjbs$ delbackup -y&lt;br /&gt;&lt;br /&gt;rjbs$ delbackup -ns&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;&lt;code&gt;-y&lt;/code&gt; dumps your bookmarks as YAML so you can import them into any other API you want, later. &lt;code&gt;-ns&lt;/code&gt; dumps them into a HTML document, organized by tags. It&#38;#39;s a Netscape bookmark file, so you can import it into nearly any web browser, but you&#38;#39;ll end up with lots of weird duplicates because Delicious uses tags and the Netscape bookmarks format uses (virtual) folders.&lt;/p&gt;

&lt;h2 id=&#34;See-Also&#34;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Net::Delicious::Simple&#34;&gt;Net::Delicious::Simple&lt;/a&gt; - which installs the &lt;i&gt;delbackup&lt;/i&gt; program&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Net::Delicious&#34;&gt;Net::Delicious&lt;/a&gt; - for more complicated interface with the API&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Rubric&#34;&gt;Rubric&lt;/a&gt; - for running your own bookmark server (it&#38;#39;s sort of ... rustic)&lt;/p&gt;

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

&lt;/div&gt;</summary><updated>2010-12-18T00:00:00-05:00</updated><category term="Perl"/><category term="RJBS"/></entry><entry><title>When in doubt, add more globals.</title><link href="http://advent.rjbs.manxome.org/2010/2010-12-17.html"/><id>http://advent.rjbs.manxome.org/2010/2010-12-17.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h3 id=&#34;EXPERIMENTAL-CODE-AHEAD&#34;&gt;EXPERIMENTAL CODE AHEAD&lt;/h3&gt;

&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/2010-12-10.html&#34;&gt;Last week&lt;/a&gt;, I wrote about the highly experimental DNS::Oterica. This week, I&#38;#39;ll be talking about the dangerously experimental &lt;a href=&#34;https://metacpan.org/module/Global::Context&#34;&gt;Global::Context&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&#34;The-Law-of-Demeter-Sucks&#34;&gt;The Law of Demeter Sucks&lt;/h2&gt;

&lt;p&gt;Actually, I&#38;#39;m a pretty firm believer in at least a modified form of the &lt;a href=&#34;http://en.wikipedia.org/wiki/Law_of_Demeter&#34;&gt;Law of Demeter&lt;/a&gt; in designing systems, but sometimes you really need a global. Sometimes the only alternative to a global is &lt;a href=&#34;http://en.wikipedia.org/wiki/Inversion_of_control&#34;&gt;inversion of control&lt;/a&gt;, a fairly complex pattern to implement. That doesn&#38;#39;t mean that globals are always a better choice than IOC, just that both are choices. (Like many other often-lousy program choices, global variables have been more maligned than they deserve. They deserve to be disliked, but maybe not quite demonized.)&lt;/p&gt;

&lt;p&gt;Years ago, we wanted to run all code inside of dynamic scopes that would provide &#38;quot;context&#38;quot; for the call. We called the notional project Class::Contexual. Context would tell us things like what user had initiated the request, from what IP, and what URL had been hit. This wouldn&#38;#39;t just be part of our web framework, though. Scripts run by the customer service staff would provide the same kind of context.&lt;/p&gt;

&lt;p&gt;Since we&#38;#39;d always have the same kind of context, we could always check permissions by using a single authorization system built into the user class. When logging, we&#38;#39;d always know where requests came from. The important thing was that we&#38;#39;d always have a context, and the context would be the same type of object everywhere. Our notional API looked something like:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;do_stuff&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;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#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;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;&lt;span class=&#34;word&#34;&gt;X::Permission&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;throw&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;unless&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;context&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;user&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;can_do_stuff&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&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;with_more_context&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;({&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;action&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;doing stuff&#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;do_else&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Then, &lt;code&gt;do_else&lt;/code&gt; would be called on some clone of &lt;code&gt;$self&lt;/code&gt; that differed only in context.&lt;/p&gt;

&lt;p&gt;The whole thing got really messy really quick, and eventually we abandoned the idea and just stuck to looking at the web request.&lt;/p&gt;

&lt;p&gt;Years later, the idea kept coming up here and there as a solution to a number of different problems. We finally said, &#38;quot;You know what? This is just what global variables are for.&#38;quot; After all, the context is describing the global execution context. It&#38;#39;s only for code that we have written and run internally, and isn&#38;#39;t going to be consumed by general publicly distributed code.&lt;/p&gt;

&lt;p&gt;We even made sure that the global context system could be re-used by multiple sets of libraries in a single process by making the specific global variable used pluggable. That is, two different systems could use the global context system without clobbering each others context. With that much safety ensured, the next question was just what we needed in our context.&lt;/p&gt;

&lt;h2 id=&#34;The-Content-of-The-Context&#34;&gt;The Content of The Context&lt;/h2&gt;

&lt;p&gt;We decided that for any given action, we&#38;#39;d only care about a few things:&lt;/p&gt;

&lt;ol&gt;

&lt;li&gt;&lt;p&gt;a handle for performing authorization checks; the auth &lt;i&gt;Token&lt;/i&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;a record of where the request came from (via email? the web? what IP?); the request&#38;#39;s &lt;i&gt;Terminal&lt;/i&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;a simple stack of how the request came in and got routed; the &lt;i&gt;Stack&lt;/i&gt;&lt;/p&gt;

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

&lt;p&gt;Auth token could come in all forms. We might get a web request from a user with a logged-in session identified in his cookie. We might get an OAuth signed request with a token associated with a user and a subset of that user&#38;#39;s rights. The token might even just represent &#38;quot;being run by employee &lt;i&gt;rjbs&lt;/i&gt; who has superuser privileges.&#38;quot; What we &lt;i&gt;do&lt;/i&gt; know is that it isn&#38;#39;t going to change one we get it. Every request has exactly one valid token, and once we have it, we don&#38;#39;t change it. Tokens are associated with users.&lt;/p&gt;

&lt;p&gt;The terminal, too, is pretty straightforward. We can tell, looking at the web request or the console program being run, where the request came from. Once we know that, it never needs to change.&lt;/p&gt;

&lt;p&gt;Both the token and the terminal can be represented by URIs, although we might want to use private URI schemas for them: &lt;code&gt;myapp://token/websession/1234&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The stack isn&#38;#39;t very complicated, either. It&#38;#39;s an array of frames, and each frame doesn&#38;#39;t need much more than a name. Imagine that user on the web has uploaded a list of contacts to add to his address book. We might have the following context, when we get to the underlying code that&#38;#39;s going to do the import:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;synIdentifier&#34;&gt;token&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;:&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;uri&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt; :&lt;/span&gt; myapp://token/websession/1234&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;user&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;:&lt;/span&gt; MyApp::User object&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;terminal&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;:&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;uri&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt; :&lt;/span&gt; ip://1.2.3.4&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;stack&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;:&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;- &lt;/span&gt;account setup wizard&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;- &lt;/span&gt;address book manager&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;- &lt;/span&gt;contact importer&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;The stack can add and drop frames as the program runs and execution enters and exits subroutines. We don&#38;#39;t tie the context&#38;#39;s stack to the program&#38;#39;s stack one-to-one, because that would make refactoring the code much more complicated. Instead, we can just add frames dynamically, and Perl will pop them off when we leave that part of the program.&lt;/p&gt;

&lt;p&gt;We get that benefit by making the context object a real old-fashioned global variable that can be localized with &lt;code&gt;local&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&#34;Putting-Things-into-Context&#34;&gt;Putting Things into Context&lt;/h2&gt;

&lt;p&gt;A simple program that uses Global::Context might look something like this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Global::Context&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;-all&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;$Context&#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;ctx_init&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;terminal&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;ip://1.2.3.4&#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;auth_token&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;myapp://token/websession/123&#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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;This imports a &lt;code&gt;$Context&lt;/code&gt; global and initializes it by calling &lt;code&gt;ctx_init&lt;/code&gt;. If some other part of the program has already initialized the context, an exception is thrown -- once we&#38;#39;ve set up the starting context, we&#38;#39;re only supposed to replace it locally. For example, if our first action is to decide to route down into the setup wizard, we might write this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;comment&#34;&gt;# our request is routed to the setup wizard:&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;...&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;local&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$Context&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;ctx_push&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;account setup wizard&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$wizard&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;process_request&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$r&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;symbol&#34;&gt;$Logger&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;program complete&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;That&#38;#39;s it! We&#38;#39;ve pushed a frame onto the stack. &lt;code&gt;$Context&lt;/code&gt; is now a new object, identical to what it was before, safe for the extra stack frame. We can keep pushing onto the stack as we descend through our program -- or we can leave it untouched. As we go back up the frame, the previous value is restored. For example, by the time we&#38;#39;re logging &#38;quot;program complete,&#38;quot; above, the &#38;quot;account setup wizard&#38;quot; stack frame is gone.&lt;/p&gt;

&lt;p&gt;This works because we&#38;#39;ve made sure that every part of the context is immutable. Nothing that we change at a deeper scope will be changed and then lost when we exit that scope. The only allowable change is the addition of stack frames.&lt;/p&gt;

&lt;p&gt;Marrying the context to logging make it easy for any part of the program to mention, in its, logs, why it&#38;#39;s doing something, without changing its API at all to allow caller info to be passed in. That is, we can take some deep, crufty old routine and make it tell us exactly why it&#38;#39;s doing something dangerous:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;__randomize_user_password&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;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$enc&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$str&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$dig&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$_uk1&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$uk_3&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$uk_2&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@rest&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;&lt;span class=&#34;comment&#34;&gt;  # log exactly why we&#39;re going to do this:&lt;br /&gt;&lt;/span&gt;  &lt;span class=&#34;symbol&#34;&gt;$Logger&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;log&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;double&#34;&gt;&#38;quot;randomizing user password for %s because of %s&#38;quot;&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;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;user_id&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;$Context&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;as_json&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;br /&gt;&#38;nbsp;&#38;nbsp;&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;password&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;re_enc&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$uk1&lt;/span&gt;&lt;span class=&#34;operator&#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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;h3 id=&#34;Specialized-Context&#34;&gt;Specialized Context&lt;/h3&gt;

&lt;p&gt;Token, terminal, and stack behavior are all implemented as roles. Because it&#38;#39;s pretty likely that different users of a system like Global::Context would want to allow different kinds of token, users, and so on, it&#38;#39;s easy to subclass any part of the system with more specific restrictions.&lt;/p&gt;

&lt;p&gt;If the only kind of terminal you want to support is a web browser, you can write a single Terminal class and require that the context object&#38;#39;s terminal attribute be a member of it.&lt;/p&gt;

&lt;h2 id=&#34;The-Future&#34;&gt;The Future&lt;/h2&gt;

&lt;p&gt;The future of this totally untested software (and idea) is, well, to be tested. It&#38;#39;s a design we&#38;#39;ve been thinking about for quite some time, but it needs to see some real combat. After that, it will probably either fail and never be seen again, or it will stick and simplify large amounts of our code.&lt;/p&gt;

&lt;h2 id=&#34;See-Also&#34;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Global::Context&#34;&gt;Global::Context&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Bread::Board&#34;&gt;Bread::Board&lt;/a&gt; - an IOC framework, if you want to avoid the globals&lt;/p&gt;

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

&lt;/div&gt;</summary><updated>2010-12-17T00:00:00-05:00</updated><category term="Perl"/><category term="RJBS"/></entry><entry><title>Dealing with an Oversized Interface</title><link href="http://advent.rjbs.manxome.org/2010/2010-12-16.html"/><id>http://advent.rjbs.manxome.org/2010/2010-12-16.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h2 id=&#34;Too-Many-Methods&#34;&gt;Too Many Methods&lt;/h2&gt;

&lt;p&gt;At &lt;a href=&#34;http://www.oscon.com/oscon2010&#34;&gt;OSCON&lt;/a&gt; this year, I had the great pleasure of presenting a &lt;a href=&#34;http://rjbs.manxome.org/talks/moose/&#34;&gt;tutorial on Moose&lt;/a&gt;. Afterward, a fellow from a large Perl-based project approached me and said, &#38;quot;Moose looks fantastic, but right now our code base is built around a really small number of gigantic classes that we need to refactor slowly. We can&#38;#39;t just replace the whole system with Moose. How can we go about doing that?&#38;quot;&lt;/p&gt;

&lt;p&gt;The question really pleased me, because it was a question we&#38;#39;d also had to deal with, and we&#38;#39;d found a few good answers that really helped us make progress on our situation. For example, two of our important classes have over &lt;i&gt;five hundred&lt;/i&gt; methods each, and are backed by database tables with way too many fields.&lt;/p&gt;

&lt;p&gt;Rewriting these classes entirely would be completely insane. The Big Rewrite is sometimes a valid approach, but here it would have been a big time sink, since way too much code would &lt;i&gt;also&lt;/i&gt; need rewriting to deal with a new interface without the same five hundred methods. We made some first attempts with replacement classes that could get the old-interface object as needed, but this ended up just meaning that we had &lt;i&gt;six&lt;/i&gt; hundred methods. It wasn&#38;#39;t targeted enough at cutting down on the amount of crap we&#38;#39;d shoved into one place.&lt;/p&gt;

&lt;h2 id=&#34;Divide-and-Delegate&#34;&gt;Divide and Delegate&lt;/h2&gt;

&lt;p&gt;Our next strategy was to identify groups of methods that all addressed a single area of concern. One of the first targets for this kind of refactoring was the code that let you subscribe or unsubscribe from a mailing list. There were a few enormous methods and dozens of goofy little ones scattered here and there. It provided a weird set of entry points with semantics that varied between them.&lt;/p&gt;

&lt;p&gt;We wanted to take all that code, give it a small set of entry points with simple semantics, and get it the heck &lt;i&gt;out&lt;/i&gt; of our existing, overcrowded classes. We made a new SubscriptionManager class and wrote all our new methods there. Then we&#38;#39;d delegate all the old calls to the new subscriptions subsystem. So, for example, our old code that looked like this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&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;$member&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$error&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;$list&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;subscribe&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$email_address&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;span class=&#34;structure&#34;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;...could now look like...&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$member&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;try&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;word&#34;&gt;subs_mgr&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;subscribe&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$email_address&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;span class=&#34;structure&#34;&gt;})&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;The actual conversion of old calls to new was somewhat tedious. First, grep for the old method names and switch them over. Next, delete all the old methods and see what breaks. Fix those and repeat.&lt;/p&gt;

&lt;h3 id=&#34;The-Spoils-of-Refactoring&#34;&gt;The Spoils of Refactoring&lt;/h3&gt;

&lt;p&gt;Some of the benefits of this refactoring are obvious: we were able to change the old code to make more sense; we moved methods into smaller libraries, making them easier to understand at a glance; we reduced the size of an overly-large interface. These were all very nice changes, but the second order of benefits were great.&lt;/p&gt;

&lt;p&gt;For example, because the SubscriptionManager was its own class, it could be written with different class-building tools than the big, old class. Namely, it could be Moose. It had to manage some persistent settings, like configuration about each mailing list&#38;#39;s subscription policies. Previously, these were all stored in the Big Class&#38;#39;s Big Table. Now that we broke out of the big class, we could put them somewhere else. I&#38;#39;ve already written about &lt;a href=&#34;http://advent.rjbs.manxome.org/2010/2010-12-09.html&#34;&gt;breaking up big tables&lt;/a&gt;, and that&#38;#39;s just what we did.&lt;/p&gt;

&lt;p&gt;Now we still had a big complicated class, but it was just a little less complicated. It had delegated a bunch of its work to a smaller class, written more cohesively, storing all its data in a little branch of a Data::Hive, but what if we wanted to move back to using relational storage in the future? What if we wanted to write a new set of behavior for the subscription manager? This had also become trivial!&lt;/p&gt;

&lt;p&gt;Look at the second (new) code sample, above, and you&#38;#39;ll see a call to a &lt;code&gt;subs_mgr&lt;/code&gt; method, which obviously returns the subscription manager object. What does that method look like? Something like this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;subs_mgr&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;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;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$subs_mgr&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;MLM::SubscriptionManager&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;list&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;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;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;It doesn&#38;#39;t need to, though. We could instead write it like this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;subs_mgr&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;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;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$subs_mgr_class&lt;/span&gt; &lt;span class=&#34;operator&#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;subs_mgr_class&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;Class::Load::load_class&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$subs_mgr_class&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;confess&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;$subs_mgr_class isn&#39;t a valid subscription manager&#38;quot;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$subs_mgr_class&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;DOES&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;MLM::Role::SubscriptionManager&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&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;$subs_mgr&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$subs_mgr_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;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;symbol&#34;&gt;$self&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;What&#38;#39;s the big difference? Well, now different lists can have different return values from &lt;code&gt;subs_mgr_class&lt;/code&gt;, so they can have radically different behavior -- but they still have to promise to implement the right &lt;a href=&#34;https://metacpan.org/module/Moose::Manual::Roles&#34;&gt;role&lt;/a&gt;. We &lt;i&gt;started&lt;/i&gt; with this built in, and it made the refactoring much easier.&lt;/p&gt;

&lt;p&gt;Our first implementation of the subscription subsystem could just keep using the old table for its storage, and then as lists were upgraded to the subscription backend, they were switched to use a class with settings stored in the hive.&lt;/p&gt;

&lt;h2 id=&#34;Making-Success-Repeatable&#34;&gt;Making Success Repeatable&lt;/h2&gt;

&lt;p&gt;This kind of refactoring was so successful, with so many side benefits, that we worked to make it easy to perform over and over, by factoring out this &#38;quot;subsystem pattern&#38;quot; into a reusable library: &lt;a href=&#34;https://metacpan.org/module/Role::Subsystem&#34;&gt;Role::Subsystem&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The way you use it is simple. First, you include Role::Subsystem in the class you want to be a subsystem, like our subscription manager; then you tell the main class how to get a subsystem object. Our subscription manager class might look like this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;MLM::SubscriptionManager&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;br /&gt;&lt;span class=&#34;word&#34;&gt;with&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;MLM::Role::SubscriptionManager&#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;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;get_subscriber_policy&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Okay, so that&#38;#39;s not very interesting -- as I said above, we put the actual subsystem stuff in a role:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;br /&gt;16:&#38;nbsp;&lt;br /&gt;17:&#38;nbsp;&lt;br /&gt;18:&#38;nbsp;&lt;br /&gt;19:&#38;nbsp;&lt;br /&gt;20:&#38;nbsp;&lt;br /&gt;21:&#38;nbsp;&lt;br /&gt;22:&#38;nbsp;&lt;br /&gt;23:&#38;nbsp;&lt;br /&gt;24:&#38;nbsp;&lt;br /&gt;25:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;MLM::Role::SubscriptionManager&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::Role&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;with&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Role::Subsystem&#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;ident&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;__PACKAGE__&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;type&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;MLM::List&#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;what&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;list&#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;getter&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;MLM::List&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;retrieve&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;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;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;requires&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;get_subscriber_policy&#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;word&#34;&gt;subscription_policy&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;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;&#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;get_subscriber_policy&#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;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;subscribe&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;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$email_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;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;&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;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;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;word&#34;&gt;is_disabled&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;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;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;subscription_policy&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;open&#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;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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;For the most part, this is pretty stock Moose code. We have some attributes and methods. We provide a &lt;code&gt;subscription_policy&lt;/code&gt; method, but its initial value will have to be provided by the class, which can do something like look in a database table or hive.&lt;/p&gt;

&lt;p&gt;The two things of note are the inclusion of the Role::Subsystem role and the call to the &lt;code&gt;list&lt;/code&gt; method on line 22. It should be pretty obvious that the list method gets the mailing list that the subscription manager belongs to, but where does it get that method? It&#38;#39;s set up, along with a lot of other useful behavior, by Role::Subsystem.&lt;/p&gt;

&lt;p&gt;Let&#38;#39;s look at it line by line:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;word&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Role::Subsystem&#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;ident&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;__PACKAGE__&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;type&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;MLM::List&#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;what&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;list&#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;getter&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;MLM::List&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;retrieve&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;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;br /&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;This says: &#38;quot;I am a subsystem known as (the current package&#38;#39;s name). I expect to be a delegate for an object of type MLM::List, which I&#38;#39;ll store in my &lt;code&gt;list&lt;/code&gt; attribute. If I only have the object&#38;#39;s identifier, and not an object, I can get it with this subroutine.&#38;quot;&lt;/p&gt;

&lt;p&gt;So, when we want a particular manager, we can say:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;word&#34;&gt;MLM::SubscriptionManager&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;list&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;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Role::Subsystem provides some shortcuts, though:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;word&#34;&gt;MLM::SubscriptionManager&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;for_list&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;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;MLM::SubscriptionManager&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;for_list_id&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;1234&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;The first form&#38;#39;s behavior should be obvious. It&#38;#39;s great for putting in the &lt;code&gt;subs_mgr&lt;/code&gt; method we wrote earlier, and is really clear.&lt;/p&gt;

&lt;p&gt;The second one might be less straightforward. It lets us get the subscription manager for a list that we haven&#38;#39;t instantiated! If it&#38;#39;s very expensive to get a list, it might be a much better idea to just get the subsystem of it that we need. If someone calls a method that needs the list object iself, it will call the &lt;a href=&#34;https://metacpan.org/module/list&#34;&gt;list&lt;/a&gt; method on the subsystem, which will lazily get the list using the getter we provided.&lt;/p&gt;

&lt;p&gt;This library might seem like it&#38;#39;s performing only a very simple task, but you might be surprised at how useful it is. See, the task it&#38;#39;s performing &lt;i&gt;is&lt;/i&gt; simple, but it&#38;#39;s &lt;i&gt;also&lt;/i&gt; boring. By making it extremely easy to make these kinds of delegates, it&#38;#39;s much more likely that code will get refactored into subsystems as soon as it&#38;#39;s useful. If this kind of refactoring requires boring slogging through extra delegation code, it will probably get put off until it&#38;#39;s absolutely essential -- and that means it will probably be pretty painful.&lt;/p&gt;

&lt;h3 id=&#34;Under-the-Hood&#34;&gt;Under the Hood&lt;/h3&gt;

&lt;p&gt;Role::Subsystem is a parameterized role, and something of an abuse of parameterized roles. While I won&#38;#39;t get into the implementation here, &lt;a href=&#34;https://github.com/rjbs/role-subsystem/blob/master/lib/Role/Subsystem.pm&#34;&gt;the source code&lt;/a&gt; might be interesting to some, especially the bits about getters and weak reference management.&lt;/p&gt;

&lt;h2 id=&#34;See-Also&#34;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Role::Subsystem&#34;&gt;Role::Subsystem&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Moose::Manual::Roles&#34;&gt;Moose::Manual::Roles&lt;/a&gt;&lt;/p&gt;

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

&lt;/div&gt;</summary><updated>2010-12-16T00:00:00-05:00</updated><category term="Perl"/><category term="RJBS"/></entry><entry><title>Lovingly Mass-Produced HTML</title><link href="http://advent.rjbs.manxome.org/2010/2010-12-15.html"/><id>http://advent.rjbs.manxome.org/2010/2010-12-15.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h2 id=&#34;Hand-Crafted-Bugs&#34;&gt;Hand-Crafted Bugs&lt;/h2&gt;

&lt;p&gt;One of my goals at work has been to grossly reduce the amount of HTML that our HTML Guy writes. Every time he writes more lines of HTML than are absolutely necessary, it&#38;#39;s a failure. This shouldn&#38;#39;t be a weird idea, because HTML is code, and any time anybody writes more code than is needed to clearly express an idea, it&#38;#39;s more likely to have mistakes. For example, there&#38;#39;s this input:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;foo&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;bar&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&#38;lt;/&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Well, this input won&#38;#39;t work as part of a form, because there&#38;#39;s no &lt;code&gt;name&lt;/code&gt; attribute that tells the value how to get into the form. Then there&#38;#39;s the incredibly tedious generation of radio buttons partly in HTML and partly in Perl:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;synSpecial&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;synComment&#34;&gt;# This example uses Mason, because that&#39;s what I use. -- rjbs, 2010-12-12&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synSpecial&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;%options&lt;/span&gt; = (&lt;br /&gt;&lt;span class=&#34;synSpecial&#34;&gt;%&lt;/span&gt;   &lt;span class=&#34;synConstant&#34;&gt;yes&lt;/span&gt;   =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;1&lt;/span&gt;,&lt;br /&gt;&lt;span class=&#34;synSpecial&#34;&gt;%&lt;/span&gt;   &lt;span class=&#34;synConstant&#34;&gt;no&lt;/span&gt;    =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;0&lt;/span&gt;,&lt;br /&gt;&lt;span class=&#34;synSpecial&#34;&gt;%&lt;/span&gt;   &lt;span class=&#34;synConstant&#34;&gt;maybe&lt;/span&gt; =&#38;gt; -&lt;span class=&#34;synConstant&#34;&gt;1&lt;/span&gt;,&lt;br /&gt;&lt;span class=&#34;synSpecial&#34;&gt;%&lt;/span&gt; );&lt;br /&gt;&lt;span class=&#34;synSpecial&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$option&lt;/span&gt; (&lt;span class=&#34;synIdentifier&#34;&gt;%options&lt;/span&gt;) {&lt;br /&gt;&lt;span class=&#34;synSpecial&#34;&gt;%&lt;/span&gt;   &lt;span class=&#34;synIdentifier&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$value&lt;/span&gt; = &lt;span class=&#34;synIdentifier&#34;&gt;$options&lt;/span&gt;{ &lt;span class=&#34;synIdentifier&#34;&gt;$option&lt;/span&gt; };&lt;br /&gt;&lt;span class=&#34;synSpecial&#34;&gt;%&lt;/span&gt;   &lt;span class=&#34;synIdentifier&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$selected&lt;/span&gt; = &lt;span class=&#34;synIdentifier&#34;&gt;$ARGS&lt;/span&gt;{&lt;span class=&#34;synIdentifier&#34;&gt;is_jolly&lt;/span&gt;} &lt;span class=&#34;synIdentifier&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$value&lt;/span&gt; ? &lt;span class=&#34;synIdentifier&#34;&gt;q&lt;/span&gt;{&lt;span class=&#34;synIdentifier&#34;&gt;selected&lt;/span&gt;=&lt;span class=&#34;synConstant&#34;&gt;&#39;selected&#39;&lt;/span&gt;} : &lt;span class=&#34;synIdentifier&#34;&gt;q&lt;/span&gt;{};&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;radio&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;is_jolly&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;&#38;lt;%&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$selected&lt;/span&gt; &lt;span class=&#34;synSpecial&#34;&gt;%&#38;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;&#38;lt;%&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$value&lt;/span&gt; &lt;span class=&#34;synSpecial&#34;&gt;%&#38;gt;&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&#38;lt;/&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;gt;&lt;/span&gt; &lt;span class=&#34;synSpecial&#34;&gt;&#38;lt;%&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$option&lt;/span&gt; &lt;span class=&#34;synSpecial&#34;&gt;%&#38;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synSpecial&#34;&gt;%&lt;/span&gt; }&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Building HTML like this over and over is just horrible, and it gets worse when the people producing the HTML aren&#38;#39;t also expected to be very good Perl programmers. There needs, instead, to be a very simple way to say things like, &#38;quot;and then I want a radio button&#38;quot; -- because &#38;quot;we&#38;#39;ll just be very careful each time&#38;quot; is not a viable strategy for anything in programming, and especially not anything boring that gets done frequently. The right solution is, as usual, &#38;quot;build a reusable component.&#38;quot;&lt;/p&gt;

&lt;h2 id=&#34;The-Widget-Factory&#34;&gt;The Widget Factory&lt;/h2&gt;

&lt;p&gt;What we wanted was to provide a simple way to say, &#38;quot;make a radio button here&#38;quot; and always get the right thing -- and to make it easy enough to provide custom tweaks that we&#38;#39;d almost &lt;i&gt;never&lt;/i&gt; have to resort to hand-written HTML.&lt;/p&gt;

&lt;p&gt;We built &lt;a href=&#34;https://metacpan.org/module/HTML::Widget::Factory&#34;&gt;HTML::Widget::Factory&lt;/a&gt;, which serves as a hub for plugins that build HTML. For example, consider that gross radio-button-building example, above. We had a list of options, &lt;code&gt;%options&lt;/code&gt;, and the value of the currently selected one in &lt;code&gt;%ARGS&lt;/code&gt;. We ignored a bunch of considerations like option ordering, or warning that would arise if the existing &lt;code&gt;is_jolly&lt;/code&gt; argument was undef, because they would have made the example even uglier. The widget factory &lt;i&gt;does&lt;/i&gt; deal with those problems, but the code looks fine, because it&#38;#39;s abstracted away:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$factory&lt;/span&gt; = HTML::Widget::Factory-&#38;gt;new;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$factory&lt;/span&gt;-&#38;gt;radio({&lt;br /&gt;&#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;is_jolly&#39;&lt;/span&gt;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;selected&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synIdentifier&#34;&gt;$ARGS&lt;/span&gt;{is_jolly},&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;options&lt;/span&gt;  =&#38;gt; [&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;[ &lt;span class=&#34;synConstant&#34;&gt;yes&lt;/span&gt;   =&#38;gt; &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;no&lt;/span&gt;    =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;0&lt;/span&gt;  ],&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;[ &lt;span class=&#34;synConstant&#34;&gt;maybe&lt;/span&gt; =&#38;gt; -&lt;span class=&#34;synConstant&#34;&gt;1&lt;/span&gt; ],&lt;br /&gt;&#38;nbsp;&#38;nbsp;],&lt;br /&gt;});&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;We work primarily with Mason, and have added a factory to our HTML::Mason::Request subclass, so in a component, we&#38;#39;d write the above as:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;synSpecial&#34;&gt;&#38;lt;%&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$m&lt;/span&gt;-&#38;gt;&lt;span class=&#34;synIdentifier&#34;&gt;widget&lt;/span&gt;-&#38;gt;&lt;span class=&#34;synIdentifier&#34;&gt;radio&lt;/span&gt;({&lt;br /&gt;&#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;is_jolly&#39;&lt;/span&gt;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;selected&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synIdentifier&#34;&gt;$ARGS&lt;/span&gt;{&lt;span class=&#34;synIdentifier&#34;&gt;is_jolly&lt;/span&gt;},&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;options&lt;/span&gt;  =&#38;gt; [&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;[ &lt;span class=&#34;synConstant&#34;&gt;yes&lt;/span&gt;   =&#38;gt; &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;no&lt;/span&gt;    =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;0&lt;/span&gt;  ],&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;[ &lt;span class=&#34;synConstant&#34;&gt;maybe&lt;/span&gt; =&#38;gt; -&lt;span class=&#34;synConstant&#34;&gt;1&lt;/span&gt; ],&lt;br /&gt;&#38;nbsp;&#38;nbsp;],&lt;br /&gt;}) &lt;span class=&#34;synSpecial&#34;&gt;%&#38;gt;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Or we could set up a bunch of checkboxes:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;@properties&lt;/span&gt; = &lt;span class=&#34;synConstant&#34;&gt;qw( is_jolly is_naughty is_sleeping celebrates_christmas )&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$prop&lt;/span&gt; (&lt;span class=&#34;synIdentifier&#34;&gt;@properties&lt;/span&gt;) {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$m&lt;/span&gt;-&#38;gt;widget-&#38;gt;checkbox({&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;id&lt;/span&gt;      =&#38;gt; &lt;span class=&#34;synIdentifier&#34;&gt;$prop&lt;/span&gt;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;value&lt;/span&gt;   =&#38;gt; &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;checked&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synIdentifier&#34;&gt;$user&lt;/span&gt;-&#38;gt;&lt;span class=&#34;synIdentifier&#34;&gt;$prop&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;});&lt;br /&gt;}&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Part of the factory&#38;#39;s job way of making things easy to get right is in filling in all the boring attributes the right way. For example, we gave an attribute id, but not a name. The name will default to the id. The checked value is just a boolean that results in either &lt;code&gt;checked=&#38;quot;checked&#38;quot;&lt;/code&gt; or nothing. This kind of behavior is all over: text gets HTML escaped, common element attributes (like id, class, and others) are handled for you, and so on.&lt;/p&gt;

&lt;p&gt;If you have to pass something weird into the produced element, you can often put it into the &lt;code&gt;attr&lt;/code&gt; argument:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;symbol&#34;&gt;$factory&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;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;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;stocking_position&#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;attr&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;usemap&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$image_map&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;accesskey&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;S&#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;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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;h2 id=&#34;Adding-New-Products-to-the-Factory&#34;&gt;Adding New Products to the Factory&lt;/h2&gt;

&lt;p&gt;Everything that the factory produces comes out of a plugin. There are a bunch of really useful plugins, but it&#38;#39;s easy to write more. This is the source for one of the simpler plugins, used to generate &lt;code&gt;textarea&lt;/code&gt; elements:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;br /&gt;16:&#38;nbsp;&lt;br /&gt;17:&#38;nbsp;&lt;br /&gt;18:&#38;nbsp;&lt;br /&gt;19:&#38;nbsp;&lt;br /&gt;20:&#38;nbsp;&lt;br /&gt;21:&#38;nbsp;&lt;br /&gt;22:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;HTML::Widget::Plugin::Textarea&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;parent&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;HTML::Widget::Plugin&#39;&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;HTML::Element&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;provided_widgets&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(textarea)&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;_attribute_args&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(disabled id)&lt;/span&gt; &lt;span class=&#34;structure&#34;&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;_boolean_args&lt;/span&gt;   &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(disabled)&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;textarea&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;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$factory&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$arg&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;&lt;span class=&#34;symbol&#34;&gt;$arg&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;attr&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;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$arg&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;attr&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;defined&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$arg&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;attr&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;structure&#34;&gt;};&lt;/span&gt;&lt;br /&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;$widget&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;HTML::Element&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;single&#34;&gt;&#39;textarea&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$widget&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;attr&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;$arg&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;attr&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;word&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;keys&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;$arg&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;attr&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;&lt;span class=&#34;symbol&#34;&gt;$widget&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;push_content&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$arg&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;value&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;});&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$widget&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;as_XML&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;When you call the &lt;code&gt;textarea&lt;/code&gt; method on a factory with this plugin, the arguments are rewritten in light of the &lt;code&gt;_attribute_args&lt;/code&gt; and &lt;code&gt;_boolean_args&lt;/code&gt; given. Boolean args produce those weird &lt;code&gt;x=&#38;#39;x&#38;#39;&lt;/code&gt; things expected for true values in HTML, and attribute args are then merged directly into the &lt;code&gt;attr&lt;/code&gt; argument described above. The &lt;code&gt;textarea&lt;/code&gt; method gets called with the rewritten args and is expected to return HTML.&lt;/p&gt;

&lt;p&gt;Notice that the method gets passed &lt;code&gt;$factory&lt;/code&gt;, the object on which &lt;code&gt;textarea&lt;/code&gt; actually got called. This means that you can write widget plugins defined in terms of other widgets. For example, the (non-core) plugin &lt;a href=&#34;https://metacpan.org/module/HTML::Widget::Plugin::Struct&#34;&gt;HTML::Widget::Plugin::Struct&lt;/a&gt; takes a Perl data structure and turns it into a bunch of hidden form inputs that can be reconstructed into the data structure by &lt;a href=&#34;https://metacpan.org/module/CGI::Expand&#34;&gt;CGI::Expand&lt;/a&gt;. For example, it can turn:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$struct&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;&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;single&#34;&gt;&#39;Edwin Ample&#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;favorite&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;pie&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;apple&#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;movie&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Elf&#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;fowl&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;duck&#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;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;siblings&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;words&#34;&gt;qw(Elmer Ebenezer Eric)&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;symbol&#34;&gt;$factory&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;struct&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;single&#34;&gt;&#39;person&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &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;$struct&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;...into...&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;hidden&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;person.name&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;Edwin Ample&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; /&#38;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;hidden&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;person.favorite.pie&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;apple&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; /&#38;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;hidden&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;person.favorite.movie&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;Elf&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; /&#38;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;hidden&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;person.favorite.fowl&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;duck&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; /&#38;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;hidden&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;person.siblings.0&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;Elmer&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; /&#38;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;hidden&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;person.siblings.1&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;Ebenezer&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; /&#38;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;&#38;lt;&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;hidden&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;person.siblings.2&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;Eric&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; /&#38;gt;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;It does that by repeatedly calling the &lt;code&gt;hidden&lt;/code&gt; method on the factory, so it gets exactly the same kind of hidden inputs that the rest of our code does -- and the thing producing those inputs can be replaced if we want all our hidden inputs to have different properties, like using end tags instead of &lt;code&gt;/&#38;gt;&lt;/code&gt; empty tag markers.&lt;/p&gt;

&lt;p&gt;Because the &lt;code&gt;struct&lt;/code&gt; widget is implemented by a class, we can do things like subclass the struct widget to make an editable struct (maybe by turning array entries into multiselects and everything else into normal inputs), or do emit a &lt;code&gt;script&lt;/code&gt; element with a &lt;a href=&#34;https://metacpan.org/module/HTML::Widget::Plugin::JS&#34;&gt;JavaScript representation of the structure&lt;/a&gt; in it.&lt;/p&gt;

&lt;p&gt;In the end, we can get all kinds of uniform, bug-free content produced with a nice, simple interface.&lt;/p&gt;

&lt;h2 id=&#34;Experiments-and-Annoyances&#34;&gt;Experiments and Annoyances&lt;/h2&gt;

&lt;p&gt;One early complaint we got internally about the factory was that it had too many quirks because of how Mason and Perl were interacting, and that it would be better if the widgets all worked like Mason components. In response, Dieter Pearcey wrote the excellent &lt;a href=&#34;https://metacpan.org/module/MasonX::Resolver::WidgetFactory&#34;&gt;MasonX::Resolver::WidgetFactory&lt;/a&gt;, which exposed a Mason component-like interface, allowing code like this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;synSpecial&#34;&gt;&#38;lt;&#38;amp;&lt;/span&gt; &lt;span class=&#34;synStatement&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;w&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;/s&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;elect&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;id&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;&#38;quot;myselect&#38;quot;&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;options&lt;/span&gt; =&#38;gt; \&lt;span class=&#34;synIdentifier&#34;&gt;@options&lt;/span&gt; &lt;span class=&#34;synSpecial&#34;&gt;&#38;amp;&#38;gt;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Then, we added &lt;a href=&#34;https://metacpan.org/module/MasonX::Resolver::Multiplex&#34;&gt;MasonX::Resolver::Multiplex&lt;/a&gt;, which let us say that things found under &lt;i&gt;/w&lt;/i&gt; would look first in on disk and then in the widget factory. This meant we could let the HTML authors write simple widgets as basic Mason components, and then alter we could turn them into faster or more reusable Perl plugins, and the interface wouldn&#38;#39;t need to change.&lt;/p&gt;

&lt;p&gt;Unfortunately, Mason&#38;#39;s caching layer would break on this sometimes, because widget factories are blessed into weirdly-named, auto-generated classes in order to resolve methods like &lt;a href=&#34;https://metacpan.org/module/textarea&#34;&gt;textarea&lt;/a&gt; to the right plugin. These names might change or be generated in the wrong runtime order, breaking things that have cached objets blessed into them.&lt;/p&gt;

&lt;p&gt;This is a surmountable problem, although tedious and annoying, so we haven&#38;#39;t addressed it yet. It&#38;#39;s one of the places where Perl&#38;#39;s lack of per-instance method resolution really becomes a hinderance. Instead, we were forced to ask HTML Guy to suck it up, for now, and use &lt;code&gt;$m-&#38;gt;widget&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Before the end of Advent, I&#38;#39;ll talk about potential solutions to this kind of problem.&lt;/p&gt;

&lt;h2 id=&#34;See-Also&#34;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/HTML::Widget::Factory&#34;&gt;HTML::Widget::Factory&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/MasonX::Resolver::WidgetFactory&#34;&gt;MasonX::Resolver::WidgetFactory&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/MasonX::Resolver::Multiplex&#34;&gt;MasonX::Resolver::Multiplex&lt;/a&gt;&lt;/p&gt;

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

&lt;/div&gt;</summary><updated>2010-12-15T00:00:00-05:00</updated><category term="Perl"/><category term="RJBS"/></entry><entry><title>Wanted: Gift, Got: Gift</title><link href="http://advent.rjbs.manxome.org/2010/2010-12-14.html"/><id>http://advent.rjbs.manxome.org/2010/2010-12-14.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h2 id=&#34;The-Case-of-the-Invisible-Differences&#34;&gt;The Case of the Invisible Differences&lt;/h2&gt;

&lt;p&gt;I&#38;#39;ve seen this kind of output from test programs more than I&#38;#39;d like to remember:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;not ok 6172 - sent expected message&lt;br /&gt;#   Failed test &#38;#39;sent expected message&#38;#39;&lt;br /&gt;#   at t/omnibus.t line 1938.&lt;br /&gt;#          got: &#38;#39;Foo.&lt;br /&gt;# &#38;#39;&lt;br /&gt;#     expected: &#38;#39;Foo.&lt;br /&gt;# &#38;#39;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;You&#38;#39;ll stare at that for a long time before having the clever idea of piping the test through &lt;code&gt;cat -A&lt;/code&gt; -- only to find that you&#38;#39;re only expecting a carriage return and newline, but you&#38;#39;re getting a newline. After the hundredth time, you learn to bring &lt;code&gt;cat -A&lt;/code&gt; into play as soon as you see this kind of weird test result, and lesson helps. The problem is that it &lt;i&gt;doesn&#38;#39;t&lt;/i&gt; help when diagnosing CPAN Testers reports from your code running on SqueeOS True56, a platform that you&#38;#39;ve never heard of and that nobody knows the line endings for. What&#38;#39;s going on with the output? You can&#38;#39;t say, so you contact the smoker and ask him to re-run the tests and tell you what the bytes in question are, but it&#38;#39;s a pretty lousy approach. The solution is to fix the diagnostic messages to show you everything that might be relevant.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Test::BinaryData&#34;&gt;Test::BinaryData&lt;/a&gt; replaces the usual &#38;quot;have X, want Y&#38;quot; diagnostic with output inspired by &lt;code&gt;xxd&lt;/code&gt;. The above test would have produced:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;not ok 6172 - sent expected message&lt;br /&gt;#   Failed test at t/omnibus.t line 1938.&lt;br /&gt;# have (hex)               have           want (hex)               want        &lt;br /&gt;# 466f6f2e0d0a------------ Foo...       ! 466f6f2e0a-------------- Foo..       &lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;It&#38;#39;s pretty obvious, here, what happened. There&#38;#39;s an extra byte in the &#38;quot;have,&#38;quot; and a quick glance at the compared lines shows that the bogus byte is an &lt;code&gt;0x0d&lt;/code&gt; before the shared &lt;code&gt;0x0a&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If we&#38;#39;ve got a bunch of identical content before the difference, we get leading content for context:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;# have (hex)               have           want (hex)               want        &lt;br /&gt;# 310d0a320d0a330d0a340d0a 1..2..3..4.. = 310d0a320d0a330d0a340d0a 1..2..3..4..&lt;br /&gt;# 350d0a360d0a540d0a380d0a 5..6..T..8.. ! 350d0a360d0a370d0a380d0a 5..6..7..8..&lt;br /&gt;# 390d0a31300d0a31310d0a31 9..10..11..1 = 390d0a31300d0a31310d0a31 9..10..11..1&lt;br /&gt;# 320d0a31330d0a31340d0a31 2..13..14..1 = 320d0a31330d0a31340d0a31 2..13..14..1&lt;br /&gt;# 350d0a31360d0a31370d0a31 5..16..17..1 = 350d0a31360d0a31370d0a31 5..16..17..1&lt;br /&gt;# 380d0a31390d0a32300d0a32 8..19..20..2 ! 380d0a31390d0a32300a3231 8..19..20.21&lt;br /&gt;# 31---------------------- 1            ! ------------------------             &lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;The column between the have and want signs shows you the relationship of the two subsequences: either they are equal (=) or they are not (!).&lt;/p&gt;

&lt;h2 id=&#34;Comparing-Encoded-Text&#34;&gt;Comparing Encoded Text&lt;/h2&gt;

&lt;p&gt;Originally, I wrote this module exclusively for comparing line endings. It had obvious applications for testing the results of encoding text strings, but I didn&#38;#39;t know much about encoding at the time. Once I became further mired in encoding issues, though, I came back to Test::BinaryData and found it really useful. For example, why did performing the same operation from different operating systems fail, with no visible differences?&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;# have (hex)               have           want (hex)               want        &lt;br /&gt;# 517565656e7372c3bf636865 Queensr..che ! 517565656e737279cc886368 Queensry..ch&lt;br /&gt;# ------------------------              ! 65---------------------- e          &lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Both encode the name of Queensr&#38;yuml;che, complete with &lt;a href=&#34;http://en.wikipedia.org/wiki/Heavy_metal_umlaut&#34;&gt;heavy metal umlaut&lt;/a&gt;, but the byte sequences differ. The first is LATIN SMALL LETTER Y WITH DIAERESIS, but the second is a combining sequence: LATIN SMALL LETTER Y, followed by COMBINING DIAERESIS.&lt;/p&gt;

&lt;p&gt;These forms are identical when read, but of course computers will see them differently, and this can cause really bizarre, awful bugs. As a side note, this kind of bug led me to find &lt;a href=&#34;https://metacpan.org/module/Unicode::Normalize&#34;&gt;Unicode::Normalize&lt;/a&gt;, which is something any programmer dealing with &#38;quot;funny characters&#38;quot; should know about.&lt;/p&gt;

&lt;p&gt;Test::BinaryData is meant to compare byte strings, and will reject any comparison when either side of it contains &#38;quot;wide characters&#38;quot; -- a sign that the content is probably a non-encoded character string. And anyway, cramming a four-character &#38;quot;byte&#38;quot; into the diagnostic display wouldn&#38;#39;t work!&lt;/p&gt;

&lt;h2 id=&#34;See-Also&#34;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Test::BinaryData&#34;&gt;Test::BinaryData&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/perlunitut&#34;&gt;perlunitut&lt;/a&gt; and &lt;a href=&#34;https://metacpan.org/module/Unicode::Normalize&#34;&gt;Unicode::Normalize&lt;/a&gt; - for learning to do Unicode right&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Test::Differences&#34;&gt;Test::Differences&lt;/a&gt; and &lt;a href=&#34;https://metacpan.org/module/Test::Diff&#34;&gt;Test::Diff&lt;/a&gt; - more &#38;quot;like &lt;code&gt;is&lt;/code&gt; but better&#38;quot; asserts&lt;/p&gt;

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

&lt;/div&gt;</summary><updated>2010-12-14T00:00:00-05:00</updated><category term="Perl"/><category term="RJBS"/></entry><entry><title>All Marked Up with No Place to Go</title><link href="http://advent.rjbs.manxome.org/2010/2010-12-13.html"/><id>http://advent.rjbs.manxome.org/2010/2010-12-13.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h3 id=&#34;NOT-ON-THE-CPAN&#34;&gt;NOT ON THE CPAN&lt;/h3&gt;

&lt;p&gt;Today&#38;#39;s article is about code not found on the CPAN.&lt;/p&gt;

&lt;h2 id=&#34;Talk-talk-talk-&#34;&gt;Talk, talk, talk!&lt;/h2&gt;

&lt;p&gt;For the past few years, I&#38;#39;ve given &lt;a href=&#34;http://rjbs.manxome.org/talks/&#34;&gt;quite a few technical talks&lt;/a&gt; at YAPC, OSCON, and other conferences. I really enjoy doing this, and I like to think I&#38;#39;ve gotten fairly good at producing good slides to illustrate the things I&#38;#39;m discussing. Since the initial release of Apple Keynote, I&#38;#39;ve been using it for nearly all of my slide construction, and I like it quite a bit, but every once in a while I run into one of its shortcomings.&lt;/p&gt;

&lt;p&gt;Although Keynote can be scripted with AppleScript, I&#38;#39;ve found that its scripting facilities are pretty weak, and they&#38;#39;ve never been sufficient to let me do what I want. Sometimes, this means I skip doing something, and sometimes it means I find a very convoluted way to achieve my goals using only Keynote&#38;#39;s stock features.&lt;/p&gt;

&lt;p&gt;One of the things that&#38;#39;s left me most frustrated, though, is my inability to automatically syntax highlight source code on slides. When you&#38;#39;re displaying fifteen lines of code on a big screen to people sitting in an amphiteater, syntax highlighting can be a huge help for readability. Just compare this plain code:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;br /&gt;16:&#38;nbsp;&lt;br /&gt;17:&#38;nbsp;&lt;br /&gt;18:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;package Counter;&lt;br /&gt;use MooseX::POE;&lt;br /&gt;has count =&#38;gt; (&lt;br /&gt;&#38;nbsp;&#38;nbsp;is =&#38;gt; &#39;rw&#39;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;default =&#38;gt; sub { 0 },&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;sub START {&lt;br /&gt;&#38;nbsp;&#38;nbsp;my ($self) = @_;&lt;br /&gt;&#38;nbsp;&#38;nbsp;$self-&#38;gt;yield(&#39;increment&#39;);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;event increment =&#38;gt; sub {&lt;br /&gt;&#38;nbsp;&#38;nbsp;my ($self) = @_;&lt;br /&gt;&#38;nbsp;&#38;nbsp;print &#38;quot;Count is now &#38;quot; . $self-&#38;gt;count . &#38;quot;\n&#38;quot;;&lt;br /&gt;&#38;nbsp;&#38;nbsp;$self-&#38;gt;count( $self-&#38;gt;count + 1 );&lt;br /&gt;&#38;nbsp;&#38;nbsp;$self-&#38;gt;yield(&#39;increment&#39;) unless $self-&#38;gt;count &#38;gt; 3;&lt;br /&gt;};&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;...to this syntax highlighted code:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;br /&gt;16:&#38;nbsp;&lt;br /&gt;17:&#38;nbsp;&lt;br /&gt;18:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;synStatement&#34;&gt;package&lt;/span&gt;&lt;span class=&#34;synType&#34;&gt; Counter&lt;/span&gt;;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;use &lt;/span&gt;MooseX::POE;&lt;br /&gt;has &lt;span class=&#34;synConstant&#34;&gt;count&lt;/span&gt; =&#38;gt; (&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;is&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;&#39;rw&#39;&lt;/span&gt;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;default&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synStatement&#34;&gt;sub &lt;/span&gt;{ &lt;span class=&#34;synConstant&#34;&gt;0&lt;/span&gt; },&lt;br /&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;START &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;$self&lt;/span&gt;) = &lt;span class=&#34;synIdentifier&#34;&gt;@_&lt;/span&gt;;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;$self&lt;/span&gt;-&#38;gt;yield(&lt;span class=&#34;synConstant&#34;&gt;&#39;increment&#39;&lt;/span&gt;);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;event &lt;span class=&#34;synConstant&#34;&gt;increment&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synStatement&#34;&gt;sub &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;$self&lt;/span&gt;) = &lt;span class=&#34;synIdentifier&#34;&gt;@_&lt;/span&gt;;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;synConstant&#34;&gt;&#38;quot;Count is now &#38;quot;&lt;/span&gt; . &lt;span class=&#34;synIdentifier&#34;&gt;$self&lt;/span&gt;-&#38;gt;count . &lt;span class=&#34;synConstant&#34;&gt;&#38;quot;&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;&lt;/span&gt;;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;$self&lt;/span&gt;-&#38;gt;count( &lt;span class=&#34;synIdentifier&#34;&gt;$self&lt;/span&gt;-&#38;gt;count + &lt;span class=&#34;synConstant&#34;&gt;1&lt;/span&gt; );&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;$self&lt;/span&gt;-&#38;gt;yield(&lt;span class=&#34;synConstant&#34;&gt;&#39;increment&#39;&lt;/span&gt;) &lt;span class=&#34;synStatement&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$self&lt;/span&gt;-&#38;gt;count &#38;gt; &lt;span class=&#34;synConstant&#34;&gt;3&lt;/span&gt;;&lt;br /&gt;};&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Adding syntax highlighting seemed like it would be a huge win, and would be useful to quite a few people, so I decided to undertake the endeavor. I knew that like many OS X apps (at the time, at least), Keynote was using RTF to store the rich text of slides. If I could produce RTF syntax highlighted code, I could get it into Keynote and be done!&lt;/p&gt;

&lt;h2 id=&#34;Making-Stew-from-the-CPAN&#34;&gt;Making Stew from the CPAN&lt;/h2&gt;

&lt;p&gt;In the end, making the RTF -- which I&#38;#39;d assumed would be the most difficult part of the job -- was pretty simple. The thing that made it simple, as with so many things in Perl, was the CPAN. All I needed to do was find the right set of modules and figure out how to tie them together. What follows is a run-through of the code-to-RTF program I produced.&lt;/p&gt;

&lt;p&gt;First, we load the libraries we&#38;#39;ll need:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&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;use &lt;/span&gt;Getopt::Long::Descriptive;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;use &lt;/span&gt;Graphics::ColorUtils &lt;span class=&#34;synConstant&#34;&gt;qw(name2rgb)&lt;/span&gt;;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;use &lt;/span&gt;RTF::Writer;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;use &lt;/span&gt;Text::VimColor;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Everybody remember &lt;a href=&#34;http://advent.rjbs.manxome.org/2010/2010-12-08.html&#34;&gt;Getopt::Long::Descriptive&lt;/a&gt;? Good. We&#38;#39;re going to use that to get some very basic options:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; (&lt;span class=&#34;synIdentifier&#34;&gt;$opt&lt;/span&gt;, &lt;span class=&#34;synIdentifier&#34;&gt;$usage&lt;/span&gt;) = describe_options(&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;&#39;%c %o &#38;lt;filename&#38;gt;&#39;&lt;/span&gt;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;[ &lt;span class=&#34;synConstant&#34;&gt;&#39;help|h&#39;&lt;/span&gt;,          &lt;span class=&#34;synConstant&#34;&gt;&#39;display this message&#39;&lt;/span&gt; ],&lt;br /&gt;&#38;nbsp;&#38;nbsp;[ &lt;span class=&#34;synConstant&#34;&gt;&#39;filetype|ft|f=s&#39;&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;&#39;filetype; Vim guesses by default&#39;&lt;/span&gt; ],&lt;br /&gt;&#38;nbsp;&#38;nbsp;[ &lt;span class=&#34;synConstant&#34;&gt;&#39;font-face|F=s&#39;&lt;/span&gt;,   &lt;span class=&#34;synConstant&#34;&gt;&#39;font face to use; defaults to Courier New&#39;&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;{ &lt;span class=&#34;synConstant&#34;&gt;default&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;&#39;Courier New&#39;&lt;/span&gt; } ],&lt;br /&gt;&#38;nbsp;&#38;nbsp;[ &lt;span class=&#34;synConstant&#34;&gt;&#39;font-size|Z=i&#39;&lt;/span&gt;,   &lt;span class=&#34;synConstant&#34;&gt;&#39;font size to use, in points; defaults to 14&#39;&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;{ &lt;span class=&#34;synConstant&#34;&gt;default&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synConstant&#34;&gt;14&lt;/span&gt; } ],&lt;br /&gt;);&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;$usage&lt;/span&gt;-&#38;gt;&lt;span class=&#34;synStatement&#34;&gt;die&lt;/span&gt; &lt;span class=&#34;synStatement&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$opt&lt;/span&gt;-&#38;gt;{help} &lt;span class=&#34;synStatement&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;@ARGV&lt;/span&gt; != &lt;span class=&#34;synConstant&#34;&gt;1&lt;/span&gt;;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;The &lt;code&gt;--filetype&lt;/code&gt; option is important, because it tells us what kind of syntax to highlight. After all, I have been known to include non-Perl code in my slides, once in a while.&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$syn&lt;/span&gt; = Text::VimColor-&#38;gt;new(&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;file&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synIdentifier&#34;&gt;$ARGV&lt;/span&gt;[&lt;span class=&#34;synConstant&#34;&gt;0&lt;/span&gt;],&lt;br /&gt;&#38;nbsp;&#38;nbsp;(&lt;span class=&#34;synIdentifier&#34;&gt;$opt&lt;/span&gt;-&#38;gt;{filetype} ? (&lt;span class=&#34;synConstant&#34;&gt;filetype&lt;/span&gt; =&#38;gt; &lt;span class=&#34;synIdentifier&#34;&gt;$opt&lt;/span&gt;-&#38;gt;{filetype}) : ()),&lt;br /&gt;);&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Here, we use one of my favorite modules. I only use it very occasionally, but it always saves quite a lot of time. While there are a number of syntax highlighting libraries on the CPAN, they often strike me as experimental or awkward to use. &lt;a href=&#34;http://vim.org/&#34;&gt;Vim&lt;/a&gt;, on the other hand, does a pretty good job with many different languages, and &lt;a href=&#34;https://metacpan.org/module/Text::VimColor&#34;&gt;Text::VimColor&lt;/a&gt; lets us get exactly the coloring that Vim would have used. Even better, we&#38;#39;ll be able to get at the syntax highlighted document as a list of substrings of the document, each with a syntax type, something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  $VAR1 = [
    [ Statement  =&#38;gt; &#38;#39;my&#38;#39;      ],
    [ &#38;#39;&#38;#39;         =&#38;gt; &#38;#39; &#38;#39;       ],
    [ Identifier =&#38;gt; &#38;#39;$syntax&#38;#39; ],
    [ &#38;#39;&#38;#39;         =&#38;gt; &#38;#39; = &#38;#39;     ],
    ...
  ];&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With our input primed in &lt;code&gt;$syn&lt;/code&gt;, it&#38;#39;s time to prime our output mechanism with &lt;a href=&#34;https://metacpan.org/module/RTF::Writer&#34;&gt;RTF::Writer&lt;/a&gt;:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$rtf&lt;/span&gt; = RTF::Writer-&#38;gt;new_to_string( \&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$str&lt;/span&gt; );&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$RTF::Writer::Escape&lt;/span&gt;[ &lt;span class=&#34;synStatement&#34;&gt;ord&lt;/span&gt;(&lt;span class=&#34;synConstant&#34;&gt;&#39;-&#39;&lt;/span&gt;) ] = &lt;span class=&#34;synConstant&#34;&gt;&#39;-&#39;&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;local&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$RTF::Writer::AUTO_NL&lt;/span&gt; = &lt;span class=&#34;synConstant&#34;&gt;0&lt;/span&gt;;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;We&#38;#39;ve initialized our RTF::Writer so that as it writes out text, it puts it in an in-memory buffer. We&#38;#39;re not going to be doing anything gargantuan, and thinking about temporary files is always a drag. Then we have to futz around with some settings to tweak out output. We prevent the replacement of hyphens with &#38;quot;non-breaking hypens&#38;quot; because Apple&#38;#39;s RTF implementation doesn&#38;#39;t seem to understand them, and we preserve the location of newlines so that we can skim our output RTF by eye to look for problems.&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;synIdentifier&#34;&gt;$rtf&lt;/span&gt;-&#38;gt;prolog(&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;fonts&lt;/span&gt;  =&#38;gt; [ &lt;span class=&#34;synIdentifier&#34;&gt;$opt&lt;/span&gt;-&#38;gt;{font_face} ],&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synConstant&#34;&gt;colors&lt;/span&gt; =&#38;gt; [ all_colors() ],&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;$hp_size&lt;/span&gt; = &lt;span class=&#34;synIdentifier&#34;&gt;$opt&lt;/span&gt;-&#38;gt;{font_size} * &lt;span class=&#34;synConstant&#34;&gt;2&lt;/span&gt;; &lt;span class=&#34;synComment&#34;&gt;# RTF uses half-points for font size&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synComment&#34;&gt;# Set size, font, and background color.&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;$rtf&lt;/span&gt;-&#38;gt;&lt;span class=&#34;synStatement&#34;&gt;print&lt;/span&gt;(&lt;br /&gt;&#38;nbsp;&#38;nbsp;\&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;\\&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;fs&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;$hp_size&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;\\&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;f0&#38;quot;&lt;/span&gt;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;color_controls_for(&lt;span class=&#34;synConstant&#34;&gt;&#39;Normal&#39;&lt;/span&gt;)&lt;br /&gt;);&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Now we&#38;#39;ve set up the RTF prolog, which tells future readers in advance what fonts and colors will be used in the document. We scale up to RTF&#38;#39;s weird &#38;quot;half point&#38;quot; font sizing, and get into our starting format by setting up our font size and colors by printing some raw RTF commands. &lt;code&gt;\fs&lt;/code&gt; sets font size, &lt;code&gt;\f&lt;/code&gt; sets font, and &lt;code&gt;\c&lt;/code&gt; sets the color. Where do &lt;code&gt;all_colors&lt;/code&gt; and &lt;code&gt;color_controls_for&lt;/code&gt; come from? We&#38;#39;ll get back to those in a bit.&lt;/p&gt;

&lt;p&gt;At this point, we&#38;#39;ve loaded in a stream of syntax-marked text hunks and we&#38;#39;ve got an RTF output stream ready to go. All we have to do is read, transform, and print -- the Platonic Perl Program:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$tokens&lt;/span&gt; = &lt;span class=&#34;synIdentifier&#34;&gt;$syn&lt;/span&gt;-&#38;gt;marked;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;while&lt;/span&gt; (&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$pair&lt;/span&gt; = &lt;span class=&#34;synStatement&#34;&gt;shift&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;@$tokens&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;$type&lt;/span&gt;, &lt;span class=&#34;synIdentifier&#34;&gt;$text&lt;/span&gt;) = &lt;span class=&#34;synIdentifier&#34;&gt;@$pair&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;$rtf&lt;/span&gt;-&#38;gt;&lt;span class=&#34;synStatement&#34;&gt;print&lt;/span&gt;(&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;color_controls_for(&lt;span class=&#34;synIdentifier&#34;&gt;$type&lt;/span&gt;), &lt;span class=&#34;synConstant&#34;&gt;&#38;quot; &#38;quot;&lt;/span&gt;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;$text&lt;/span&gt;,&lt;br /&gt;&#38;nbsp;&#38;nbsp;);&lt;br /&gt;}&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;That&#38;#39;s it! &lt;code&gt;@$tokens&lt;/code&gt; is our input, each entry a pair of &#38;quot;type&#38;quot; and &#38;quot;text&#38;quot; values. For each one, we spit out a color command, terminated by a space, and then the text. We don&#38;#39;t need to worry about anything else, because we&#38;#39;ve picked a monospace font and RTF won&#38;#39;t try to mangle our whitespace. (Thanks, RTF!) We can just finalize the RTF document and print out the buffer to which it was written:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;synIdentifier&#34;&gt;$rtf&lt;/span&gt;-&#38;gt;&lt;span class=&#34;synStatement&#34;&gt;close&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;print&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$str&lt;/span&gt;;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;So, that&#38;#39;s the whole program -- save for color handling -- in about 45 significant lines.&lt;/p&gt;

&lt;p&gt;It turns out that almost all of the work was in reading the Vim color scheme file!&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;br /&gt;16:&#38;nbsp;&lt;br /&gt;17:&#38;nbsp;&lt;br /&gt;18:&#38;nbsp;&lt;br /&gt;19:&#38;nbsp;&lt;br /&gt;20:&#38;nbsp;&lt;br /&gt;21:&#38;nbsp;&lt;br /&gt;22:&#38;nbsp;&lt;br /&gt;23:&#38;nbsp;&lt;br /&gt;24:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;%color_pos&lt;/span&gt;;&lt;br /&gt;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;@colors&lt;/span&gt;;&lt;br /&gt;&lt;span class=&#34;synPreProc&#34;&gt;BEGIN&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;%color&lt;/span&gt; = groups_from_file(&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;$ENV&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;{HOME}/.vim/colors/manxome.vim&#38;quot;&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;$color&lt;/span&gt;{Normal} ||= {};&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;$color&lt;/span&gt;{Normal}{bg} ||= [   &lt;span class=&#34;synConstant&#34;&gt;0&lt;/span&gt;,   &lt;span class=&#34;synConstant&#34;&gt;0&lt;/span&gt;,   &lt;span class=&#34;synConstant&#34;&gt;0&lt;/span&gt; ];&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;$color&lt;/span&gt;{Normal}{fg} ||= [ &lt;span class=&#34;synConstant&#34;&gt;127&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;127&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;127&lt;/span&gt; ];&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$group&lt;/span&gt; (&lt;span class=&#34;synStatement&#34;&gt;keys&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;%color&lt;/span&gt;) {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$which&lt;/span&gt; (&lt;span class=&#34;synConstant&#34;&gt;qw(fg bg)&lt;/span&gt;) {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;next&lt;/span&gt; &lt;span class=&#34;synStatement&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$rgb&lt;/span&gt; = &lt;span class=&#34;synIdentifier&#34;&gt;$color&lt;/span&gt;{ &lt;span class=&#34;synIdentifier&#34;&gt;$group&lt;/span&gt; }{ &lt;span class=&#34;synIdentifier&#34;&gt;$which&lt;/span&gt; };&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#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;$pos&lt;/span&gt; = &lt;span class=&#34;synIdentifier&#34;&gt;$color_pos&lt;/span&gt;{ &lt;span class=&#34;synStatement&#34;&gt;join&lt;/span&gt;(&lt;span class=&#34;synConstant&#34;&gt;&#39;-&#39;&lt;/span&gt;, &lt;span class=&#34;synIdentifier&#34;&gt;@$rgb&lt;/span&gt;) };&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;unless&lt;/span&gt; (&lt;span class=&#34;synStatement&#34;&gt;defined&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$pos&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;synStatement&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;@colors&lt;/span&gt;, &lt;span class=&#34;synIdentifier&#34;&gt;$rgb&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;synIdentifier&#34;&gt;$pos&lt;/span&gt; = &lt;span class=&#34;synIdentifier&#34;&gt;$color_pos&lt;/span&gt;{ &lt;span class=&#34;synStatement&#34;&gt;join&lt;/span&gt;(&lt;span class=&#34;synConstant&#34;&gt;&#39;-&#39;&lt;/span&gt;, &lt;span class=&#34;synIdentifier&#34;&gt;@$rgb&lt;/span&gt;) } = &lt;span class=&#34;synIdentifier&#34;&gt;$#colors&lt;/span&gt;;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;}&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;$color_pos&lt;/span&gt;{ &lt;span class=&#34;synConstant&#34;&gt;&#38;quot;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;$group&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;$which&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;&lt;/span&gt; } = &lt;span class=&#34;synIdentifier&#34;&gt;$pos&lt;/span&gt;;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;}&lt;br /&gt;&#38;nbsp;&#38;nbsp;}&lt;br /&gt;}&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;We read in the syntax highlighting groups from a given file -- here, my personal Vim color scheme -- and save everything as two entries in a hash. The keys are names like &lt;i&gt;Identifier:fg&lt;/i&gt; and &lt;i&gt;Identifier:bg&lt;/i&gt;, and the values are numbers -- because in RTF, we always refer to colors by their position in the index of colors, like this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;synStatement&#34;&gt;\line&lt;/span&gt; &lt;span class=&#34;synStatement&#34;&gt;\cf0&lt;/span&gt; &lt;span class=&#34;synStatement&#34;&gt;\cb3&lt;/span&gt; This text is color 0 on color 3! &lt;span class=&#34;synStatement&#34;&gt;\line&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;So this code has to set up the index and make sure all the possible names refer back to index positions. The color index looks like this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;{&lt;span class=&#34;synStatement&#34;&gt;\colortbl&lt;/span&gt; \red0\green170\blue0;\red0\green0\blue0;\red170\green170\blue170;&lt;br /&gt;\red255\green255\blue0;\red255\green0\blue0;\red0\green170\blue170;&lt;br /&gt;\red255\green255\blue255;\red0\green0\blue255;\red170\green0\blue0;&lt;br /&gt;\red0\green255\blue0;\red255\green0\blue255;\red0\green255\blue255;&lt;br /&gt;\red0\green0\blue238;\red204\green204\blue204;}&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;...so we need to get all our colors into RGB values, but in Vim color schemes, we&#38;#39;re free to use named colors, like &#38;quot;SlateBlue.&#38;quot; We&#38;#39;ll resolve these with &lt;a href=&#34;https://metacpan.org/module/Graphics::ColorUtils&#34;&gt;Graphics::ColorUtils&lt;/a&gt;, a weird little module that turns out to be really handy once in a while.&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;br /&gt;16:&#38;nbsp;&lt;br /&gt;17:&#38;nbsp;&lt;br /&gt;18:&#38;nbsp;&lt;br /&gt;19:&#38;nbsp;&lt;br /&gt;20:&#38;nbsp;&lt;br /&gt;21:&#38;nbsp;&lt;br /&gt;22:&#38;nbsp;&lt;br /&gt;23:&#38;nbsp;&lt;br /&gt;24:&#38;nbsp;&lt;br /&gt;25:&#38;nbsp;&lt;br /&gt;26:&#38;nbsp;&lt;br /&gt;27:&#38;nbsp;&lt;br /&gt;28:&#38;nbsp;&lt;br /&gt;29:&#38;nbsp;&lt;br /&gt;30:&#38;nbsp;&lt;br /&gt;31:&#38;nbsp;&lt;br /&gt;32:&#38;nbsp;&lt;br /&gt;33:&#38;nbsp;&lt;br /&gt;34:&#38;nbsp;&lt;br /&gt;35:&#38;nbsp;&lt;br /&gt;36:&#38;nbsp;&lt;br /&gt;37:&#38;nbsp;&lt;br /&gt;38:&#38;nbsp;&lt;br /&gt;39:&#38;nbsp;&lt;br /&gt;40:&#38;nbsp;&lt;br /&gt;41:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;synStatement&#34;&gt;sub &lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;groups_from_file &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;$filename&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;synStatement&#34;&gt;open&lt;/span&gt; &lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$fh&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;&#39;&#38;lt;&#39;&lt;/span&gt;, &lt;span class=&#34;synIdentifier&#34;&gt;$filename&lt;/span&gt; &lt;span class=&#34;synStatement&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;synStatement&#34;&gt;die&lt;/span&gt; &lt;span class=&#34;synConstant&#34;&gt;&#38;quot;couldn&#39;t open &lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;$filename&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt; to read: &lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;$!&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;&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;%color&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;LINE: &lt;span class=&#34;synStatement&#34;&gt;while&lt;/span&gt; (&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$line&lt;/span&gt; = &#38;lt;&lt;span class=&#34;synIdentifier&#34;&gt;$fh&lt;/span&gt;&#38;gt;) {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;chomp&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$line&lt;/span&gt;;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;$line&lt;/span&gt; =~ &lt;span class=&#34;synStatement&#34;&gt;s/&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;\A\s+&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;//&lt;/span&gt;;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;next&lt;/span&gt; LINE &lt;span class=&#34;synStatement&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$line&lt;/span&gt; =~ &lt;span class=&#34;synStatement&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;\A&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;hi&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;(?:&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;ghlight&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;)?&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;/&lt;/span&gt;;&lt;br /&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;$group&lt;/span&gt;) = &lt;span class=&#34;synIdentifier&#34;&gt;$line&lt;/span&gt; =~ &lt;span class=&#34;synStatement&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;\A&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;hi&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;(?:&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;ghlight&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;)?\s+(\w+)&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;/&lt;/span&gt;;&lt;br /&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;%attr&lt;/span&gt;;&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;synStatement&#34;&gt;my&lt;/span&gt; (&lt;span class=&#34;synIdentifier&#34;&gt;$fg&lt;/span&gt;) = &lt;span class=&#34;synIdentifier&#34;&gt;$line&lt;/span&gt; =~ &lt;span class=&#34;synStatement&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;guifg=&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;(\S+)&lt;/span&gt;&lt;span class=&#34;synStatement&#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;$attr&lt;/span&gt;{fg} = color_to_rgb(&lt;span class=&#34;synIdentifier&#34;&gt;$1&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;synStatement&#34;&gt;my&lt;/span&gt; (&lt;span class=&#34;synIdentifier&#34;&gt;$bg&lt;/span&gt;) = &lt;span class=&#34;synIdentifier&#34;&gt;$line&lt;/span&gt; =~ &lt;span class=&#34;synStatement&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;guibg=&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;(\S+)&lt;/span&gt;&lt;span class=&#34;synStatement&#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;$attr&lt;/span&gt;{bg} = color_to_rgb(&lt;span class=&#34;synIdentifier&#34;&gt;$bg&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;synIdentifier&#34;&gt;$color&lt;/span&gt;{ &lt;span class=&#34;synIdentifier&#34;&gt;$group&lt;/span&gt; } = \&lt;span class=&#34;synIdentifier&#34;&gt;%attr&lt;/span&gt;;&lt;br /&gt;&#38;nbsp;&#38;nbsp;}&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;%color&lt;/span&gt;;&lt;br /&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;color_to_rgb &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;$str&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;synStatement&#34;&gt;if&lt;/span&gt; (&lt;span class=&#34;synIdentifier&#34;&gt;$str&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;([0-9a-f]{6})&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;/i&lt;/span&gt;) {&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;synStatement&#34;&gt;map {&lt;/span&gt; &lt;span class=&#34;synStatement&#34;&gt;hex&lt;/span&gt; &lt;span class=&#34;synStatement&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;synStatement&#34;&gt;unpack&lt;/span&gt; &lt;span class=&#34;synConstant&#34;&gt;&#38;quot;(a2)*&#38;quot;&lt;/span&gt;, &lt;span class=&#34;synIdentifier&#34;&gt;$1&lt;/span&gt; ]&lt;br /&gt;&#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;&lt;span class=&#34;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;@rgb&lt;/span&gt; = name2rgb(&lt;span class=&#34;synIdentifier&#34;&gt;$str&lt;/span&gt;);  &lt;span class=&#34;synComment&#34;&gt;# &#38;lt;-- from Graphics::ColorUtils&lt;/span&gt;&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;synStatement&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;@rgb&lt;/span&gt;;&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;synIdentifier&#34;&gt;@rgb&lt;/span&gt;;&lt;br /&gt;&#38;nbsp;&#38;nbsp;}&lt;br /&gt;}&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Also note that for some bizarre reason I chose to use &lt;code&gt;unpack&lt;/code&gt;, above. It&#38;#39;s actually the only form of unpack that I know how to use.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Finally&lt;/i&gt;, we get to the heart of the matter:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;synStatement&#34;&gt;sub &lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;all_colors &lt;/span&gt;{ &lt;span class=&#34;synIdentifier&#34;&gt;@colors&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;color_controls_for &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;$group&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;synStatement&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$ctrl&lt;/span&gt; = &lt;span class=&#34;synConstant&#34;&gt;&#39;&#39;&lt;/span&gt;;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;for&lt;/span&gt; (&lt;span class=&#34;synConstant&#34;&gt;qw(f b)&lt;/span&gt;) {&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;$ctrl&lt;/span&gt; .= &lt;span class=&#34;synConstant&#34;&gt;&#38;quot;&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;\\&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;c&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;&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;.  (&lt;span class=&#34;synStatement&#34;&gt;defined&lt;/span&gt; &lt;span class=&#34;synIdentifier&#34;&gt;$color_pos&lt;/span&gt;{&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;$group&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;:${_}g&#38;quot;&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;? &lt;span class=&#34;synIdentifier&#34;&gt;$color_pos&lt;/span&gt;{&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;$group&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;:${_}g&#38;quot;&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;: &lt;span class=&#34;synIdentifier&#34;&gt;$color_pos&lt;/span&gt;{&lt;span class=&#34;synConstant&#34;&gt;&#38;quot;Normal:${_}g&#38;quot;&lt;/span&gt;});&lt;br /&gt;&#38;nbsp;&#38;nbsp;}&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;$ctrl&lt;/span&gt;;&lt;br /&gt;}&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;&lt;code&gt;all_colors&lt;/code&gt; returns a list of RGB arrayrefs to be used as the color index, and &lt;code&gt;color_controls_for&lt;/code&gt; returns an RTF command sequence to switch to the color for the given group.&lt;/p&gt;

&lt;h2 id=&#34;The-Proof-of-the-Stew-is-in-the-Eating&#34;&gt;The Proof of the Stew is in the Eating&lt;/h2&gt;

&lt;p&gt;I got this code written pretty quickly, and felt pretty good about it. It didn&#38;#39;t do anything clever or tricky, it just tied together a few simple CPAN modules to perform a simple text transformation, and it &lt;i&gt;worked&lt;/i&gt;! Those are the qualities I like to end up with in my code: simple, straightforward, mostly implemented in terms of other libraries, and &lt;i&gt;working&lt;/i&gt;. You can look at &lt;a href=&#34;http://advent.rjbs.manxome.org/2010/synrtf.rtf&#34;&gt;some sample output&lt;/a&gt;, if you want, too.&lt;/p&gt;

&lt;p&gt;From here, things should have been simple. I&#38;#39;d write some AppleScript like this (forgive my pseudo-AppleScript):&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;tell application Keynote&lt;br /&gt;&#38;nbsp;&#38;nbsp;get body of current slide&lt;br /&gt;&#38;nbsp;&#38;nbsp;write body to file with path P&lt;br /&gt;&#38;nbsp;&#38;nbsp;execute shell command &#38;quot;synrtf P &#38;gt; P.rtf&#38;quot;&lt;br /&gt;&#38;nbsp;&#38;nbsp;set rtf to (read file with path (P &#38;amp; &#38;quot;.rtf&#38;quot;))&lt;br /&gt;&#38;nbsp;&#38;nbsp;set body of current slide to rtf&lt;br /&gt;end tell&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Well, it turns out that you can&#38;#39;t address the formatting of slides in Keynote, at all. You also can&#38;#39;t address anything on the slide that isn&#38;#39;t the main body -- and the main body has several behaviors that differ from other shapes with text. I could&#38;#39;ve resorted to GUI-level automation to do things like:&lt;/p&gt;

&lt;ol&gt;

&lt;li&gt;&lt;p&gt;assume that the current text object is the target&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;simulate Cmd-A, Cmd-C to select all text and copy it&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;run &lt;code&gt;synrtf&lt;/code&gt; using &lt;code&gt;pbclip&lt;/code&gt; to get pasteboard contents&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;get &lt;code&gt;synrtf&lt;/code&gt; output and put it on the pasteboard&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;simulate pressing Cmd-V to paste the formatted text&lt;/p&gt;

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

&lt;p&gt;It was pretty clear by this point, though, that all the work lay ahead of me would be boring drudgery, and that I could just quit now and feel good about the RTF bits, maybe to revisit them later, when Keynote&#38;#39;s automation improved.&lt;/p&gt;

&lt;p&gt;I&#38;#39;m sorry to report that now, three years later, the automation hasn&#38;#39;t gotten any better, &lt;i&gt;and&lt;/i&gt; it no longer uses RTF. I don&#38;#39;t see myself switching away from Keynote, despite that, but maybe &lt;code&gt;synrtf&lt;/code&gt;, or some of the code it shows off, will be useful to someone else the way I&#38;#39;d hoped the original project would be.&lt;/p&gt;

&lt;h2 id=&#34;See-Also&#34;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://github.com/rjbs/misc/blob/master/synrtf&#34;&gt;synrtf&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;http://advent.rjbs.manxome.org/2010/synrtf.rtf&#34;&gt;sample output of &lt;code&gt;synrtf&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Text::VimColor&#34;&gt;Text::VimColor&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/RTF::Writer&#34;&gt;RTF::Writer&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;http://www.oreilly.com/catalog/rtfpg&#34;&gt;The RTF Pocket Guide&lt;/a&gt;&lt;/p&gt;

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

&lt;/div&gt;</summary><updated>2010-12-13T00:00:00-05:00</updated><category term="Perl"/><category term="RJBS"/></entry><entry><title>One People, One Address Book</title><link href="http://advent.rjbs.manxome.org/2010/2010-12-12.html"/><id>http://advent.rjbs.manxome.org/2010/2010-12-12.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h2 id=&#34;Centralizing-Your-Config&#34;&gt;Centralizing Your Config&lt;/h2&gt;

&lt;p&gt;I used to be really lousy at keeping track of people&#38;#39;s info. I had a text file with a bunch of people&#38;#39;s email addresses, and sometimes phone numbers. Other addresses were in my &lt;i&gt;mutt&lt;/i&gt; alias file, and others I&#38;#39;d find by searching my Maildir as needed. Phone numbers were either in memory, on paper, or in my cell phone&#38;#39;s memory. Any time I looked at fixing this, I was frustrated by lousy tools and lousy tool integration. If I wanted to put everything into Thunderbird, I could, but then... well, I&#38;#39;d be stuck using Thunderbird.&lt;/p&gt;

&lt;p&gt;When I started using Mac OS X heavily, I started using the Apple Address Book pretty heavily, too. My cell phone supported iSync, so I could get &lt;i&gt;all&lt;/i&gt; my phone numbers onto my cell effortlessly, which was fantastic. I started to load in everything else, and found it to be a totally reasonable program for managing my addresses. If I had been using Apple&#38;#39;s Mail program, it would have also provided lots of configuration for free, like whitelisting and address autocompletion. There was just one problem: I absolutely could not tolerate Apple&#38;#39;s Mail.&lt;/p&gt;

&lt;p&gt;I wanted to keep using &lt;i&gt;mutt&lt;/i&gt;, and Spam Assassin, and other disparate tools, all with configuration drawn from my address book. The solution was &lt;i&gt;addex&lt;/i&gt;.&lt;/p&gt;

&lt;p&gt;Addex talks to an address book -- any kind for which you care to provide an adapter -- and has plugins that do stuff with your address book entries. For example, my &lt;code&gt;addex.ini&lt;/code&gt; config file looks something liket his:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;synType&#34;&gt;addressbook =&lt;/span&gt; App::Addex::AddressBook::Apple&lt;br /&gt;&lt;span class=&#34;synType&#34;&gt;output =&lt;/span&gt; App::Addex::Output::Mutt&lt;br /&gt;&lt;span class=&#34;synType&#34;&gt;output =&lt;/span&gt; App::Addex::Output::SpamAssassin&lt;br /&gt;&lt;span class=&#34;synType&#34;&gt;output =&lt;/span&gt; AddexYAML&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synSpecial&#34;&gt;[App::Addex::Output::Mutt]&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synType&#34;&gt;filename =&lt;/span&gt; mutt/alias-abook&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synSpecial&#34;&gt;[AddexYAML]&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synType&#34;&gt;filename =&lt;/span&gt; abook.yaml&lt;br /&gt;&lt;br /&gt;&lt;span class=&#34;synSpecial&#34;&gt;[App::Addex::Output::SpamAssassin]&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synType&#34;&gt;filename =&lt;/span&gt; spamassassin/whitelists-abook&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;The program will acquire address book entries from App::Addex::AddressBook::Apple and then use a bunch of different output plugins to produce things like &lt;i&gt;mutt&lt;/i&gt; configuration, Spam Assassin whitelists, and some random YAML file that one of my personal mail filters uses. Addex ships with a number of these output plugins, but it&#38;#39;s easy to write your own. That AddexYAML plugin, for example, helps my &lt;a href=&#34;https://metacpan.org/module/Email::Filter&#34;&gt;Email::Filter&lt;/a&gt; program decide how to file mail. There&#38;#39;s a block in it that looks like this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&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;$email_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;span class=&#34;word&#34;&gt;Email::Address&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;parse&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$this&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&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;$email_address&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$from_addr&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;lc&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$email_address&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;address&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;my&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$addex_dest&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;YAML::Syck::LoadFile&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;$ENV{HOME}/.brita/abook.yaml&#38;quot;&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;$addex_dest&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;lc&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;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;delete&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$addex_dest&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;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;word&#34;&gt;keys&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$addex_dest&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;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$folder&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$addex_dest&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;$from_addr&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;symbol&#34;&gt;$dest&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.=&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;.$folder/&#38;quot;&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;_log&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Delivering to: $dest&#38;quot;&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;symbol&#34;&gt;$this&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;accept&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$dest&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;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;If there&#38;#39;s a delivery destination for a given sender, the mail goes there instead of into my default folder. The &lt;i&gt;abook.yaml&lt;/i&gt; file gets produced by this really simple plugin that took five minutes to write:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;br /&gt;16:&#38;nbsp;&lt;br /&gt;17:&#38;nbsp;&lt;br /&gt;18:&#38;nbsp;&lt;br /&gt;19:&#38;nbsp;&lt;br /&gt;20:&#38;nbsp;&lt;br /&gt;21:&#38;nbsp;&lt;br /&gt;22:&#38;nbsp;&lt;br /&gt;23:&#38;nbsp;&lt;br /&gt;24:&#38;nbsp;&lt;br /&gt;25:&#38;nbsp;&lt;br /&gt;26:&#38;nbsp;&lt;br /&gt;27:&#38;nbsp;&lt;br /&gt;28:&#38;nbsp;&lt;br /&gt;29:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;AddexYAML&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;base&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(App::Addex::Output::ToFile)&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;YAML::Syck&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;process_entry&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;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$addex&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$entry&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;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$s&lt;/span&gt; &lt;span class=&#34;operator&#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;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;_struct&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;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$folder&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$entry&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;field&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;folder&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$folder&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;transliterate&#34;&gt;tr{/}{.}&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&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;@emails&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;grep&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;word&#34;&gt;sends&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$entry&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;emails&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&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;$email&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@emails&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;symbol&#34;&gt;$s&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;$email&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$s&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;$email&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;ne&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$folder&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;warn&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;conflict on email &#38;lt;$email&#38;gt;: &#39;$s-&#38;gt;{ $email }&#39; vs. &#39;$folder&#39;\n&#38;quot;&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;symbol&#34;&gt;$s&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;$email&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;$folder&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;finalize&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;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;&#38;nbsp;&#38;nbsp;&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;output&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;YAML::Syck::Dump&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;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;_struct&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;}));&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&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;SUPER::finalize&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;The &lt;code&gt;process_entry&lt;/code&gt; method is called for every address book entry, and builds up a map of email addresses to folder names. When it&#38;#39;s processed every entry, it spits out a YAML dump of the mapping. It extends App::Addex::Output::ToFile, which takes care of the boring parts of file construction.&lt;/p&gt;

&lt;p&gt;So, what are address book entry objects, and where do they come from?&lt;/p&gt;

&lt;h2 id=&#34;Entries-and-Address-Books&#34;&gt;Entries and Address Books&lt;/h2&gt;

&lt;p&gt;Entries are simple. Every entry represents a person or contact. It has a name, one or more email addresses, and a hash of other miscellaneous fields. Every email address has a label, for things like &#38;quot;home&#38;quot; or &#38;quot;work&#38;quot; email addresses. The fields are just key/value pairs, and get used by things like the YAML plugin above, to provide arbitrary extra information. The &#38;quot;folder&#38;quot; field might say to which folder mail should be delivered. There&#38;#39;s another field used to pick the default email address for an entry (instead of the default of &#38;quot;home.&#38;quot;)&lt;/p&gt;

&lt;p&gt;The entries come from address book plugins, which really only need to provide one method: &lt;code&gt;entries&lt;/code&gt;, which must return a list of entries. My original target was Apple&#38;#39;s Address Book, of course, which I talked to with Chris Nandor&#38;#39;s spectacular &lt;a href=&#34;https://metacpan.org/module/Mac::Glue&#34;&gt;Mac::Glue&lt;/a&gt; library. Things like an entry&#38;#39;s name and email addresses are pretty unambiguous, there, but what about the &#38;quot;fields&#38;quot; for things like &#38;quot;folder&#38;quot;?&lt;/p&gt;

&lt;p&gt;We just read the free text &#38;quot;notes&#38;quot; field on the contact, looking for lines like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  folder: family
  whitelist: no&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I showed addex to a friend, years ago, and he said, &#38;quot;Wow, that&#38;#39;s great, how can I use it on Linux?&#38;quot; It hadn&#38;#39;t occurred to me, but it was easy to write a plugin to let addex work with &lt;a href=&#34;http://abook.sourceforge.net/&#34;&gt;abook&lt;/a&gt;, mapping user-defined fields to addex fields.&lt;/p&gt;

&lt;h2 id=&#34;Surviving-the-Death-of-Mac::Glue&#34;&gt;Surviving the Death of Mac::Glue&lt;/h2&gt;

&lt;p&gt;I really wanted to post about Addex in this calendar, but it didn&#38;#39;t seem fair. Addex hasn&#38;#39;t worked very well on modern OS X because Mac::Glue, the Carbon-Perl bridge used to access Address Book won&#38;#39;t build in most situations. Ever since upgrading to Snow Leopard, I haven&#38;#39;t been able to update my mutt config, which has been a growing annoyance.&lt;/p&gt;

&lt;p&gt;Finally, I decided that I&#38;#39;d work around the lack of Mac::Glue so that I could write this post, and I&#38;#39;m glad I did. The solution is simultaneously cute and absolutely horrible. I won&#38;#39;t include it all here, but you can read &lt;a href=&#34;https://github.com/rjbs/app-addex-addressbook-applescript/blob/master/lib/App/Addex/AddressBook/AppleScript.pm&#34;&gt;the whole source&lt;/a&gt; on GitHub.&lt;/p&gt;

&lt;p&gt;I&#38;#39;ll just include the most horrible part:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;br /&gt;16:&#38;nbsp;&lt;br /&gt;17:&#38;nbsp;&lt;br /&gt;18:&#38;nbsp;&lt;br /&gt;19:&#38;nbsp;&lt;br /&gt;20:&#38;nbsp;&lt;br /&gt;21:&#38;nbsp;&lt;br /&gt;22:&#38;nbsp;&lt;br /&gt;23:&#38;nbsp;&lt;br /&gt;24:&#38;nbsp;&lt;br /&gt;25:&#38;nbsp;&lt;br /&gt;26:&#38;nbsp;&lt;br /&gt;27:&#38;nbsp;&lt;br /&gt;28:&#38;nbsp;&lt;br /&gt;29:&#38;nbsp;&lt;br /&gt;30:&#38;nbsp;&lt;br /&gt;31:&#38;nbsp;&lt;br /&gt;32:&#38;nbsp;&lt;br /&gt;33:&#38;nbsp;&lt;br /&gt;34:&#38;nbsp;&lt;br /&gt;35:&#38;nbsp;&lt;br /&gt;36:&#38;nbsp;&lt;br /&gt;37:&#38;nbsp;&lt;br /&gt;38:&#38;nbsp;&lt;br /&gt;39:&#38;nbsp;&lt;br /&gt;40:&#38;nbsp;&lt;br /&gt;41:&#38;nbsp;&lt;br /&gt;42:&#38;nbsp;&lt;br /&gt;43:&#38;nbsp;&lt;br /&gt;44:&#38;nbsp;&lt;br /&gt;45:&#38;nbsp;&lt;br /&gt;46:&#38;nbsp;&lt;br /&gt;47:&#38;nbsp;&lt;br /&gt;48:&#38;nbsp;&lt;br /&gt;49:&#38;nbsp;&lt;br /&gt;50:&#38;nbsp;&lt;br /&gt;51:&#38;nbsp;&lt;br /&gt;52:&#38;nbsp;&lt;br /&gt;53:&#38;nbsp;&lt;br /&gt;54:&#38;nbsp;&lt;br /&gt;55:&#38;nbsp;&lt;br /&gt;56:&#38;nbsp;&lt;br /&gt;57:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;_produce_applescript&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;@fields&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;single&#34;&gt;&#39;first name&#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;single&#34;&gt;&#39;middle name&#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;single&#34;&gt;&#39;last name&#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;single&#34;&gt;&#39;nickname&#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;single&#34;&gt;&#39;suffix&#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;single&#34;&gt;&#39;note&#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;structure&#34;&gt;);&lt;/span&gt;&lt;br /&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;$dumper&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;&#39;&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;for&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$field&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@fields&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;symbol&#34;&gt;$dumper&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.=&lt;/span&gt; &lt;span class=&#34;heredoc&#34;&gt;&#38;lt;&#38;lt;&#38;quot;END_FIELD_DUMPER&#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;      set _this to get $field of _person&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;if $field of _person is not missing value then&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;set _answer to _answer &#38;amp; &#38;quot;- BEGIN $field\n&#38;quot;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;set _answer to _answer &#38;amp; ($field of _person) &#38;amp; &#38;quot;\n&#38;quot;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;set _answer to _answer &#38;amp; &#38;quot;- END $field\n&#38;quot;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;end if&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;heredoc_terminator&#34;&gt;END_FIELD_DUMPER&lt;br /&gt;&lt;/span&gt;  &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;br /&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;$osascript&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;END_APPLESCRIPT&#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;  tell application &#38;quot;Address Book&#38;quot;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;set _people to (get people)&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;set _answer to &#38;quot;&#38;quot;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;repeat with _person in _people&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;repeat 1 times&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;if count of email of _person = 0 then&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;exit repeat&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;end if&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;set _answer to _answer &#38;amp; &#38;quot;--- BEGIN &#38;quot; &#38;amp; id of _person &#38;amp; &#38;quot;\n&#38;quot;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;$dumper&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;set _answer to _answer &#38;amp; &#38;quot;- BEGIN email\n&#38;quot;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;repeat with _email in (get email of _person)&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;set _answer to _answer &#38;amp; (label of _email) &#38;amp; &#38;quot;\n&#38;quot;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;set _answer to _answer &#38;amp; (value of _email) &#38;amp; &#38;quot;\n&#38;quot;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;end repeat&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;set _answer to _answer &#38;amp; &#38;quot;- END email\n&#38;quot;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;set _answer to _answer &#38;amp; &#38;quot;--- END &#38;quot; &#38;amp; id of _person &#38;amp; &#38;quot;\n\n&#38;quot;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;end repeat&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;end repeat&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;_answer&lt;br /&gt;&#38;nbsp;&#38;nbsp;end tell&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;heredoc_terminator&#34;&gt;END_APPLESCRIPT&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$osascript&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;substitute&#34;&gt;s/\$dumper/$dumper/&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$osascript&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;With no direct access to the scripting interface from Perl, we&#38;#39;re reduced to writing AppleScript and later running it with the &lt;i&gt;osascript&lt;/i&gt; program. AppleScript doesn&#38;#39;t have a useful facility for &lt;i&gt;stdout&lt;/i&gt;, so we just build up a big string with concatenation. &lt;i&gt;osascript&lt;/i&gt; will print out the value of the last evaluated expression, so we evaluate &lt;code&gt;_answer&lt;/code&gt; last.&lt;/p&gt;

&lt;p&gt;There&#38;#39;s no JSON library, and trying to worry about escaping JSON strings would be a real pain, so instead I&#38;#39;ve come up with my own ridiculous output format to dump address book entries. Later, there&#38;#39;s code that will parse that back in, after reading the output of the AppleScript program.&lt;/p&gt;

&lt;p&gt;It&#38;#39;s a gross, colossal hack, but because address books are pluggable, everything just keeps working the way it did before.&lt;/p&gt;

&lt;h2 id=&#34;The-Future&#34;&gt;The Future&lt;/h2&gt;

&lt;p&gt;I keep meaning to write a GMail address book plugin, and an output plugin to update my &lt;a href=&#34;http://www.pobox.com/&#34;&gt;Pobox&lt;/a&gt; whitelists. So far, though, I&#38;#39;ve just been too lazy. Apart from that, though, I&#38;#39;m pretty happy with things the way they are. It just works, and it means I can keep using mutt and Apple Address Book and pretend that they know how to interoperate.&lt;/p&gt;

&lt;h2 id=&#34;See-Also&#34;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/App::Addex&#34;&gt;App::Addex&lt;/a&gt; - the app itself&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/App::Addex::AddressBook::Apple&#34;&gt;App::Addex::AddressBook::Apple&lt;/a&gt; - if you still have &lt;a href=&#34;https://metacpan.org/module/Mac::Glue&#34;&gt;Mac::Glue&lt;/a&gt;!&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/App::Addex::AddressBook::AppleScript&#34;&gt;App::Addex::AddressBook::AppleScript&lt;/a&gt; - if you don&#38;#39;t!&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/App::Addex::AddressBook::Abook&#34;&gt;App::Addex::AddressBook::Abook&lt;/a&gt; - if you use &lt;i&gt;abook&lt;/i&gt; (woah)&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/App::Addex::Plugin::Hiveminder&#34;&gt;App::Addex::Plugin::Hiveminder&lt;/a&gt; - for &lt;a href=&#34;http://hiveminder.com&#34;&gt;Hiveminder&lt;/a&gt; integration&lt;/p&gt;

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

&lt;/div&gt;</summary><updated>2010-12-12T00:00:00-05:00</updated><category term="Perl"/><category term="RJBS"/></entry><entry><title>Putting less on Your Wish List</title><link href="http://advent.rjbs.manxome.org/2010/2010-12-11.html"/><id>http://advent.rjbs.manxome.org/2010/2010-12-11.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h2 id=&#34;One-of-Perls-lesser-Known-Features&#34;&gt;One of Perl&#38;#39;s &lt;code&gt;less&lt;/code&gt;er Known Features&lt;/h2&gt;

&lt;p&gt;I do a lot of work with email, including a lot of message rewriting. Last year, I wrote about &lt;a href=&#34;http://advent.rjbs.manxome.org/2009/2009-12-17.html&#34;&gt;my favorite message-rewriting helper&lt;/a&gt;, but this year I&#38;#39;ll write about something somewhat more removed.&lt;/p&gt;

&lt;p&gt;Although quite a lot of my mail-handling uses &lt;a href=&#34;https://metacpan.org/module/Email::MIME&#34;&gt;Email::MIME&lt;/a&gt; or &lt;a href=&#34;https://metacpan.org/module/Email::Simple&#34;&gt;Email::Simple&lt;/a&gt;, the most heavily-munged mail goes through the venerable &lt;a href=&#34;https://metacpan.org/module/MIME::Entity&#34;&gt;MIME::Entity&lt;/a&gt;, which has much more sophisticated facilities for things like &#38;quot;message body stored on disk.&#38;quot; When you&#38;#39;re going to build email messages with huge attachments, and then rewrite them, this is pretty important.&lt;/p&gt;

&lt;p&gt;Sometimes, though, we know we&#38;#39;re going to deal with very small messages, and using the disks to store MIME content will just grind on IO. For example, we might have a program that does something like this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$parser&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;MIME::Parser&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;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;$file&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;File::Find::Rule&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;in&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;Maildir&#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;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;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$entity&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$parser&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;parse_open&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$file&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;MIME::Visitor&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;rewrite_parts&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$entity&lt;/span&gt;&lt;span class=&#34;operator&#34;&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;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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;By default, this will produce temporary files in &lt;i&gt;/tmp&lt;/i&gt; for the message and temporary working data. This is often (perhaps surprisingly) much faster than working in memory, because disk IO is native, while Perl&#38;#39;s file-in-memory IO is implemented in (relatively) slow Perl. So, while the default behavior may be &lt;i&gt;faster&lt;/i&gt;, it&#38;#39;s also more &lt;i&gt;expensive&lt;/i&gt;, at least as regards disk IO. If, like me, you often find yourself bound by disk operations, you might want a way to switch your programs into a mode that will use less disk IO operations, or &#38;quot;iops.&#38;quot;&lt;/p&gt;

&lt;p&gt;This is easy, first we update our program to have the optional code path:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$parser&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;MIME::Parser&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;keyword&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;less&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;of&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;iops&#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;structure&#34;&gt;{&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$parser&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;output_to_core&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;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$parser&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;tmp_to_core&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;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;for&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$file&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;File::Find::Rule&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;file&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;in&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;Maildir&#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;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;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$entity&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$parser&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;parse_open&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$file&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;MIME::Visitor&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;rewrite_parts&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$entity&lt;/span&gt;&lt;span class=&#34;operator&#34;&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;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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Now, most of the time that path will not be entered. The call to &lt;code&gt;less-&#38;gt;of&lt;/code&gt; will usually return false. To make it true, we would need to add a line like this to the top of the program:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;less&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;iops&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;We don&#38;#39;t want to edit our program every time, though -- but we&#38;#39;re not out of luck. Instead, we can invoke it in one of two ways. The first is the normal way, which will produce lots of disk IO:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  $ perl scan-all-mail&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If we want less IO, we run:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  $ perl -Mless=iops scan-all-mail&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;-M&lt;/code&gt; flag to &lt;i&gt;perl&lt;/i&gt; basically injects that &lt;code&gt;use&lt;/code&gt; line to the top of our program, causing the &lt;code&gt;less-&#38;gt;of&lt;/code&gt; call to return true, and all message handling to be done in memory.&lt;/p&gt;

&lt;h3 id=&#34;Disregard-that-this-is-less-useful&#34;&gt;Disregard that, this is less &#38;#39;useful&#38;#39;&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;less&lt;/code&gt; has long been regarded as a joke module, which did nothing until perl 5.10.0. In that release, it became something of a demonstration of how to write a lexical pragma that looks at the &#38;quot;hints hash&#38;quot; found in the 11th (!) element returned by &lt;code&gt;&lt;a href=&#34;https://metacpan.org/module/perlfunc#caller&#34;&gt;caller&lt;/a&gt;&lt;/code&gt;. From the outside, it actually looked useful, as seen above.&lt;/p&gt;

&lt;p&gt;Unfortunately, &lt;code&gt;less&lt;/code&gt; is just the sort of pragma where &lt;i&gt;dynamic&lt;/i&gt;, rather than lexical scope would be useful. We want to put that parser-optimizing code down in some &#38;quot;give me a new MIME parser&#38;quot; library that anything can call, getting a usefully-optimized parser based on what the programmer has asked to use less of most recently -- not just what he asked to use less of &lt;i&gt;in the lexical scope calling &lt;code&gt;of&lt;/code&gt;&lt;/i&gt;.&lt;/p&gt;

&lt;p&gt;With that limitation in place, can you use &lt;code&gt;less&lt;/code&gt; for anything useful? Possibly, but in the end, less is less useful than less could be if less used less lexicality.&lt;/p&gt;

&lt;h2 id=&#34;Wait-RJBS-didnt-write-less-&#34;&gt;Wait, RJBS didn&#38;#39;t write &lt;code&gt;less&lt;/code&gt;!&lt;/h2&gt;

&lt;p&gt;That&#38;#39;s true. I didn&#38;#39;t write less, and I don&#38;#39;t think I can easily fix it given its existing interface. I did fix another big problem with it, though.&lt;/p&gt;

&lt;p&gt;This code snippet looks great:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;less&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;cpu&#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;process_lots_of_files&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@filenames&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Or this one:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;less&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;memory&#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;process_lots_of_files&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@filenames&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;This one, though, is just unbearable:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;less&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;filehandles&#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;process_lots_of_files&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@filenames&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;It&#38;#39;s not that I mind the idea of trying to minimize open filehandles. That can be a reasonable optimization, sometimes. The problem is that filehandles are countable things, and you don&#38;#39;t use &#38;quot;less&#38;quot; with countable objects. The word &#38;quot;less&#38;quot; is for things that cannot be counted. For example:&lt;/p&gt;



&lt;blockquote&gt;

&lt;p&gt;This advent calendar entry has &lt;i&gt;less merit&lt;/i&gt; than many others.&lt;/p&gt;



&lt;/blockquote&gt;

&lt;p&gt;...but...&lt;/p&gt;



&lt;blockquote&gt;

&lt;p&gt;Rik deserves &lt;i&gt;fewer words&lt;/i&gt; of praise today than he did yesterday.&lt;/p&gt;



&lt;/blockquote&gt;

&lt;p&gt;If you are running perl 5.12.0 or newer, you can fix the nasty English suggested by the previous code snipped by installing &lt;a href=&#34;https://metacpan.org/module/fewer&#34;&gt;fewer&lt;/a&gt; and writing:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;pragma&#34;&gt;fewer&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;filehandles&#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;process_lots_of_files&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@filenames&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;I hope this is of use.&lt;/p&gt;

&lt;h2 id=&#34;See-Also&#34;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

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

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

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

&lt;/div&gt;</summary><updated>2010-12-11T00:00:00-05:00</updated><category term="Perl"/><category term="RJBS"/></entry><entry><title>In Lieu of Coal, Naughty Children May Be Given M4 Files</title><link href="http://advent.rjbs.manxome.org/2010/2010-12-10.html"/><id>http://advent.rjbs.manxome.org/2010/2010-12-10.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h3 id=&#34;EXPERIMENTAL-CODE-AHEAD&#34;&gt;EXPERIMENTAL CODE AHEAD&lt;/h3&gt;

&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/2010-12-03.html&#34;&gt;Last week&lt;/a&gt;, I wrote about the somewhat experimental Throwable::X. This week, I&#38;#39;ll be talking about the much more experimental &lt;a href=&#34;https://metacpan.org/module/DNS::Oterica&#34;&gt;DNS::Oterica&lt;/a&gt;. It&#38;#39;s been unchanged for a while, but this article is meant to tantalize more than to offer a warrantied product.&lt;/p&gt;

&lt;h2 id=&#34;Better-Living-Through-Macros&#34;&gt;Better Living Through Macros&lt;/h2&gt;

&lt;p&gt;Like, nearly any other internet business, my company has to manage DNS records. For a number of reasons, not the least of which was our heavy reliance on MX records and email transports to get work done. With on the order of 200 host names (&lt;code&gt;A&lt;/code&gt; records) alone to manage, the programmers of old had very wisely decided that maintaining thousands of lines of &lt;a href=&#34;http://cr.yp.to/djbdns.html&#34;&gt;tinydns&lt;/a&gt; configuration was madness. They very wisely decided to automate the generation of these files. They very wisely decided to generate output based on the jobs performed by actual hosts. Then they went and decided to use &lt;a href=&#34;http://en.wikipedia.org/wiki/m4_(computer_language)&#34;&gt;M4&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;dns/data.m4&lt;/i&gt; was not a well-loved file, and with good reason. Here&#38;#39;s a brief sampling of some of its contents:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;br /&gt;16:&#38;nbsp;&lt;br /&gt;17:&#38;nbsp;&lt;br /&gt;18:&#38;nbsp;&lt;br /&gt;19:&#38;nbsp;&lt;br /&gt;20:&#38;nbsp;&lt;br /&gt;21:&#38;nbsp;&lt;br /&gt;22:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;# create tinydns-data &#38;quot;+&#38;quot; or &#38;quot;=&#38;quot; lines&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;define(&lt;/span&gt;EQUALS,  &lt;span class=&#34;synConstant&#34;&gt;`=&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;$1&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;$2&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;$3&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;synComment&#34;&gt;dnl&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;define(&lt;/span&gt;PLUS,    &lt;span class=&#34;synConstant&#34;&gt;`+&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;$1&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;$2&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;$3&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;synComment&#34;&gt;dnl&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;# set up a macro for the IP and an = line at the same time&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;define(&lt;/span&gt;defq,  &lt;span class=&#34;synConstant&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;define(&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;$1&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;$2&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;EQUALS(&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;$1&lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;synComment&#34;&gt;dnl&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;# macros to get host definition parts out of the defq-defined host&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;define(&lt;/span&gt;NAME_FOR, &lt;span class=&#34;synSpecial&#34;&gt;$1&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;synComment&#34;&gt;dnl&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;define(&lt;/span&gt;IP_FOR,   &lt;span class=&#34;synSpecial&#34;&gt;$2&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;synComment&#34;&gt;dnl&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;define(&lt;/span&gt;TTL_FOR,  &lt;span class=&#34;synSpecial&#34;&gt;$3&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;synComment&#34;&gt;dnl&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;# macro for boxes that send mail form us&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;define(&lt;/span&gt;SENDS_PUBLIC_MAIL,   &lt;span class=&#34;synType&#34;&gt;PLUS(&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;outbound-1.example.com, &lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;$1&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;, ONE_HOUR&lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;synComment&#34;&gt;dnl&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;# set up one of our webservers&lt;br /&gt;defq(XYZ,        `xyz.example.com,   10.2.3.34,    3600&#39;)&lt;span class=&#34;synComment&#34;&gt;dnl&lt;/span&gt;&lt;br /&gt;defp(XYZ_WWW,    `xyz.www.example.com, 10.2.3.32,    600&#39;)&lt;span class=&#34;synComment&#34;&gt;dnl&lt;/span&gt;&lt;br /&gt;defq(XYZ_STATIC, `xyz.static.www.example.com, 10.2.3.34,    600&#39;)&lt;span class=&#34;synComment&#34;&gt;dnl&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synType&#34;&gt;DEFAULT_SOA_AND_NS(&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; 34.3.2.10.in-addr.arpa &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synType&#34;&gt;SENDS_PUBLIC_MAIL(&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;IP_FOR(&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; XYZ &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt; &lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;This is probably some of the clearest m4 found in the file. I won&#38;#39;t show you anything worse, because nobody wants his or her Friday ruined by something like this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;synIdentifier&#34;&gt;define(&lt;/span&gt;DEFAULT_MAIL, &lt;span class=&#34;synConstant&#34;&gt;`&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synConstant&#34;&gt;@&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;$1&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;::mx.example.com:10:600&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;pushdef(&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;`__dom&#39;&lt;/span&gt;, &lt;span class=&#34;synConstant&#34;&gt;`__macro_&#39;&lt;/span&gt;&lt;span class=&#34;synStatement&#34;&gt;translit(&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;$1&lt;/span&gt;, -., __&lt;span class=&#34;synStatement&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;define(&lt;/span&gt;__dom&lt;span class=&#34;synConstant&#34;&gt;`_mx&#39;&lt;/span&gt;, @&lt;span class=&#34;synSpecial&#34;&gt;$1&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;`::$&#39;`1:10:600&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synConstant&#34;&gt;map&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;(&lt;/span&gt;__dom&lt;span class=&#34;synConstant&#34;&gt;`_mx&#39;&lt;/span&gt;, DEFAULT_MXES&lt;span class=&#34;synSpecial&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synType&#34;&gt;popdef(&lt;/span&gt;&lt;span class=&#34;synConstant&#34;&gt;`__dom&#39;&lt;/span&gt;&lt;span class=&#34;synType&#34;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;synConstant&#34;&gt;&#39;&lt;/span&gt;&lt;span class=&#34;synIdentifier&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;So this file was a relic of days gone by, produced by programmers who had long since moved on to other ventures. Every shop has this kind of system: it works, its custodians can make very basic adjustments to it, but nobody dares make significant changes. Unfortunately, these kind of systems usually get built very early in a product&#38;#39;s lifecycle, to solve very important problems that are not within the business&#38;#39;s central competency. That is: we were not a company that existed to manage DNS records, but we needed to have something to manage them as soon as possible.&lt;/p&gt;

&lt;p&gt;The problem is that eventually the business will grow past this kind of solution, and if it can&#38;#39;t be maintained, it will have to be rewritten. There may be plenty of ways to make that take longer and to keep these systems more maintainable, but their eventual retirement and replacement, over and over, seems inevitable.&lt;/p&gt;

&lt;p&gt;The time for our system to die was at hand, and before we could replace it, we had to understand it.&lt;/p&gt;

&lt;h2 id=&#34;Decomposing-data.m4&#34;&gt;Decomposing &lt;i&gt;data.m4&lt;/i&gt;&lt;/h2&gt;

&lt;p&gt;Hosts in the M4 file were macros. That meant that when you said, &#38;quot;XYZ sends public mail,&#38;quot; &lt;i&gt;m4&lt;/i&gt; would eventually say, &#38;quot;XYZ&#38;#39;s IP appears as reverse DNS for &lt;i&gt;outbound-1.example.com&lt;/i&gt;.&#38;quot; Other macros were more complex, like the &lt;code&gt;REDIRECTING_VIRTUAL_DOMAIN&lt;/code&gt; macro, which set up quite a few records of both forward and reverse DNS lookup. All these macros would be passed the host macro, which stood in for a number of identifying attributes of the host.&lt;/p&gt;

&lt;p&gt;In fact, once you got past a lot of the weird M4-ness of the file, it was trying to say some pretty simple things, like this:&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;All hosts have a primary name.&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hosts might have IP addresses for their name.&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hosts might have extra names that go to the same address.&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hosts might belong to service groups, like MX or webservers.&lt;/p&gt;

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

&lt;p&gt;Then there was a second layer of logic that said &#38;quot;a host turns into a bunch of tinydns lines based on its names and IP addresses&#38;quot; and &#38;quot;service groups turn into a bunch of tinydns lines based on the hosts in them.&#38;quot; The only things that varied, really, was what it meant to be in a given group.&lt;/p&gt;

&lt;p&gt;So, there were two kinds of entities to consider: hosts and groups. Hosts were easy, since they&#38;#39;re all pretty much the same. We put our host definitions into YAML files, like this one:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;synIdentifier&#34;&gt;hostname&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;:&lt;/span&gt; a-lb-mx-fastnet&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;domain&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;:&lt;/span&gt; example.com&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;location&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;:&lt;/span&gt; megacenter&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;ip&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;:&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synIdentifier&#34;&gt;world&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;:&lt;/span&gt; 10.1.0.100&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;aliases&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;:&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;- &lt;/span&gt;almf.example.com&lt;br /&gt;&lt;span class=&#34;synIdentifier&#34;&gt;families&lt;/span&gt;&lt;span class=&#34;synSpecial&#34;&gt;:&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;- &lt;/span&gt;com.example.mx&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;- &lt;/span&gt;com.example.memcached&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synStatement&#34;&gt;- &lt;/span&gt;com.example.tor-exit-node&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Files like this sit in a directory organized however the sysadmins want. Ours, for example, puts each server in one file, along with any Solaris zones running on that server. The tool doesn&#38;#39;t care. It just reads in a bunch of YAML documents and turns them into Host objects. When every host is loaded in, the hosts can be turned into DNS data lines with their &lt;code&gt;as_data_lines&lt;/code&gt; method:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;as_data_lines&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;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;&lt;span class=&#34;keyword&#34;&gt;return&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;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;rec&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;comment&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;begin host &#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#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;fqdn&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;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;rec&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;comment&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;  families: &#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;join&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;literal&#34;&gt;q{, }&lt;/span&gt;&lt;span class=&#34;operator&#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;_family_names&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;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&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;rec&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;a_and_ptr&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;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;fqdn&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;node&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;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;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&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;rec&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;a&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;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;node&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;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;word&#34;&gt;for&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;aliases&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&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;rec&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;comment&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;end host &#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#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;fqdn&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;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;(&lt;code&gt;$self-&#38;gt;rec&lt;/code&gt; is a record generator, so that we can generate diagnostic output rather than tinydns-config, as needed.)&lt;/p&gt;

&lt;p&gt;This is pretty straightforward. Sure it&#38;#39;s &lt;i&gt;longer&lt;/i&gt; than the corresponding M4 found in our &lt;code&gt;defq&lt;/code&gt; macro, but it&#38;#39;s a heck of a lot clearer. That said, it&#38;#39;s also pretty boring. This code might solve a problem, but it doesn&#38;#39;t solve the more interesting, difficult problem we have: composing the behavior found in each service group -- here, called &lt;i&gt;families&lt;/i&gt;.&lt;/p&gt;

&lt;p&gt;In our YAML document above, we put the host into several families, one of which was &lt;i&gt;com.example.mx&lt;/i&gt;, which we implement in a class seen below. We&#38;#39;ll go through it in chunks:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;DNS::Oterica::NodeFamily::ExampleMX&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;word&#34;&gt;extends&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;DNS::Oterica::NodeFamily&#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;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;com.example.mx&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;It&#38;#39;s just a Moose class, implementing the abstract NodeFamily class. (There ended up being boring reasons that NodeFamily couldn&#38;#39;t be a role.) The &lt;code&gt;name&lt;/code&gt; corresponds to the family name used in the config files.&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;mx_nodes&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;single&#34;&gt;&#39;HashRef&#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;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;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;after&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;add_node&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;&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;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$node&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;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$nodes&lt;/span&gt; &lt;span class=&#34;operator&#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;mx_nodes&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;$i&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;keys&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$nodes&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;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$next_name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;sprintf&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;mx-%s.example.com&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$i&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;br /&gt;&#38;nbsp;&#38;nbsp;&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;mx_nodes&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;$next_name&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;$node&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;The family keeps track of all the MX nodes that it&#38;#39;s seen; there&#38;#39;s an &lt;code&gt;mx_nodes&lt;/code&gt; attribute on the object, and every time it adds a node, it records the node and gives it a new name. The first is &lt;i&gt;mx-1.example.com&lt;/i&gt;, the &lt;i&gt;mx-2.example.com&lt;/i&gt; and so on.&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;word&#34;&gt;augment&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;as_data_lines&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;&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;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@lines&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;&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;$mx&lt;/span&gt; &lt;span class=&#34;operator&#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;mx_nodes&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;for&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$mxname&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;sort&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;keys&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$mx&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;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@lines&lt;/span&gt;&lt;span class=&#34;operator&#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;rec&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;a&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;name&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$mxname&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;&lt;span class=&#34;word&#34;&gt;node&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$mx&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$mxname&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;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;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@lines&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Then, when we&#38;#39;re ready to turn the family into configuration we... wait, &lt;i&gt;what??&lt;/i&gt; What&#38;#39;s &lt;i&gt;augment&lt;/i&gt;? Rather than a length explanation, here&#38;#39;s a snippet of the method definition from the base NodeFamily class:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;as_data_lines&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;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;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@lines&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@lines&lt;/span&gt;&lt;span class=&#34;operator&#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;rec&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;comment&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;begin family &#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#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;name&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;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@lines&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;word&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;inner&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;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@lines&lt;/span&gt;&lt;span class=&#34;operator&#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;rec&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;comment&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;end family &#38;quot;&lt;/span&gt; &lt;span class=&#34;operator&#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;name&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@lines&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;We&#38;#39;re going to return a list of lines. We create start and end comments, and get the rest by calling &lt;code&gt;inner&lt;/code&gt;. &lt;code&gt;inner&lt;/code&gt; is the other end of &lt;code&gt;augment&lt;/code&gt;. When we call &lt;code&gt;inner&lt;/code&gt;, the augment blocks get called in subclasses. With &#38;quot;normal&#38;quot; method calls, we&#38;#39;d end up entering the subclass&#38;#39;s method first, and it would decide how (and whether) to call the superclass&#38;#39;s method. Here, we&#38;#39;re working backward, in a sense: first the superclass method is begun, then any subclasses may contribute to the output, and then the superclass is finalized.&lt;/p&gt;

&lt;p&gt;This avoids any need to worry about calling the superclass method in subclasses, which can then write the simplest thing needed. &lt;i&gt;Unfortuantely&lt;/i&gt;, you can&#38;#39;t call &lt;code&gt;augment&lt;/code&gt; in a role. To get that kind of method composition, you may have to wait for a future Advent posting!&lt;/p&gt;

&lt;h2 id=&#34;A-Triumph-of-the-Moose&#34;&gt;A Triumph of the Moose&lt;/h2&gt;

&lt;p&gt;In the end, we replaced literally hundreds of thousands of lines of M4 with 42 very short class definitions -- our node families -- and one file per physical server. The new system can be the target of regression tests, either of individual groups or of the whole thing. Most of the time, the sysadmins can just edit simple YAML documents. Occasionally, node families need updating, but they&#38;#39;re all very simple Perl classes with only one or two methods of any note.&lt;/p&gt;

&lt;p&gt;Best of all, nobody needs to learn M4.&lt;/p&gt;

&lt;h2 id=&#34;See-Also&#34;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/DNS::Oterica&#34;&gt;DNS::Oterica&lt;/a&gt;&lt;/p&gt;

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

&lt;/div&gt;</summary><updated>2010-12-10T00:00:00-05:00</updated><category term="Perl"/><category term="RJBS"/></entry><entry><title>A Place to Shove Your Settings</title><link href="http://advent.rjbs.manxome.org/2010/2010-12-09.html"/><id>http://advent.rjbs.manxome.org/2010/2010-12-09.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h2 id=&#34;Because-132-Fields-Ought-To-Be-Enough-for-Anybody&#34;&gt;Because 132 Fields Ought To Be Enough for Anybody&lt;/h2&gt;

&lt;p&gt;A long time ago, I inherited a lot of shares in a pretty crufty old system. Like almost everything else you&#38;#39;re likely to find at a small software place, it had a bunch of objects that it stored in relational database -- and like you&#38;#39;d find a lot of places, there weren&#38;#39;t enough tables. (I once heard this problem described as, &#38;quot;It&#38;#39;s like some programmers think that they&#38;#39;re charged by the table.&#38;quot;) We had thousands of rows, each with well over a hundred fields, and we&#38;#39;d end up finding great stuff like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  mysql&#38;gt; SELECT use_oxford_comma, COUNT(*)
       &#38;gt; FROM customers
       &#38;gt; GROUP BY use_oxford_comma;

  +------------------+----------+
  | use_oxford_comma | COUNT(*) |
  +------------------+----------+
  | NULL             |    89162 |
  | 1                |        8 |
  | yes              |        1 |
  +------------------+----------+&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Creating extra tables for this sort of setting was the right thing to do, but that would&#38;#39;ve been a lot of tables, and let&#38;#39;s face it: there &lt;i&gt;is&lt;/i&gt; a charge per table. You have to add the table, add the class to your ORM, and update queries. Query costs change when you add more FKs between tables. We wanted to strike a balance between hundreds of rarely-used table and only one enormous table by offloading weird nearly-one-off data someplace else. The answer was pseudo-structured data storage in a key-value store. Not MongoDB or CouchDB or something like that, mind you -- just a table that looks something like this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;synStatement&#34;&gt;CREATE&lt;/span&gt; &lt;span class=&#34;synSpecial&#34;&gt;TABLE&lt;/span&gt; customer_hive (&lt;br /&gt;&#38;nbsp;&#38;nbsp;id          &lt;span class=&#34;synType&#34;&gt;INTEGER&lt;/span&gt; AUTO_INCREMENT PRIMARY KEY,&lt;br /&gt;&#38;nbsp;&#38;nbsp;customer_id &lt;span class=&#34;synType&#34;&gt;INTEGER&lt;/span&gt; REFERENCES customers (id),&lt;br /&gt;&#38;nbsp;&#38;nbsp;hive_key    STRING,&lt;br /&gt;&#38;nbsp;&#38;nbsp;hive_val    STRING,&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;synSpecial&#34;&gt;UNIQUE&lt;/span&gt; KEY (customer_id, hive_key)&lt;br /&gt;);&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;What are the hive key and value? The key is a &lt;a href=&#34;http://use.perl.org/~Ovid/journal/39460&#34;&gt;materialized path&lt;/a&gt; for the value, which is just, well, a value. Every value can only be typed as a string, but that&#38;#39;s okay. If we get worried about the type, we&#38;#39;ll move the data to its own table later. So, what do entries in this table look like? Maybe something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  mysql&#38;gt; SELECT hive_key, hive_val FROM customer_hive WHERE customer_id = 123;

  +-------------------------------------------+----------+
  | hive_key                                  | hive_val |
  +-------------------------------------------+----------+
  | formatting.use_oxford_comma               |   always |
  | formatting.spaces_after_period            |        2 |
  | reports                                   |        1 |
  | reports.activity.daily.include_moon_phase |        1 |
  +-------------------------------------------+----------+&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So we&#38;#39;re really storing something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;                                     (root)
                                    /      \
                                   /        \
                         formatting          \
                            /      \          reports: 1
        use_oxford_comma: always    \               \
                                     \              activity
                        spaces_after_period: 2            \
                                                         daily
                                                          \
                                                          include_moon_phase: 1&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(Notice that this can&#38;#39;t be represented as a hash, because we have parts of the hierarchy, like &lt;code&gt;reports&lt;/code&gt; that have both values and subtrees!)&lt;/p&gt;

&lt;p&gt;What we needed next was a convenient way to access these data, and that&#38;#39;s where &lt;a href=&#34;https://metacpan.org/module/Data::Hive&#34;&gt;Data::Hive&lt;/a&gt; came in to play.&lt;/p&gt;

&lt;h3 id=&#34;Yet-Another-Hashes-as-Objects-Schema&#34;&gt;Yet Another Hashes-as-Objects Schema&lt;/h3&gt;

&lt;p&gt;We called this structure a hive, in honor of the Windows registry -- always a good role model for software design. We wanted it to be as simple to use for new data as possible, so we could just plow forward with new code and never think about how the settings were being saved. If the setting became important or significantly-used, we could move it, later, to a more strictly-typed part of the schema. For now, the goal was to allow for rapid development. The interface for setting up a hive like the one above would be:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$hive&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Data::Hive&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;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;symbol&#34;&gt;$hive&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;formatting&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;use_oxford_comma&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;SET&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;always&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$hive&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;formatting&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;spaces_after_period&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;SET&lt;/span&gt;&lt;span class=&#34;structure&#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;br /&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$hive&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;reports&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;SET&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;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$hive&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;reports&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;activity&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;daily&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;include_moon_phase&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;SET&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;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;...and maybe later...&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&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;$hive&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;formatting&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;use_oxford_comma&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;GET&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;never&#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;comment&#34;&gt;# never = default&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;That&#38;#39;s it! Now, we didn&#38;#39;t have to predeclare any of the potential structure of our hive -- that would not be simple enough. So, how did these methods work? Well, we&#38;#39;re using another usually-the-wrong-solution feature of Perl, &lt;a href=&#34;https://metacpan.org/module/perlsub#Autoloading&#34;&gt;autoloading&lt;/a&gt;. As you call not-all-caps methods, you just keep getting back another proxy object for the path you build. Eventually, you call something like &lt;code&gt;GET&lt;/code&gt; or &lt;code&gt;SET&lt;/code&gt; or &lt;code&gt;DELETE&lt;/code&gt; to deal with the underlying data.&lt;/p&gt;

&lt;h3 id=&#34;Hooking-it-All-Up&#34;&gt;Hooking it All Up&lt;/h3&gt;

&lt;p&gt;So, where &lt;i&gt;is&lt;/i&gt; the underlying data? Data::Hive doesn&#38;#39;t care. Its concern is mapping the path-descending interface to something else -- and that something else is a storage driver. In other words, &#38;quot;bring your own underlying data access code.&#38;quot; For the sake of testing, it comes with some simple storage drivers that store hives in hashrefs. This isn&#38;#39;t too useful, though, because we (or I, at least) want to use hives to store persistent data. Fortunately, one of our drivers can store to anything implementing a set of &lt;a href=&#34;https://metacpan.org/module/CGI&#34;&gt;CGI.pm&lt;/a&gt;-like &lt;code&gt;params&lt;/code&gt; methods.&lt;/p&gt;

&lt;p&gt;We also don&#38;#39;t just want standalone hives. We want hives that are associated with other objects. We want to be able to decorate any arbitrary object with a hive to add ad hoc hierarchical data to an object. We looked at a system for doing this in last year&#38;#39;s calendar; there was a whole article about &lt;a href=&#34;http://advent.rjbs.manxome.org/2009/2009-12-22.html&#34;&gt;Mixin::ExtraFields&lt;/a&gt;. (You might want to review it.) ExtraFields &lt;i&gt;also&lt;/i&gt; has storage drivers, some of which persist the extra fields into databases. There&#38;#39;s also a Data::Hive-specific subclass that lets you associate hives with objects just like you can extras.&lt;/p&gt;

&lt;p&gt;What does that mean? It means that for any object you want, you can write something like this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;MyApp::Customer&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;Mixin::ExtraFields::Hive&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;-hive&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;driver&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;class&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;DBIC&#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;schema&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;MyApp::Schema&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;connect&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;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;rs_moniker&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;CustomerHive&#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;name_column&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;hive_key&#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;value_column&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;hive_val&#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;structure&#34;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;That little &lt;code&gt;use&lt;/code&gt; statement means that we can now write:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$formatting_hive&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$customer&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;hive&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;formatting&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;$formatting_hive&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;use_oxford_comma&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;DELETE&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$formatting_hive&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;page_numbers&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;number_index&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;SET&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;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;...and all the changes will be made for us in a &lt;a href=&#34;https://metacpan.org/module/DBIx::Class&#34;&gt;DBIx::Class&lt;/a&gt;-managed table, without any need to worry about how it works. Later, we can change the backend for storage and nothing needs to know.&lt;/p&gt;

&lt;h2 id=&#34;See-Also&#34;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Data::Hive&#34;&gt;Data::Hive&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Mixin::ExtraFields&#34;&gt;Mixin::ExtraFields&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Mixin::ExtraFields::Hive&#34;&gt;Mixin::ExtraFields::Hive&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Mixin::ExtraFields::Driver::DBIC&#34;&gt;Mixin::ExtraFields::Driver::DBIC&lt;/a&gt;&lt;/p&gt;

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

&lt;/div&gt;</summary><updated>2010-12-09T00:00:00-05:00</updated><category term="Perl"/><category term="RJBS"/></entry><entry><title>Option Processing -- This Time, Invented Here!</title><link href="http://advent.rjbs.manxome.org/2010/2010-12-08.html"/><id>http://advent.rjbs.manxome.org/2010/2010-12-08.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h2 id=&#34;Everybodys-Favorite-Getopt&#34;&gt;Everybody&#38;#39;s Favorite Getopt&lt;/h2&gt;

&lt;p&gt;This isn&#38;#39;t everybody&#38;#39;s favorite getopt. It&#38;#39;s &lt;i&gt;my&lt;/i&gt; favorite getopt, and it might be the favorite of some other people, but the problem with getopt libraries is that they can be optimized for so many different needs... but most of the time no optimization is needed, so we each get attached to the library we&#38;#39;re using most often, forgetting that there are lots of reasons to choose differently.&lt;/p&gt;

&lt;p&gt;Well, I&#38;#39;m not here to tolerate other people&#38;#39;s libraries. The &lt;a href=&#34;http://advent.rjbs.manxome.org/2010/2010-12-05.html&#34;&gt;time for tolerance&lt;/a&gt; is past. I&#38;#39;m going to talk about &lt;i&gt;my&lt;/i&gt; favorite getopt library. In what may be a first for the RJBS Advent Calendar, it&#38;#39;s a library I didn&#38;#39;t write. It was written by my former co-worker &lt;a href=&#34;https://metacpan.org/author/HDP&#34;&gt;Dieter&lt;/a&gt;, and I remember very clearly how happy I was when I started that the &#38;quot;which getopt?&#38;quot; question had not only been answered already, but had been answered with a library that I liked using.&lt;/p&gt;

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

&lt;p&gt;So, if all getopt libraries make tradeoffs, what are ours? We wanted it to be very easy to read and write option specifications, and we &lt;i&gt;needed&lt;/i&gt; the command to get a usage message that was &lt;i&gt;always&lt;/i&gt; correct and up to date with the usage message. Our non-technical staff all use a Unix shell, and run a lot of command-line programs. They need to have useful help messages to forestall questions about how to use things.&lt;/p&gt;

&lt;p&gt;To use Getopt::Long::Descriptive (aka GLD), you basically describe the options you&#38;#39;d like to accept and get back the options parsed from &lt;code&gt;@ARGV&lt;/code&gt; and an object representing the &#38;quot;usage message.&#38;quot; Here&#38;#39;s a fairly complete program using GLD:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;br /&gt;16:&#38;nbsp;&lt;br /&gt;17:&#38;nbsp;&lt;br /&gt;18:&#38;nbsp;&lt;br /&gt;19:&#38;nbsp;&lt;br /&gt;20:&#38;nbsp;&lt;br /&gt;21:&#38;nbsp;&lt;br /&gt;22:&#38;nbsp;&lt;br /&gt;23:&#38;nbsp;&lt;br /&gt;24:&#38;nbsp;&lt;br /&gt;25:&#38;nbsp;&lt;br /&gt;26:&#38;nbsp;&lt;br /&gt;27:&#38;nbsp;&lt;br /&gt;28:&#38;nbsp;&lt;br /&gt;29:&#38;nbsp;&lt;br /&gt;30:&#38;nbsp;&lt;br /&gt;31:&#38;nbsp;&lt;br /&gt;32:&#38;nbsp;&lt;br /&gt;33:&#38;nbsp;&lt;br /&gt;34:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&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;$opt&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$usage&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;describe_options&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;%c %o recipient  ...&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;template|t=s&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;the HTML template for the card&#38;quot;&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;default&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;card.html&#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;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;from|f=s&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;     &lt;span class=&#34;double&#34;&gt;&#38;quot;the sending address&#38;quot;&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;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;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;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;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;text-mode&#38;quot;&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;=&#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;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;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;one_of&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;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;html-only&#38;quot;&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;send no plaintext part&#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;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;autotext&#38;quot;&lt;/span&gt;     &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;generate plaintext from HTML&#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;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;text-tmpl=s&#38;quot;&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;filename for a separate plaintext template&#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;&#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;&#38;nbsp;&#38;nbsp;&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;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@rcpts&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@ARGV&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;symbol&#34;&gt;$usage&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;die&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;({&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;pre_text&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;no recipients given!&#38;quot;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;})&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@rcpts&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;$html_template&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;slurp&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$opt&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;template&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;$text_template&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$opt&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;text_mode&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;html_only&#39;&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;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;&lt;span class=&#34;operator&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$opt&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;text_mode&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;autotext&#39;&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;textify&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$html_template&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;&#38;nbsp;&#38;nbsp;&#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;$opt&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;text_mode&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;text_tmpl&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;slurp&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$opt&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;text_tmpl&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;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#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;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;$rcpt&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@rcpts&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;send_card&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;html&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;render&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$html_template&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$rcpt&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;text&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;render&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$text_template&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$rcpt&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;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;to&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$rcpt&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;from&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$opt&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;from&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Some of this is obvious, especially if you know Getopt::Long, but have another slow read through the code, and then we&#38;#39;ll walk through it piece by piece.&lt;/p&gt;

&lt;h3 id=&#34;describe_options&#34;&gt;&lt;code&gt;describe_options&lt;/code&gt;&lt;/h3&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&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;$opt&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$usage&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;describe_options&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;single&#34;&gt;&#39;%c %o recipient  ...&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;template|t=s&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;the HTML template for the card&#38;quot;&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;default&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;card.html&#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;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;from|f=s&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;     &lt;span class=&#34;double&#34;&gt;&#38;quot;the sending address&#38;quot;&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;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;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;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;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;text-mode&#38;quot;&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;=&#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;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;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;one_of&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;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;html-only&#38;quot;&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;send no plaintext part&#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;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;autotext&#38;quot;&lt;/span&gt;     &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;generate plaintext from HTML&#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;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;text-tmpl=s&#38;quot;&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;filename for a separate plaintext template&#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;&#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;&#38;nbsp;&#38;nbsp;&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;&lt;code&gt;describe_options&lt;/code&gt; doesn&#38;#39;t really &lt;i&gt;just&lt;/i&gt; describe the options. It parses the command line arguments by reading &lt;code&gt;@ARGV&lt;/code&gt; and returns an object describing the switches that were given (&lt;code&gt;$opt&lt;/code&gt;) and another object that can be used to print out a usage message in case of error. If &lt;code&gt;@ARGV&lt;/code&gt; can&#38;#39;t be parsed legally, that message is printed and the program dies, something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  send-holiday-card [-ft] [long options...] recipient ...
    -t --template     the HTML template for the card
    -f --from         the sending address
  
    --html-only       set no plaintext part
    --autotext        generate plaintext from HTML
    --text-tmpl       filename for a separate plaintext template&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The first argument to &lt;code&gt;describe_options&lt;/code&gt; produces the first line of the usage message. It uses &lt;code&gt;sprintf&lt;/code&gt;-like formatting, letting you get the name of the script and a quick summary of available options into the usage message.&lt;/p&gt;

&lt;p&gt;After that, everything describes options. Each argument is an arrayref with up to three entries:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt;  &lt;span class=&#34;symbol&#34;&gt;$switch&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$description&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;\&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;%options&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;The contents of &lt;code&gt;$switch&lt;/code&gt; value might look familiar. It&#38;#39;s just a Getopt::Long-style description of the switch. GLD is not so ambitious as to try to implement its own argument processor! It&#38;#39;s just a layer on top of Getopt::Long and some other tools. So, every &lt;code&gt;$switch&lt;/code&gt; value can have a few names, separated by pipes. The first name (with some mild munging, like &lt;code&gt;s/-/_/&lt;/code&gt;, becomes the name of the accessor on &lt;code&gt;$opt&lt;/code&gt;. That&#38;#39;s why later we can call &lt;code&gt;$opt-&#38;gt;from&lt;/code&gt; to get the value given for &lt;code&gt;--form&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;$description&lt;/code&gt; field is just the description for the option in the usage message. The description &#38;quot;hidden&#38;quot; means that an option isn&#38;#39;t displayed in the usage message, and an entirely empty option, like &lt;code&gt;[]&lt;/code&gt;, by the way, means &#38;quot;put a blank line in the usage message.&#38;quot;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;%options&lt;/code&gt;, which is optional, changes how the switch is interpreted. It can take a bunch of options, but the most common are &lt;code&gt;required&lt;/code&gt; and &lt;code&gt;default&lt;/code&gt;, which change what happens if no value was given. The value can also be validated by using &lt;a href=&#34;https://metacpan.org/module/Params::Validate&#34;&gt;Params::Validate&lt;/a&gt; arguments.&lt;/p&gt;

&lt;p&gt;The most interesting kind of option is &lt;code&gt;one_of&lt;/code&gt;, as seen in:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;text-mode&#38;quot;&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;=&#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;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;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;one_of&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;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;html-only&#38;quot;&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;send no plaintext part&#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;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;autotext&#38;quot;&lt;/span&gt;     &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;generate plaintext from HTML&#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;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;structure&#34;&gt;[&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;text-tmpl=s&#38;quot;&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;filename for a separate plaintext template&#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;&#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;&#38;nbsp;&#38;nbsp;&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;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;&lt;code&gt;one_of&lt;/code&gt; is usually used in combination with &lt;code&gt;hidden&lt;/code&gt;, and creates a sort of virtual option. &lt;code&gt;$opt-&#38;gt;text_mode&lt;/code&gt; will tell us which of the sub-options was used, and then we can check that option&#38;#39;s value. Only one of the sub-options can be specified. That&#38;#39;s why we could safely write this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$text_template&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$opt&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;text_mode&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;html_only&#39;&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;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;&lt;span class=&#34;operator&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$opt&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;text_mode&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;autotext&#39;&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;textify&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$html_template&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;&#38;nbsp;&#38;nbsp;&#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;$opt&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;text_mode&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;text_tmpl&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;slurp&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$opt&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;text_tmpl&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;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;operator&#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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;&lt;code&gt;one_of&lt;/code&gt; options are useful for establishing mutually exclusive kinds of operation, and were originally set up to create something like a &#38;quot;run mode.&#38;quot; There&#38;#39;d be a hidden &lt;code&gt;mode&lt;/code&gt; option, and the user would pick &lt;code&gt;one_of&lt;/code&gt; &#38;quot;delete&#38;quot; or &#38;quot;add&#38;quot; or &#38;quot;list,&#38;quot; for example. Our use of virtual options for that has faded after the creation of &lt;a href=&#34;http://advent.rjbs.manxome.org/2009/2009-12-14.html&#34;&gt;App::Cmd&lt;/a&gt;, a framework for slightly more complicated applications. App::Cmd helps make command-line applications easy to write, but it isn&#38;#39;t so ambitious as to try to provide its own getopt implementation: to use App::Cmd properly, you need to first understand Getopt::Long::Descriptive.&lt;/p&gt;

&lt;h2 id=&#34;See-Also&#34;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Getopt::Long::Descriptive&#34;&gt;Getopt::Long::Descriptive&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Getopt::Long&#34;&gt;Getopt::Long&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Params::Validate&#34;&gt;Params::Validate&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/App::Cmd&#34;&gt;App::Cmd&lt;/a&gt;&lt;/p&gt;

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

&lt;/div&gt;</summary><updated>2010-12-08T00:00:00-05:00</updated><category term="Perl"/><category term="RJBS"/></entry><entry><title>Safe, Simple, Deadly</title><link href="http://advent.rjbs.manxome.org/2010/2010-12-07.html"/><id>http://advent.rjbs.manxome.org/2010/2010-12-07.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h2 id=&#34;Making-Exception-Testing-Easier&#34;&gt;Making Exception Testing Easier&lt;/h2&gt;

&lt;p&gt;I do not like &#38;quot;returns false on failure.&#38;quot; Even worse is &#38;quot;returns a result or some magic error value.&#38;quot; Part of this is based in reason and part in irrational reaction to a personal history of dealing with really, really bad APIs. The result is that when I write a subroutine that returns a value, it&#38;#39;s very likely to follow these simple rules:&lt;/p&gt;

&lt;ol&gt;

&lt;li&gt;&lt;p&gt;return a value of a known type, if everything worked; &#38;quot;false&#38;quot; is okay too&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;if something went wrong, throw an exception&lt;/p&gt;

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

&lt;p&gt;I &lt;i&gt;do&lt;/i&gt; like testing my code. Testing case 1, from above, is easy!&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Gift::Wrapper&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(wrap)&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;Test::More&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;$gift&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;wrap&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$input&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;isa_ok&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$gift&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Wrapped::Gift&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;is&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$gift&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;contents&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$input&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;That&#38;#39;s nice and simple and straightforward! There&#38;#39;s no code there that doesn&#38;#39;t contribute to the very thing we&#38;#39;re testing. What about testing case 2, though&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Gift::Wrapper&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(wrap)&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;Test::More&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;$okay&lt;/span&gt;  &lt;span class=&#34;operator&#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;word&#34;&gt;wrap&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$coal&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;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;$error&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;&lt;span class=&#34;word&#34;&gt;ok&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;$okay&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;we can&#39;t wrap coal&#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;is&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$error&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;ident&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;  &lt;span class=&#34;single&#34;&gt;&#39;coal is not a good gift&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;That &#38;quot;eval and check result and capture &lt;code&gt;$@&lt;/code&gt;&#38;quot; is going to get pretty tedious, pretty quickly. Also, if our tests are part of some larger test program -- which they probably are -- then we&#38;#39;re missing a bunch of extra safety. That&#38;#39;s why we&#38;#39;d &lt;i&gt;never&lt;/i&gt; use &lt;code&gt;eval&lt;/code&gt;, right? We all use &lt;a href=&#34;https://metacpan.org/module/Try::Tiny&#34;&gt;Try::Tiny&lt;/a&gt; instead! With that, our code would look like this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Gift::Wrapper&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(wrap)&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;Test::More&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;$error&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;try&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;wrap&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$coal&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;span class=&#34;word&#34;&gt;catch&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;$error&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;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;finally&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;die&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;bizarre error condition&#38;quot;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;magic&#34;&gt;@_&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;not&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;number&#34;&gt;0&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;ok&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;$okay&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;we can&#39;t wrap coal&#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;is&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$error&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;ident&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt;  &lt;span class=&#34;single&#34;&gt;&#39;coal is not a good gift&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Woah, what? Now we&#38;#39;re in a world of hurt, and there&#38;#39;s no chance that we&#38;#39;ll ever write that over and over. And what&#38;#39;s up with that &lt;code&gt;finally&lt;/code&gt; block with the weird &lt;code&gt;die&lt;/code&gt;? Well, Perl has some really bizarre (read: awful) semantics with exception handling, and in a number of cases it can die but leave &lt;code&gt;$@&lt;/code&gt; empty. Try::Tiny helps us deal with these situations, but only at the first order. Here, we want a higher-order check of our exception status.&lt;/p&gt;

&lt;p&gt;Obviously, this is all lead in to the simple way to check this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Gift::Wrapper&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(wrap)&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;Test::More&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;Test::Fatal&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;$error&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;exception&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;wrap&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$coal&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;isnt&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$error&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;double&#34;&gt;&#38;quot;we can&#39;t wrap coal&#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;is&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$error&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;ident&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;coal is not a good gift&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;&lt;code&gt;exception&lt;/code&gt; always returns a scalar: the exception that was thrown, if any, or &lt;code&gt;undef&lt;/code&gt; otherwise. In the event that the code died, but no exception could be found -- a highly problematic case -- &lt;code&gt;exception&lt;/code&gt; itself will die. The routine&#38;#39;s &#38;quot;returns a scalar&#38;quot; behavior makes it excellent for use inline in test assertions:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;comment&#34;&gt;# test that we died&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;ok&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;exception&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;wrap&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;core&#34;&gt;undef&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;double&#34;&gt;&#38;quot;no empty boxes!&#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;comment&#34;&gt;# test that we got the exception we wanted, more or less&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;like&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;exception&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;wrap&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;gift certificate&#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;&lt;span class=&#34;regexp&#34;&gt;qr{show some imagination!}&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;# test that we lived!&lt;br /&gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;ok&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;span class=&#34;word&#34;&gt;exception&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;wrap&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;toy train&#38;quot;&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;double&#34;&gt;&#38;quot;nothing wrong with wrapping a toy train&#38;quot;&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;h3 id=&#34;A-Quick-Note-about-Test::Exception&#34;&gt;A Quick Note about Test::Exception&lt;/h3&gt;

&lt;p&gt;Test::Fatal is not the only library for this kind of testing. There also exists &lt;a href=&#34;https://metacpan.org/module/Test::Exception&#34;&gt;Test::Exception&lt;/a&gt;, which also provides tools for testing. Test::Exception has more moving pieces than Test::Fatal, including the highly complex &lt;a href=&#34;https://metacpan.org/module/Sub::Uplevel&#34;&gt;Sub::Uplevel&lt;/a&gt;. In almost all cases, its complexity is not needed, and you will be better served by the simple &lt;code&gt;exception&lt;/code&gt; routine than by the handful of test assertions provided by Test::Exception -- but it takes all kinds.&lt;/p&gt;

&lt;h2 id=&#34;See-Also&#34;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Test::Fatal&#34;&gt;Test::Fatal&lt;/a&gt;&lt;/p&gt;

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

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Test::Exception&#34;&gt;Test::Exception&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Sub::Uplevel&#34;&gt;Sub::Uplevel&lt;/a&gt;&lt;/p&gt;

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

&lt;/div&gt;</summary><updated>2010-12-07T00:00:00-05:00</updated><category term="Perl"/><category term="RJBS"/></entry><entry><title>Feast of St. Burl</title><link href="http://advent.rjbs.manxome.org/2010/2010-12-06.html"/><id>http://advent.rjbs.manxome.org/2010/2010-12-06.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h3 id=&#34;NOT-ON-THE-CPAN&#34;&gt;NOT ON THE CPAN&lt;/h3&gt;

&lt;p&gt;Today&#38;#39;s article is about code not found on the CPAN.&lt;/p&gt;

&lt;h2 id=&#34;The-Good-Old-Days&#34;&gt;The Good Old Days&lt;/h2&gt;

&lt;p&gt;Today is the feast of St. Burl, the little known patron saint of gophers. In his honor, I&#38;#39;d like to talk a little about the Gopher protocol and my on-again, off-again affection for it.&lt;/p&gt;

&lt;p&gt;Since I first made a home page some time around 1995, it has included an opening something like this:&lt;/p&gt;



&lt;blockquote&gt;

&lt;p&gt;I made my first home page back when HTML 1.1 was just coming out and some guy named Mozilla was releasing Netscape, which he said would replace the NCSA Mosaic browser. I&#38;#39;ll let you in on a little secret: I didn&#38;#39;t believe for a minute that HTTP would replace such tried-and-true services as Archie, Veronica, and (my favorite) Gopher.&lt;/p&gt;



&lt;/blockquote&gt;

&lt;p&gt;Eventually, though very late, I accepted that Gopher was done for, but I&#38;#39;d think back on it fondly from time to time. As HTML and CSS and JavaScript and XML and the rest of the web got more and more complicated, and there were more and more &#38;quot;best viewed in Webbernet SurfPro&#38;quot; badges or &#38;quot;required plugin missing&#38;quot; errors, I&#38;#39;d remember the nice, simple Gopher system. You&#38;#39;d basically get two things from it: directories and files. There was nothing to screw up!&lt;/p&gt;

&lt;p&gt;Years later, when I had learned how to write non-trivial programs, I decided I would write a Gopher server, which meant reading &lt;a href=&#34;http://www.faqs.org/rfcs/rfc1436.html&#34;&gt;the Gopher spec&lt;/a&gt;. It looked sort of weird, but easy enough to implement a test server:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;br /&gt;15:&#38;nbsp;&lt;br /&gt;16:&#38;nbsp;&lt;br /&gt;17:&#38;nbsp;&lt;br /&gt;18:&#38;nbsp;&lt;br /&gt;19:&#38;nbsp;&lt;br /&gt;20:&#38;nbsp;&lt;br /&gt;21:&#38;nbsp;&lt;br /&gt;22:&#38;nbsp;&lt;br /&gt;23:&#38;nbsp;&lt;br /&gt;24:&#38;nbsp;&lt;br /&gt;25:&#38;nbsp;&lt;br /&gt;26:&#38;nbsp;&lt;br /&gt;27:&#38;nbsp;&lt;br /&gt;28:&#38;nbsp;&lt;br /&gt;29:&#38;nbsp;&lt;br /&gt;30:&#38;nbsp;&lt;br /&gt;31:&#38;nbsp;&lt;br /&gt;32:&#38;nbsp;&lt;br /&gt;33:&#38;nbsp;&lt;br /&gt;34:&#38;nbsp;&lt;br /&gt;35:&#38;nbsp;&lt;br /&gt;36:&#38;nbsp;&lt;br /&gt;37:&#38;nbsp;&lt;br /&gt;38:&#38;nbsp;&lt;br /&gt;39:&#38;nbsp;&lt;br /&gt;40:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&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;IO::Socket&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;$port&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;70&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;$crlf&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;\015\012&#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;$socket&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;IO::Socket::INET&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;&lt;span class=&#34;word&#34;&gt;Proto&lt;/span&gt;     &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;tcp&#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;LocalPort&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$port&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;Listen&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;128&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;Reuse&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;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;warn&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;waiting for incoming connections on port $port...\n&#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;while&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;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;next&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$connection&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$socket&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;accept&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;word&#34;&gt;fork&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;symbol&#34;&gt;$connection&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;close&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;next&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;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;&lt;span class=&#34;symbol&#34;&gt;$connection&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;autoflush&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;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;$request&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$connection&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;getline&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;symbol&#34;&gt;$request&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;substitute&#34;&gt;s/$crlf//g&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;word&#34;&gt;STDERR&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;REQUEST: $request\n&#38;quot;&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;symbol&#34;&gt;$request&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$request&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;eq&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;/&#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;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$connection&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;1Directory Listing\t/\tlocalhost\t70$crlf&#38;quot;&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;symbol&#34;&gt;$connection&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;0README.TXT\tREADME.TXT\tlocalhost\t70$crlf&#38;quot;&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;symbol&#34;&gt;$connection&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;0README.TxT\tREADME.TxT\tlocalhost\t70$crlf&#38;quot;&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;symbol&#34;&gt;$connection&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;.$crlf&#38;quot;&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;br /&gt;&#38;nbsp;&#38;nbsp;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;symbol&#34;&gt;$connection&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;close&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;symbol&#34;&gt;$socket&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;close&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;All this server could do was print a directory. You could ask for the other stuff it had to offer, but you wouldn&#38;#39;t get it. Anyway, the directory is good enough for us to look at Gopher a little. It&#38;#39;s a bunch of tab-delimited lines, which would look like this, as a table:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  +--------------------+------------+-----------+------+
  | Type, Display Name | Selector   | Host      | Post |
  +--------------------+------------+-----------+------+
  | 1Directory Listing | /          | localhost |   70 |
  | 0README.TXT        | README.TXT | localhost |   70 |
  | 0README.TxT        | README.TxT | localhost |   70 |
  +--------------------+------------+-----------+------+&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The Gopher request to get that listing goes like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  CLIENT: connect, send &#38;quot;/&#38;quot; and CRLF
  SERVER: send tab-delimited lines, followed by . and CRLF, then disconnect&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Simple!&lt;/p&gt;

&lt;p&gt;When the Gopher client gets that table, it turns it into a menu like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  [ Dir  ]  Directory Listing
  [ File ]  README.TXT
  [ File ]  README.TxT&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The user can pick one of three options and get a new document. The first option leads to another directory and the other two lead to files. We know this because the first character of the lines was either &lt;code&gt;0&lt;/code&gt; (a directory) or &lt;code&gt;1&lt;/code&gt; (a file). This is crucial, because we need to know, if we&#38;#39;re getting a text file, that we shouldn&#38;#39;t look for tabs and display it as a menu.&lt;/p&gt;

&lt;p&gt;This leads to the first big problem. See, imagine what happens if we try to get &lt;i&gt;README.TXT&lt;/i&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  CLIENT: connect, send &#38;quot;README.TXT&#38;quot; and CRLF
  SERVER: send a bunch of lines, followed by . and CRLF, then disconnect&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;How do we know that what we got back was a text file and not a directory listing? There&#38;#39;s nothing in the request or the response telling us. We need to know &lt;i&gt;before&lt;/i&gt; making the request, because the &lt;i&gt;directory&lt;/i&gt; told us what to expect. Gopher predates URIs, but if it didn&#38;#39;t, we might imagine that the URI for the README file was the whole line:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  0README.TXT\tREADME.TXT\tlocalhost\t70 &lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In fact, when Gopher was given its own scheme, the above locator would look read &lt;code&gt;gopher://localhost:70/0README.TXT&lt;/code&gt; but it would often be rewritten as &lt;code&gt;gopher://localhost:70/0/README.TXT&lt;/code&gt;. (In HTTP this problem doesn&#38;#39;t exist, because every response includes a declaration of the type of the content.)&lt;/p&gt;

&lt;p&gt;So, what does this mean in practical terms? My first guess was that it just meant that we&#38;#39;d have a simple transport layer to get bodies, and then a slightly more complex presentation layer to display the body based on what it expected. Unfortunately, that doesn&#38;#39;t play out. See, zero and one aren&#38;#39;t the only content types. There are about 124 possible values, although only a few are assigned. Here are two troublesome ones that are assigned:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  5 - binary file (for DOS)
  9 - binary file&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(How do the two differ? Nobody seems to have any idea.)&lt;/p&gt;

&lt;p&gt;The trouble is that you&#38;#39;re prohibited from encoding binary files, even if they contain the pattern CRLF-dot-CRLF. That means you can&#38;#39;t detect the end of stream, and there may not be a terminal CRLF. So, the client must wait until the server disconnects and &lt;b&gt;must not&lt;/b&gt; truncate any trailing dot-CRLF. In that case, how does it know when to stop reading? Only by getting hung up on. That means that the context of the request (that is, its appearance in some containing directory) influences not only the presentation, but also the behavior of the network client.&lt;/p&gt;

&lt;p&gt;If it doesn&#38;#39;t get that &#38;quot;end of body&#38;quot; sentinel, how does it know that it got the whole document? Well, it doesn&#38;#39;t.&lt;/p&gt;

&lt;p&gt;There are some other weird type identifiers. &#38;quot;g&#38;quot; means a GIF image, and &#38;quot;I&#38;quot; means &#38;quot;some kind of image file.&#38;quot; (It&#38;#39;s assumed that with broad types like &#38;quot;I&#38;quot; the client will decide what to do by interpreting the selector as a file name and looking at the extension.) Both &#38;quot;g&#38;quot; and &#38;quot;I&#38;quot; can be dot-terminated. &#38;quot;7&#38;quot; means &#38;quot;search engine,&#38;quot; and the client prompts the user for a search string to be concatenated to the selector before fetching. &#38;quot;7&#38;quot; is assumed to actually return a directory (a &#38;quot;1&#38;quot;).&lt;/p&gt;

&lt;p&gt;There are even some types for other protocols. For example, &#38;quot;T&#38;quot; points to an interactive tn3270 session. I must admit to being moved to feelings of nostalgia by that -- like finding &#38;quot;troff&#38;quot; as a top-level MIME-type-like classification for in an early email RFC. If we added &#38;quot;h&#38;quot; as a type for HTTP, we could say:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  +--------------------+------------+-------------------------+------+
  | Type, Display Name | Selector   | Host                    | Post |
  +--------------------+------------+-------------------------+------+
  | hAdvent Calendar   | /2010      | advent.rjbs.manxome.org |   70 |
  +--------------------+------------+-------------------------+------+&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We don&#38;#39;t need to mandate that &#38;quot;h&#38;quot; also means &#38;quot;expect HTML,&#38;quot; because HTTP requires that the server tell us what it&#38;#39;s giving us. Once we&#38;#39;re off into HTTP land, we really have entered a &lt;i&gt;web&lt;/i&gt; of interconnected documents of all types, using &lt;i&gt;uniform&lt;/i&gt; resource locators. (Did you notice, by the way, that because Gopher gives us &#38;quot;links&#38;quot; only in directory listings, we can&#38;#39;t provide hypertext in Gopher without a new type definition? A text file (&#38;quot;0&#38;quot;) in Gopher can&#38;#39;t contain links.&lt;/p&gt;

&lt;h2 id=&#34;Todays-Gift-As-Is&#34;&gt;Today&#38;#39;s Gift, As-Is&lt;/h2&gt;

&lt;p&gt;I still sometimes think back on the &lt;i&gt;apparent&lt;/i&gt; simplicity of Gopher. It could be emulated in HTML pretty easily. Maybe I&#38;#39;ll write a DTD for a subset of XHTML that gets you something like Gopher. In the past, though, I was young and idealistic and less willing to compromise. I really wanted to write a fun little framework for Gopher servers in Perl. I even wanted to make it part of my 2009 Advent calendar, but disappointment with the protocol and its implications for implementing and testing overwhelmed me.&lt;/p&gt;

&lt;p&gt;I have since given up the idea of ever finishing it, so I present to you, unfinished, &lt;a href=&#34;https://github.com/rjbs/net-gopher-server&#34;&gt;Net::Gopher::Server&lt;/a&gt;!&lt;/p&gt;

&lt;h2 id=&#34;See-Also&#34;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://github.com/rjbs/net-gopher-server&#34;&gt;Net::Gopher::Server&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;http://www.backpan.org/distribution/Net-Gopher/&#34;&gt;Net::Gopher&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Gopher::Server&#34;&gt;Gopher::Server&lt;/a&gt;&lt;/p&gt;

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

&lt;/div&gt;</summary><updated>2010-12-06T00:00:00-05:00</updated><category term="Perl"/><category term="RJBS"/></entry><entry><title type="html">It&#38;#39;s a Time for Tolerance</title><link href="http://advent.rjbs.manxome.org/2010/2010-12-05.html"/><id>http://advent.rjbs.manxome.org/2010/2010-12-05.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h2 id=&#34;Secret-Origins-&#34;&gt;Secret Origins!&lt;/h2&gt;

&lt;p&gt;Once upon a time, I was called upon to write a database for complex &lt;a href=&#34;http://en.wikipedia.org/wiki/Epitaxy&#34;&gt;semiconductor growth&lt;/a&gt; specifications. Very often, the specification would state that a given measurement had to be within a certain tolerance, rather than a specific value. For bizarre semi-political reasons, we couldn&#38;#39;t just provide outer limits and shoot for a center point. We had to track, through all parts of the system, the specific way in which the specification was... specified. That might be like any of the following:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  5
  &#38;gt; 5
  &#38;ge; 5
  &#38;lt; 5
  &#38;ge; 5
  5 &#38;plusmn; 1
  5 &#38;plusmn; 20%
  4 .. 6
  5 (-1 to +2)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;At the time, the need to stick to a given format was frustrating, but it drove me to write a library that has proven itself useful again and again -- mostly in weird situations, but I&#38;#39;m still happy to have a tool I only use once in a while.&lt;/p&gt;

&lt;h2 id=&#34;Tolerance-in-Form-and-Action&#34;&gt;Tolerance in Form and Action&lt;/h2&gt;

&lt;p&gt;A tolerance is an object that acts like a number for the sake of comparison.&lt;/p&gt;

&lt;p&gt;Rather than struggle to contrive a generic example, I&#38;#39;ll talk about how this code was originally used. Our customer is going to come to us with a specification for a product, and we want to be able to record that specification, overlay our own specifications, and then test results against it. The customer might give us the following set of requirements:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Number::Tolerant&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;$spec&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;customer&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;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;width&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;tolerance&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;words&#34;&gt;qw( 10  plus_or_minus       2)&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;depth&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;tolerance&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;words&#34;&gt;qw( 182 plus_or_minus_pct   5)&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;weight&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;tolerance&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;words&#34;&gt;qw( less_than 10 )&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;hue&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;tolerance&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;words&#34;&gt;qw( 630 to 740)&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Internally, we know what our production equipment&#38;#39;s capabilities are:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;symbol&#34;&gt;$spec&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;machine&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;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;width&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;tolerance&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;words&#34;&gt;qw( 7 to 10 )&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;depth&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;tolerance&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;words&#34;&gt;qw( less_than 184 )&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;weight&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;tolerance&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;words&#34;&gt;qw( less_than 50 )&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;hue&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;675&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;...and engineering doesn&#38;#39;t want to use anything too heavy, and have done some final design work, so they tack on:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;symbol&#34;&gt;$spec&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;engineering&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;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;width&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;9&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;weight&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;tolerance&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;words&#34;&gt;qw( less_than 2 )&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Now we have a bunch of different, separate specification documents, and we can have a quick review of them all:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;sub&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;tol_string&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;$tol&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;&lt;span class=&#34;word&#34;&gt;join&lt;/span&gt; &lt;span class=&#34;interpolate&#34;&gt;qq{\n}&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;word&#34;&gt;sprintf&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;%10s %s&#38;quot;&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;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$tol&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;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;word&#34;&gt;sort&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;keys&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$tol&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;for&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;keys&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%spec&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;double&#34;&gt;&#38;quot;\U$_\n&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;tol_string&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$spec&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;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;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;...to get...&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  CUSTOMER
       depth 182 +/- 5%
         hue 630 &#38;lt;= x &#38;lt;= 740
      weight x &#38;lt; 10
       width 10 +/- 2
  ENGINEERING
      weight x &#38;lt; 2
       width 9
  MACHINE
       depth x &#38;lt; 184
         hue 675
      weight x &#38;lt; 50
       width 7 &#38;lt;= x &#38;lt;= 10&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Composing these together is easy:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$final_spec&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;keyword&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;keys&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;%spec&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;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$this_spec&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$spec&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;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;keyword&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;keys&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$this_spec&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;symbol&#34;&gt;$final_spec&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;magic&#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;word&#34;&gt;tolerance&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;infinite&#39;&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;symbol&#34;&gt;$final_spec&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;magic&#34;&gt;$_&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;&#38;amp;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$this_spec&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;magic&#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;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;tol_string&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$final_spec&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;...and we get:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;     depth 172.9 &#38;lt;= x &#38;lt; 184
       hue 675
    weight x &#38;lt; 2
     width 9&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What just happened? Well, tolerances can be joined together logically with intersections and unions. When we want to produce the intersection of a bunch of tolerances, we just use the &lt;code&gt;&#38;amp;&lt;/code&gt; operator. Or, if you want to avoid weird overloading, you can use the &lt;code&gt;union&lt;/code&gt; method. When unions intersect, the result is either a new tolerance (like the unified depth specification above) or a constant giving the only permissible value. When a union would produce an impossible tolerance, an exception is thrown. I accidentally caused one of those when writing the above code. I&#38;#39;d picked a bad &lt;code&gt;hue&lt;/code&gt; for the machine spec and got:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  No valid intersection of (630 &#38;lt;= x &#38;lt;= 740) and (775) at...&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once we&#38;#39;ve gotten our final product, it&#38;#39;s easy to test against the spec:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;br /&gt;12:&#38;nbsp;&lt;br /&gt;13:&#38;nbsp;&lt;br /&gt;14:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$final_product&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;get_final_product&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;@errors&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;$prop&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;keys&lt;/span&gt; &lt;span class=&#34;cast&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$final_product&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;next&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;unless&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;exists&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$final_spec&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;$prop&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&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;$value&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$final_product&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;$prop&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;$spec&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$final_spec&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;$prop&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;};&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;next&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$value&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$spec&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;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@errors&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;$prop ($value) outside of specification ($spec)&#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;say&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@errors&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;...which might produce an error like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  weight (2.2) outside of specification (x &#38;lt; 2)&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;Testing-with-Tolerance&#34;&gt;Testing with Tolerance&lt;/h3&gt;

&lt;p&gt;Tolerances can also be handy for running automated tests. An output file&#38;#39;s size should fall into a given range, or we should process no more than a certain number of records, and so on. Using Number::Tolerant with tests can be useful when tolerances must be combined -- but it&#38;#39;s often just easier to use than Test::More&#38;#39;s &lt;code&gt;cmp_ok&lt;/code&gt;, which has pretty gross semantics. For example, compare:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Test::More&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;cmp_ok&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$x&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;&#38;gt;&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;10&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;cmp_ok&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$x&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;&#38;lt;&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;number&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;to:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Test::Tolerant&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;word&#34;&gt;is_tol&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$x&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;10 &#38;lt; x &#38;lt; 20&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Test::Tolerant&#34;&gt;Test::Tolerant&lt;/a&gt; is part of the Number-Tolerant distribution.&lt;/p&gt;

&lt;h2 id=&#34;See-Also&#34;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Number::Tolerant&#34;&gt;Number::Tolerant&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Test::Tolerant&#34;&gt;Test::Tolerant&lt;/a&gt;&lt;/p&gt;

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

&lt;/div&gt;</summary><updated>2010-12-05T00:00:00-05:00</updated><category term="Perl"/><category term="RJBS"/></entry><entry><title>83% of Advent Remaining</title><link href="http://advent.rjbs.manxome.org/2010/2010-12-04.html"/><id>http://advent.rjbs.manxome.org/2010/2010-12-04.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h2 id=&#34;Sufficiently-Advanced-ProgressBar-Technology&#34;&gt;Sufficiently Advanced (ProgressBar) Technology&lt;/h2&gt;

&lt;p&gt;At &lt;a href=&#34;http://www.yapc.org/America/previous-years/2004/&#34;&gt;YAPC::NA 2004&lt;/a&gt; in Buffalo, Damian Conway gave a talk on &#38;quot;Sufficiently Advanced Technologies,&#38;quot; in which he showed off a number of very simple interfaces for fairly complex operations. Among the libraries he talked about was &lt;a href=&#34;https://metacpan.org/module/Smart::Comments&#34;&gt;Smart::Comments&lt;/a&gt;, a source filter that turns comments into code. It had a bunch of functions, but one of them let you do this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Smart::Comments&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;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@input&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;acquire_input&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;@output&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;for&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$datum&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@input&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;comment&#34;&gt;### Analyzing [===|   ] % done&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@output&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;expensive_analysis&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$datum&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;...and your program would, on one line, cycle through stuff like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  Analyzing [|                ]   0% done
  Analyzing [===|             ]  25% done
  Analyzing [========|        ]  50% done
  Analyzing [============|    ]  75% done
  Analyzing [=================] 100% done&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Progress bars are hard to get right! Just look at any implementation you&#38;#39;ve seen in otherwise great, well-designed software, like Microsoft Windows. They often provide progress bars that jump between &#38;quot;almost done&#38;quot; and &#38;quot;-919 days remain.&#38;quot;&lt;/p&gt;

&lt;p&gt;Smart::Comments can have this problem, too, as the workload changes out from under it -- some items in &lt;code&gt;@input&lt;/code&gt;, for example, might be costly to analyze, for example. There might be &lt;code&gt;redo&lt;/code&gt; or &lt;code&gt;next&lt;/code&gt; statements, or &lt;code&gt;last&lt;/code&gt;s, all of which can interfere with proper job speed detection.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Acme::ProgressBar&lt;/code&gt; is &lt;i&gt;always&lt;/i&gt; accurate. No matter what the characteristics of the input are, no matter how the loop flow is altered, no matter what, Acme::ProgressBar is accurate. Only extreme system load or fatal signals can interfere with its accuracy.&lt;/p&gt;

&lt;p&gt;It&#38;#39;s very easy to use, too. It isn&#38;#39;t a source filter, and uses no complex features. It should never introduce bugs to your code and can be added or removed to your code easily. Written with Acme::ProgressBar instead, the above code would look like this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Acme::ProgressBar&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;@input&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;acquire_input&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;@output&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;progress&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;for&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$datum&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@input&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;push&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;@output&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;expensive_analysis&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$datum&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;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;...and would produce output like this (but all on one line, and I&#38;#39;ve omitted some lines for brevity&#38;#39;s sake):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  Progress: [          ] (calculating time remaining)
  Progress: [==        ] 8s remaining                         
  Progress: [====      ] 6s remaining                         
  Progress: [======    ] 4s remaining                         
  Progress: [========  ] 2s remaining                         
  Progress: [==========] 0s remaining                         &lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There can be a performance cost for using Acme::ProgressBar, but the impact varies from program to program. You should test it in your code before judging the performance costs.&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/rjbs/acme-progressbar/blob/master/lib/Acme/ProgressBar.pm&#34;&gt;The source code&lt;/a&gt; for Acme::ProgressBar may also be instructive.&lt;/p&gt;

&lt;h2 id=&#34;See-Also&#34;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Acme::ProgressBar&#34;&gt;Acme::ProgressBar&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Smart::Comments&#34;&gt;Smart::Comments&lt;/a&gt;&lt;/p&gt;

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

&lt;/div&gt;</summary><updated>2010-12-04T00:00:00-05:00</updated><category term="Perl"/><category term="RJBS"/></entry><entry><title>Exceptionally Extensible Exceptions</title><link href="http://advent.rjbs.manxome.org/2010/2010-12-03.html"/><id>http://advent.rjbs.manxome.org/2010/2010-12-03.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h2 id=&#34;Building-Exception-Classes-with-Moose&#34;&gt;Building Exception Classes with Moose&lt;/h2&gt;

&lt;p&gt;Perl 5 supports exception objects natively, with &lt;code&gt;&lt;a href=&#34;https://metacpan.org/module/perlfunc#die&#34;&gt;die&lt;/a&gt;&lt;/code&gt; and &lt;code&gt;&lt;a href=&#34;https://metacpan.org/module/perlfunc#eval&#34;&gt;eval&lt;/a&gt;&lt;/code&gt; and &lt;code&gt;$@&lt;/code&gt;, but there has traditionally not been any standard, core class for exception objects. This has been both good and bad, because it has encouraged many different people to produce their own exception classes -- some quite simple, and some quite complex. One fairly successful such system was &lt;a href=&#34;https://metacpan.org/module/Exception::Class&#34;&gt;Exception::Class&lt;/a&gt;, a framework for quickly building exception classes. It provided a number of generic class-building features, and you&#38;#39;d use them to build classes for your exceptions.&lt;/p&gt;

&lt;p&gt;These days, we have a much better and more powerful system for building classes: &lt;a href=&#34;https://metacpan.org/module/Moose&#34;&gt;Moose&lt;/a&gt;. &lt;a href=&#34;https://metacpan.org/module/Throwable&#34;&gt;Throwable&lt;/a&gt; is a tiny Moose role for turning generic Moose classes into throwable exceptions. If you&#38;#39;ve written:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Catastrophe&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;br /&gt;&lt;span class=&#34;word&#34;&gt;has&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;description&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;ro&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &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;single&#34;&gt;&#39;Str&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &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;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;You can turn that into a throwable exception by adding...&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;word&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(Throwable StackTrace::Auto)&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Now you can call use &lt;code&gt;Catastrophe-&#38;gt;throw(...)&lt;/code&gt; and it means the same thing as &lt;code&gt;die Catastrophe-&#38;gt;new(...)&lt;/code&gt;, and it&#38;#39;s given a &lt;code&gt;stack_trace&lt;/code&gt; attribute that contains a &lt;a href=&#34;https://metacpan.org/module/Devel::StackTrace&#34;&gt;Devel::StackTrace&lt;/a&gt; so you can tell where the catastrophe happened. &#38;quot;&lt;i&gt;But wait!&lt;/i&gt;&#38;quot; you cry, &#38;quot;that stack trace isn&#38;#39;t coming from Throwable!&#38;quot; That&#38;#39;s right, it&#38;#39;s not. It&#38;#39;s coming from another library that&#38;#39;s meant to work well as part of an exception class, but it&#38;#39;s totally optional. Sometimes, after all, you want exceptions for flow control and not error reporting, and in those cases a stack trace is a needless expense.&lt;/p&gt;

&lt;p&gt;Over time, I&#38;#39;ve found other behaviors I really want in my exceptions, and I threw them all into an experimental &lt;a href=&#34;https://metacpan.org/module/Throwable::X&#34;&gt;Throwable::X&lt;/a&gt; role -- but rather than actually talk about &lt;i&gt;that&lt;/i&gt;, it will be more useful to look at the pieces that make up Throwable::X, because you can use them one by one.&lt;/p&gt;

&lt;h3 id=&#34;One-Arg-Exception-Throwing&#34;&gt;One-Arg Exception Throwing&lt;/h3&gt;

&lt;p&gt;The first thing I ever did with Exception::Class was to make it possible to call &lt;code&gt;throw&lt;/code&gt; with only one arg. Why give named parameters every time, if almost every time you call &lt;code&gt;throw&lt;/code&gt; you only need to pass one value?&lt;/p&gt;

&lt;p&gt;Throwable::X does the same thing by using &lt;a href=&#34;https://metacpan.org/module/MooseX::OneArgNew&#34;&gt;MooseX::OneArgNew&lt;/a&gt; to say, &#38;quot;If you only got one argument to &lt;code&gt;new&lt;/code&gt; (or, by extension, &lt;code&gt;throw&lt;/code&gt;), it&#38;#39;s the &lt;code&gt;ident&lt;/code&gt; argument.&#38;quot; Since most of the time, all that&#38;#39;s needed of a thrown exception is its name. Probably better than 95% of my thrown exceptions look like this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;word&#34;&gt;X::Permission&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;throw&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;single&#34;&gt;&#39;must run as root&#39;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Making that work just means adding this to our role or class:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;word&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;MooseX::OneArgNew&#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;type&lt;/span&gt;     &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Throwable::X::_VisibleStr&#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;single&#34;&gt;&#39;ident&#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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;You can do that in any Moose class or role, by the way, not just exceptions!&lt;/p&gt;

&lt;h3 id=&#34;Clearly-Identified-Exceptions&#34;&gt;Clearly-Identified Exceptions&lt;/h3&gt;

&lt;p&gt;So, I said that if you gave &lt;code&gt;throw&lt;/code&gt; only one argument, it stood for the &lt;code&gt;ident&lt;/code&gt; argument. What&#38;#39;s that?&lt;/p&gt;

&lt;p&gt;Well, in Exception::Class, it would have been &lt;code&gt;message&lt;/code&gt;, which is the error message that the exception is giving you. If your exception classes ar pretty broad (like &#38;quot;X::Permission&#38;quot; and &#38;quot;X::Unavailable&#38;quot; and similar-sized categories) then you&#38;#39;ll probably end up using &lt;code&gt;message&lt;/code&gt; for more detailed information. So, you&#38;#39;ll see code that looks like this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;word&#34;&gt;ExceptionClass::Error&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;throw&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;can&#39;t use $value as hostname&#38;quot;&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;How do we detect that this is the error we got? We do something like this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;catch&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;magic&#34;&gt;$_&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;message&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=~&lt;/span&gt; &lt;span class=&#34;match&#34;&gt;/\Acan&#39;t use .+? as hostname\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;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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Regular expression matches are a pretty lousy substitute for clear identification -- especially when we control the exception system and could just &lt;i&gt;make&lt;/i&gt; our exceptions identifiable. By using &lt;a href=&#34;https://metacpan.org/module/Role::Identifiable::HasIdent&#34;&gt;Role::Identifiable::HasIdent&lt;/a&gt;, we add an &lt;code&gt;ident&lt;/code&gt; attribute that is guaranteed to be a simple string that we can use to identify our exceptions. Our classes can identify exceptions in broad groups, but string equality with our &lt;code&gt;ident&lt;/code&gt; will always tell us if we have exactly the exception we expected.&lt;/p&gt;

&lt;p&gt;If the &lt;code&gt;ident&lt;/code&gt; is not supposed to contain any specifics (like the hostname that we say is illegal), then how do we communicate that stuff back to the user?&lt;/p&gt;

&lt;h3 id=&#34;Describing-the-Error&#34;&gt;Describing the Error&lt;/h3&gt;

&lt;p&gt;We describe our exception with the &lt;code&gt;message&lt;/code&gt; attribute, just like we did with Exception::Class. We can leave it blank, and it will default to the &lt;code&gt;ident&lt;/code&gt;. If we provide it, though, it acts sort of like a &lt;code&gt;sprintf&lt;/code&gt; format. (Readers of last year&#38;#39;s calendar may remember that &lt;a href=&#34;http://advent.rjbs.manxome.org/2009/2009-12-08.html&#34;&gt;I have a soft spot for &lt;code&gt;sprintf&lt;/code&gt;&lt;/a&gt;.) We might say something like this:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;word&#34;&gt;X::BadValue&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;throw&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;ident&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;bad nameserver hostname&#38;quot;&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;message&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;can&#39;t use %{hostname}s for nameserver&#38;quot;&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;payload&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;hostname&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$hostname&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;When the &lt;code&gt;message&lt;/code&gt; is read, it gets formatted to read just like you expect, interpolating the value of &lt;code&gt;$hostname&lt;/code&gt; for the &lt;code&gt;%...s&lt;/code&gt; expression. The formatting language is very simple and easy to implement in other languages. It&#38;#39;s on the CPAN as &lt;a href=&#34;https://metacpan.org/module/String::Errf&#34;&gt;String::Errf&lt;/a&gt;, and has a JSON-backed test suite. The named inputs come from the payload -- but they don&#38;#39;t all need to be in the &lt;code&gt;payload&lt;/code&gt; hash.&lt;/p&gt;

&lt;p&gt;For example, what if we have a lot of errors related to hostnames? We could write a role:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;X::Role::HasHostname&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::Role&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;hostname&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;single&#34;&gt;&#39;Str&#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;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;traits&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;Payload&#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;comment&#34;&gt;# &#38;lt;-- Role::HasPayload::Meta::Attribute::Payload&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;...then if we made an exception class with that role included, the value of the &lt;code&gt;hostname&lt;/code&gt; attribute would automatically be part of the payload -- and we can be guaranteed that it will be there, and a string, because of the attribute definition. We could rewrite the above as:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;word&#34;&gt;X::BadValue::HasHostname&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;throw&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;ident&lt;/span&gt;    &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;bad nameserver hostname&#38;quot;&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;message&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;can&#39;t use %{hostname}s for nameserver&#38;quot;&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;hostname&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$hostname&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;This lets us write really generic exceptions to start with, but refactor to more specific implementations if it&#38;#39;s ever useful. With all the refactoring we might do over time, how do we keep track of what exceptions signify without relying on class or role names that might vary over time? We already have an &lt;code&gt;ident&lt;/code&gt; for identifying specific exceptions, but we want to identify whole categories of exceptions.&lt;/p&gt;

&lt;h3 id=&#34;Identification-by-Tagging&#34;&gt;Identification by Tagging&lt;/h3&gt;

&lt;p&gt;We want to be able to identify exceptions at resolutions other than &#38;quot;it&#38;#39;s an exception&#38;quot; and &#38;quot;its ident is &#38;#39;bad hostname&#38;#39;,&#38;quot; so one option would be to rely on checking classes and roles with &lt;code&gt;isa&lt;/code&gt; and &lt;code&gt;does&lt;/code&gt;. The problem is that we&#38;#39;re probably going to be ripping apart and rebuilding classes and roles over time as we figure out what kind of exceptions we really need to handle. Instead of tying our type checks to classes, we can tie them to something easier to carry around when we refactor: &lt;i&gt;tags&lt;/i&gt;.&lt;/p&gt;

&lt;p&gt;We can use &lt;a href=&#34;https://metacpan.org/module/Role::Identifiable::HasTags&#34;&gt;Role::Identifiable::HasTags&lt;/a&gt; to add tags to our exceptions:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;word&#34;&gt;X::BadValue&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;throw&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;ident&lt;/span&gt;   &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;bad nameserver hostname&#38;quot;&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;message&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;can&#39;t use %{hostname}s for nameserver&#38;quot;&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;payload&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;hostname&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$hostname&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;tags&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;words&#34;&gt;qw(dns hostname)&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Later, refactoring like we said above, we might end up writing:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;br /&gt;10:&#38;nbsp;&lt;br /&gt;11:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;package&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;X::Role::HasHostname&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::Role&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;add_tags&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;words&#34;&gt;qw(hostname)&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;hostname&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;single&#34;&gt;&#39;Str&#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;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;traits&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;Payload&#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;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;...and the hostname tag would no longer be required when throwing, because it would be implicit in the class.&lt;/p&gt;

&lt;p&gt;(The tags role is still in a bit of flux as it is rewritten to use &lt;a href=&#34;https://metacpan.org/module/MooseX::ComposedBehavior&#34;&gt;MooseX::ComposedBehavior&lt;/a&gt;. More on that another day.)&lt;/p&gt;

&lt;h2 id=&#34;Picking-and-Choosing&#34;&gt;Picking and Choosing&lt;/h2&gt;

&lt;p&gt;I think there are a number of exception extensions left to be written, most importantly stringification and serialization behaviors. Because each of these behaviors is its own role or component, you can build your own application&#38;#39;s exception classes with only the behavior you want. You can even re-use most of these behaviors in other classes that have nothing to do with exceptions, because they&#38;#39;re just hunks of behavior, rather than exception-specific code built into and inseparable from an exception library.&lt;/p&gt;

&lt;h2 id=&#34;See-Also&#34;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

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

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Throwable::X&#34;&gt;Throwable::X&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/MooseX::OneArgNew&#34;&gt;MooseX::OneArgNew&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Role::Identifiable::HasIdent&#34;&gt;Role::Identifiable::HasIdent&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/String::Errf&#34;&gt;String::Errf&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Role::HasPayload::Merged&#34;&gt;Role::HasPayload::Merged&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Role::Identifiable::HasTags&#34;&gt;Role::Identifiable::HasTags&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Exception::Class&#34;&gt;Exception::Class&lt;/a&gt;&lt;/p&gt;

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

&lt;/div&gt;</summary><updated>2010-12-03T00:00:00-05:00</updated><category term="Perl"/><category term="RJBS"/></entry><entry><title>Bringing out the Good Exporter for Company</title><link href="http://advent.rjbs.manxome.org/2010/2010-12-02.html"/><id>http://advent.rjbs.manxome.org/2010/2010-12-02.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h2 id=&#34;The-Illusion-of-Sophistication&#34;&gt;The Illusion of Sophistication&lt;/h2&gt;

&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Sub::Exporter&#34;&gt;Sub::Exporter&lt;/a&gt;, covered in &lt;a href=&#34;http://advent.rjbs.manxome.org/2009/2009-12-01.html&#34;&gt;the first Advent post last year&lt;/a&gt;, describes itself as &#38;quot;a sophisticated exporter for custom-built routines.&#38;quot; This is in contrast to &lt;a href=&#34;https://metacpan.org/module/Exporter&#34;&gt;Exporter&lt;/a&gt;, which is, well... chocked full of near-adequacy.&lt;/p&gt;

&lt;p&gt;Sometimes, though, you&#38;#39;re stuck working with some code that you don&#38;#39;t control and that uses the plain old Exporter. &lt;a href=&#34;https://metacpan.org/module/Sub::Import&#34;&gt;Sub::Import&lt;/a&gt; gets around this problem by letting you import from that library with a number of the features otherwise found only in Sub::Exporter.&lt;/p&gt;

&lt;p&gt;For example, say you want to use the useful but horribly named &lt;code&gt;&lt;a href=&#34;https://metacpan.org/module/List::MoreUtils#natatime&#34;&gt;natatime&lt;/a&gt;&lt;/code&gt; routine from List::MoreUtils, and you want to give it a name that won&#38;#39;t make you constantly wonder, &#38;quot;What&#38;#39;s &lt;i&gt;natural&lt;/i&gt; &lt;code&gt;atime&lt;/code&gt;?&#38;quot; It&#38;#39;s easy to use Sub::Import to get apply Sub::Exporter&#38;#39;s renaming facility:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Sub::Import&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;List::MoreUtils&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;natatime&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;-as&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;iterate_by_n&#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;$iterator&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;iterate_by_n&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;symbol&#34;&gt;@list&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;The import-to-scalar rename would work, too:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$by_n&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::Import&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;List::MoreUtils&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;natatime&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;-as&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;symbol&#34;&gt;$by_n&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;$iterator&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$by_n&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;number&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;operator&#34;&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;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;You&#38;#39;re not limited to renaming single routines, either. You can use the prefix and suffix renaming for groups:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Sub::Import&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;Perl6::Junction&#39;&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;-ALL&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;-suffix&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;_junction&#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;if&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$input&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;any_junction&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;2&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;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;say&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;$input is okay&#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;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;Many other advanced features are available too, like custom installers or generators, so even if you&#38;#39;re working with a library that&#38;#39;s still using stock Exporter, you&#38;#39;re not stuck with its limitations.&lt;/p&gt;

&lt;h2 id=&#34;See-Also&#34;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Sub::Import&#34;&gt;Sub::Import&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Sub::Exporter&#34;&gt;Sub::Exporter&lt;/a&gt;&lt;/p&gt;

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

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

&lt;/div&gt;</summary><updated>2010-12-02T00:00:00-05:00</updated><category term="Perl"/><category term="RJBS"/></entry><entry><title>A Logging Library that Really Stinks</title><link href="http://advent.rjbs.manxome.org/2010/2010-12-01.html"/><id>http://advent.rjbs.manxome.org/2010/2010-12-01.html</id><summary type="html">&lt;div class=&#39;pod&#39;&gt;&lt;h2 id=&#34;Couldnt-you-just-use...&#34;&gt;Couldn&#38;#39;t you just use...&lt;/h2&gt;

&lt;p&gt;Yeah, probably. After all, there are over one hundred logging libraries on the CPAN. Probably there&#38;#39;s something out there that&#38;#39;s tolerable. The question is how to find it.&lt;/p&gt;

&lt;p&gt;A few years ago, at work, we were really starting to suffer because of the totally haphazard approach to logging. Some code used Sys::Syslog, some code logged to files, some code used print. Some used internal solution A, and some used internal solution B. Given any two pieces of code, the odds were good that they didn&#38;#39;t log the same way. Worse, lots of the code didn&#38;#39;t log at all, because &lt;i&gt;doing&lt;/i&gt; any logging was blocked by &lt;i&gt;choosing how&lt;/i&gt; to log.&lt;/p&gt;

&lt;p&gt;We wanted to standardize on something, and we didn&#38;#39;t want to write our own logging framework. How would we choose from the overwhelming selection available on the CPAN? We picked the usual strategy: figure out what everybody else was using. The winner was &lt;a href=&#34;https://metacpan.org/module/Log::Log4perl&#34;&gt;Log::Log4perl&lt;/a&gt;, and we wrote up notes on how we&#38;#39;d go about standardizing, which mostly meant writing a comprehensive configuration and then using it everywhere. We got about as far as figuring out what syslog facilities to use for what and then balked. It felt like there were too many options to really move forward. We needed freedom from all that choice.&lt;/p&gt;

&lt;p&gt;Our alternative had been &lt;a href=&#34;https://metacpan.org/module/Log::Dispatch&#34;&gt;Log::Dispatch&lt;/a&gt;, which has many of the same properties as Log4perl, but is less complex. In fact, we had quite a bit of code already using it, and that code was pretty easy to work with it. The only drag was that those programs often ended up with dozens of lines of code just to initialize the logger. It turned out that they were always the same lines of code, with just a few tweaks, though. We took that code and shoved it into a factory that built loggers and started using it everywhere. That made it a one-liner to set up a logger the way we liked.&lt;/p&gt;

&lt;p&gt;Over time, the usual thing happened: we simplified our logging so much that it seemed silly not to simplify it more, and a &lt;code&gt;sprintf&lt;/code&gt; facility was built into our logger (using &lt;a href=&#34;String:Flogger&#34;&gt;String:Flogger&lt;/a&gt;). Then we added proxies so that subroutines of a program could use subloggers with built-in prefixes. Just about everything we log, now -- many gigabytes per day -- gets logged by Log::Dispatchouli.&lt;/p&gt;

&lt;h2 id=&#34;Enough-History-Lets-See-Some-Code&#34;&gt;Enough History, Let&#38;#39;s See Some Code&lt;/h2&gt;

&lt;p&gt;So, how does it work? It&#38;#39;s easy. First, you need to make a logger. Then you need to do it.&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$logger&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Log::Dispatchouli&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;&lt;span class=&#34;word&#34;&gt;ident&lt;/span&gt;     &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;My::Awesome::Program&#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;facility&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;local2&#39;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;comment&#34;&gt;# a syslog facility&lt;/span&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&lt;span class=&#34;word&#34;&gt;to_stdout&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;symbol&#34;&gt;$logger&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;double&#34;&gt;&#38;quot;This is a boring message.&#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;$logger&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;([&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;This will be passed through %s.&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;String::Flogger&#39;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;The logger only really has to know a couple things: what its identity is, where it will log, and whether it should discard debugging messages. There are a few other options, but they&#38;#39;re pretty rarely needed. The example above covers the great majority of options that get used.&lt;/p&gt;

&lt;p&gt;We can call &lt;code&gt;log&lt;/code&gt; on our logger and give it strings or arrayrefs of &lt;a href=&#34;https://metacpan.org/module/String::Flogger&#34;&gt;String::Flogger&lt;/a&gt; args. Those arrayrefs are mostly just &lt;code&gt;sprintf&lt;/code&gt; arguments, but non-strings (like references, objects, and undef) are converted to JSON, and we can defer evaluation of bits of the log message so that it won&#38;#39;t be evaluated unless needed. This works well with the &lt;code&gt;log_debug&lt;/code&gt; method, which logs only if our logger is in debug mode.&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;symbol&#34;&gt;$logger&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;log_debug&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;([&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;Current score: %s&#38;quot;&lt;/span&gt;&lt;span class=&#34;operator&#34;&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;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;compute_score&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;]);&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;If &lt;code&gt;compute_score&lt;/code&gt; is expensive, this is a big win, because we can avoid calling it unless we&#38;#39;re actually going to log this message.&lt;/p&gt;

&lt;p&gt;We can also make little proxies for use in subroutines, for example:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&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;$account_id&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@account_ids&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;$self&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;do_work&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;account&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &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;word&#34;&gt;retrieve&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$account_id&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;logger&lt;/span&gt;  &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$logger&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;proxy&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;({&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;proxy_prefix&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;$account_id: &#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;&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;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;All the &lt;code&gt;do_work&lt;/code&gt; calls will log with a proxy to the main logger that prefixes all logged messages with a fixed string.&lt;/p&gt;

&lt;p&gt;This has been the state of the art for our logging for a few years now, and it&#38;#39;s been a huge improvement, &lt;i&gt;precisely because it has so few options&lt;/i&gt;.&lt;/p&gt;

&lt;h3 id=&#34;Future-Experiments&#34;&gt;Future Experiments&lt;/h3&gt;

&lt;p&gt;One of the biggest drags with Log::Dispatchouli is that we tend to pass around logger objects or proxies up or down the call stack. This can be a really annoying chore, and usually adds nothing to the program that couldn&#38;#39;t be added other ways. The program&#38;#39;s logging behavior is mostly a global issue. When we pass loggers to subroutines, right now, it&#38;#39;s only to set a prefix or just to allow access to the logger at all.&lt;/p&gt;

&lt;p&gt;We&#38;#39;re experimenting with a promising new throwback interface, using a shared global variable. Globals are usually a bad idea, but sometimes you really do want a global! Globals also let you tie behavior to the execution context with &lt;code&gt;local&lt;/code&gt; -- again, usually you don&#38;#39;t want it, but consider the example above, rewritten:&lt;/p&gt;



&lt;table class=&#39;code-listing&#39;&gt;&lt;tr&gt;&lt;td class=&#39;line-numbers&#39;&gt;&lt;br /&gt;&lt;code&gt;1:&#38;nbsp;&lt;br /&gt;2:&#38;nbsp;&lt;br /&gt;3:&#38;nbsp;&lt;br /&gt;4:&#38;nbsp;&lt;br /&gt;5:&#38;nbsp;&lt;br /&gt;6:&#38;nbsp;&lt;br /&gt;7:&#38;nbsp;&lt;br /&gt;8:&#38;nbsp;&lt;br /&gt;9:&#38;nbsp;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;td class=&#39;code&#39;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&#34;keyword&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;Log::Dispatchouli::Global&lt;/span&gt; &lt;span class=&#34;single&#34;&gt;&#39;$Logger&#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;for&lt;/span&gt; &lt;span class=&#34;keyword&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$account_id&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;@account_ids&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;local&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$Logger&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;symbol&#34;&gt;$Logger&lt;/span&gt;&lt;span class=&#34;operator&#34;&gt;-&#38;gt;&lt;/span&gt;&lt;span class=&#34;word&#34;&gt;proxy&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;({&lt;/span&gt; &lt;span class=&#34;word&#34;&gt;proxy_prefix&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &lt;span class=&#34;double&#34;&gt;&#38;quot;$account_id: &#38;quot;&lt;/span&gt; &lt;span class=&#34;structure&#34;&gt;});&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&#38;nbsp;&#38;nbsp;&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;do_work&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;account&lt;/span&gt; &lt;span class=&#34;operator&#34;&gt;=&#38;gt;&lt;/span&gt; &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;word&#34;&gt;retrieve&lt;/span&gt;&lt;span class=&#34;structure&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;symbol&#34;&gt;$account_id&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;structure&#34;&gt;});&lt;/span&gt;&lt;br /&gt;&lt;span class=&#34;structure&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&#38;nbsp;&lt;/td&gt;&lt;/table&gt;

&lt;p&gt;It looks about the same, but when we want to start using a proxy, we localize the shared variable instead of passing a lexical. That means that &lt;code&gt;do_work&lt;/code&gt; doesn&#38;#39;t need to look for a &lt;code&gt;logger&lt;/code&gt; argument or decide what to do if none was passed. It justs uses the global, which is guaranteed to be there. Unlike many systems that use global variables, Log::Dispatchouli::Global can be subclassed to use &lt;i&gt;distinct&lt;/i&gt; globals per subclass, so your application can have its own shared global that won&#38;#39;t conflict with other applications, if you ever need to load more than one in a program.&lt;/p&gt;

&lt;h2 id=&#34;See-Also&#34;&gt;See Also&lt;/h2&gt;

&lt;ul&gt;

&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Log::Dispatchouli&#34;&gt;Log::Dispatchouli&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Log::Dispatchouli::Global&#34;&gt;Log::Dispatchouli::Global&lt;/a&gt;&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/Log::Dispatch&#34;&gt;Log::Dispatch&lt;/a&gt; - the logging engine behind Log::Dispatchouli&lt;/p&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://metacpan.org/module/String::Flogger&#34;&gt;String::Flogger&lt;/a&gt; - the string formatter used by Log::Dispatchouli&lt;/p&gt;

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

&lt;/div&gt;</summary><updated>2010-12-01T00:00:00-05:00</updated><category term="Perl"/><category term="RJBS"/></entry></feed>