<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Dan</title>
    <description>The latest articles on DEV Community by Dan (@grinnz).</description>
    <link>https://dev.to/grinnz</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F512635%2Fa86a8f7d-aa99-442e-8037-e21c62bd9f23.png</url>
      <title>DEV Community: Dan</title>
      <link>https://dev.to/grinnz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/grinnz"/>
    <language>en</language>
    <item>
      <title>The Perl Shebang</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Sun, 04 Jul 2021 22:36:55 +0000</pubDate>
      <link>https://dev.to/grinnz/the-perl-shebang-1ojg</link>
      <guid>https://dev.to/grinnz/the-perl-shebang-1ojg</guid>
      <description>&lt;p&gt;Often overlooked, the &lt;a href="https://en.wikipedia.org/wiki/Shebang_(Unix)" rel="noopener noreferrer"&gt;shebang&lt;/a&gt; of a Perl program is a comment on the first line which tells the (Unix-like) OS how to run the script when invoked directly on the commandline. (It's ignored on Windows, which only looks at the file extension.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/perl&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;v5&lt;/span&gt;&lt;span class="mf"&gt;.16.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;warnings&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello world&lt;/span&gt;&lt;span class="p"&gt;";&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod &lt;/span&gt;a+x myscript.pl
./myscript.pl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But there isn't one right answer for what the shebang should be. &lt;code&gt;/usr/bin/perl&lt;/code&gt; may be commonly available, but not always, and may not be the &lt;code&gt;perl&lt;/code&gt; the user prefers.&lt;/p&gt;

&lt;p&gt;For Perl scripts that are distributed to users to run how they wish, use &lt;code&gt;env&lt;/code&gt; to run the &lt;code&gt;perl&lt;/code&gt; that comes first in PATH:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Perl scripts distributed on CPAN, however, get installed to a specific &lt;code&gt;perl&lt;/code&gt; with their dependencies, so their shebang must also point to that &lt;code&gt;perl&lt;/code&gt;. This is handled by a shebang rewrite step in the installation process, but it doesn't work for an &lt;code&gt;env&lt;/code&gt; shebang for &lt;a href="https://github.com/Perl-Toolchain-Gang/ExtUtils-MakeMaker/issues/58" rel="noopener noreferrer"&gt;historical reasons&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For Perl scripts distributed via CPAN installation, you can use any single-word shebang that ends in &lt;code&gt;perl&lt;/code&gt;, even just &lt;code&gt;perl&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;While developing and testing, the shebang will not have been rewritten yet, so you can invoke it as &lt;code&gt;perl script/myscript.pl&lt;/code&gt; to run it with your preferred &lt;code&gt;perl&lt;/code&gt; and ignore the shebang. If the script depends on modules in &lt;code&gt;lib/&lt;/code&gt; in the same distribution, it is common to run it during development as &lt;code&gt;perl -Ilib script/myscript.pl&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, when you deploy and install a script manually, it should be run with a specific &lt;code&gt;perl&lt;/code&gt; so that it doesn't suddenly start running with a different &lt;code&gt;perl&lt;/code&gt; from the one it was deployed for, which may not have the script's dependencies installed or may behave subtly differently.&lt;/p&gt;

&lt;p&gt;For Perl scripts deployed to a specific location, use the full path to the &lt;code&gt;perl&lt;/code&gt; that should run it on that machine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/perl&lt;/span&gt;
&lt;span class="c1"&gt;#!/opt/perl/bin/perl&lt;/span&gt;
&lt;span class="c1"&gt;#!/home/user/perl5/perlbrew/perls/perl-5.34.0/bin/perl&lt;/span&gt;
&lt;span class="c1"&gt;#!/home/user/.plenv/versions/5.34.0/bin/perl&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may also find Perl scripts with flags specified in the shebang with hyphens. This doesn't work with &lt;code&gt;env&lt;/code&gt; shebangs in many cases, but the two common flags used this way are &lt;code&gt;-w&lt;/code&gt; for warnings and &lt;code&gt;-T&lt;/code&gt; for taint mode. &lt;code&gt;-w&lt;/code&gt; is unnecessary and &lt;a href="https://perldoc.perl.org/warnings#What's-wrong-with-w-and-$%5EW" rel="noopener noreferrer"&gt;discouraged&lt;/a&gt;; just &lt;code&gt;use warnings;&lt;/code&gt; instead.&lt;/p&gt;

</description>
      <category>perl</category>
    </item>
    <item>
      <title>CGI::Tiny - Perl CGI, but modern</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Sun, 30 May 2021 21:44:36 +0000</pubDate>
      <link>https://dev.to/grinnz/perl-cgi-but-modern-4630</link>
      <guid>https://dev.to/grinnz/perl-cgi-but-modern-4630</guid>
      <description>&lt;p&gt;In a &lt;a href="http://blogs.perl.org/users/grinnz/2018/11/modern-perl-cgi.html" rel="noopener noreferrer"&gt;previous blog post&lt;/a&gt;, I explored the modern way to write CGI scripts using frameworks like &lt;a href="https://mojolicious.org" rel="noopener noreferrer"&gt;Mojolicious&lt;/a&gt;. But as pointed out in comments, despite the many benefits, there is one critical problem: when you actually need to deploy to a regular CGI server, where the scripts will be loaded each time and not persisted, frameworks designed for persistent applications add lots of overhead to each request.&lt;/p&gt;

&lt;p&gt;CGI scripts have historically been written using the &lt;a href="https://metacpan.org/pod/CGI" rel="noopener noreferrer"&gt;CGI&lt;/a&gt; module (or even more ancient libraries). But this module is bulky, crufty, and has serious design issues that led to it being &lt;a href="https://metacpan.org/pod/CGI#CGI.pm-HAS-BEEN-REMOVED-FROM-THE-PERL-CORE" rel="noopener noreferrer"&gt;removed from Perl core&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Enter &lt;a href="https://metacpan.org/pod/CGI::Tiny" rel="noopener noreferrer"&gt;CGI::Tiny&lt;/a&gt;. It is built for one thing only: serving the CGI protocol. In most cases, frameworks are still the right answer, but in the case of scripts that are forced to run under the actual CGI protocol (such as shared web hosting), or when you want to just drop in CGI scripts with no need to scale, CGI::Tiny provides a modern alternative to CGI.pm. You can explore the &lt;a href="https://metacpan.org/pod/CGI::Tiny#COMPARISON-TO-CGI.PM" rel="noopener noreferrer"&gt;interface differences from CGI.pm&lt;/a&gt; or &lt;a href="https://metacpan.org/pod/CGI::Tiny::Cookbook" rel="noopener noreferrer"&gt;suggested ways to extend CGI::Tiny scripts&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So without further ado, here is the equivalent CGI::Tiny script to my previous blog post's examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env perl&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;strict&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;warnings&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;CGI::&lt;/span&gt;&lt;span class="nv"&gt;Tiny&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nv"&gt;cgi&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$cgi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vg"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$cgi&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;param&lt;/span&gt;&lt;span class="p"&gt;('&lt;/span&gt;&lt;span class="s1"&gt;input&lt;/span&gt;&lt;span class="p"&gt;');&lt;/span&gt;
  &lt;span class="nv"&gt;$cgi&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;json&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;output&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;uc&lt;/span&gt; &lt;span class="nv"&gt;$input&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>perl</category>
      <category>cgi</category>
    </item>
    <item>
      <title>Dist::Zilla @Starter Revision 3 - Git, versioning, and more</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Thu, 11 Mar 2021 23:46:33 +0000</pubDate>
      <link>https://dev.to/grinnz/dist-zilla-starter-revision-3-git-versioning-and-more-k5h</link>
      <guid>https://dev.to/grinnz/dist-zilla-starter-revision-3-git-versioning-and-more-k5h</guid>
      <description>&lt;p&gt;I've just released revision 3 of the &lt;a href="https://metacpan.org/pod/Dist::Zilla::PluginBundle::Starter" rel="noopener noreferrer"&gt;@Starter&lt;/a&gt; plugin bundle for the Dist::Zilla CPAN distribution authoring tool. There's no changes to the base configuration from revision 2, but there are now additional options to help manage common authoring tasks using modern best practices. You must set your revision to 3 to enable these new options, as a safety measure to make sure you have a new enough version of the bundle to support them.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;managed_versions&lt;/code&gt; option is the most complex new addition. Instead of declaring a distribution version in your dist.ini or using a plugin like [Git::NextVersion] or [AutoVersion] to determine it, this option lets you version your modules like you normally would and reads the version of your main module to use as the distribution version. The versions of any other modules in the distribution are updated to match in the build or release, and after a release it's incremented in the source files. This is widely considered the least fragile and most contributor-friendly method of managing versions with Dist::Zilla currently, as your modules don't require Dist::Zilla to determine their version while testing.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;regenerate&lt;/code&gt; option makes use of a very useful quasi-phase called &lt;a href="https://metacpan.org/pod/Dist::Zilla::Role::Regenerator" rel="noopener noreferrer"&gt;-Regenerator&lt;/a&gt; created by Kent Fredric. For each filename you specify, it copies this file from the Dist::Zilla build tree to your source tree whenever you release as well as when you run &lt;code&gt;dzil regenerate&lt;/code&gt;. This can be useful for keeping generated files such as LICENSE in your git repository where they may also be important, as well as copying your Makefile.PL/Build.PL and META.json to your source tree if you wish to make it directly installable with &lt;a href="https://metacpan.org/pod/cpanm" rel="noopener noreferrer"&gt;cpanm&lt;/a&gt; for testing or Travis CI. (Note: this method is only for testing unreleased changes, you should always install distributions from CPAN normally.)&lt;/p&gt;

&lt;p&gt;Finally, revision 3 made it possible to release the &lt;a href="https://metacpan.org/pod/Dist::Zilla::PluginBundle::Starter::Git" rel="noopener noreferrer"&gt;@Starter::Git&lt;/a&gt; variant bundle, which takes all of the same options as &lt;code&gt;@Starter&lt;/code&gt;, and interleaves plugins appropriate to a Git workflow. [Git::GatherDir] replaces [GatherDir], as it's a simple subclass that prevents cruft from being gathered by simply gathering the files tracked in Git. This means your .gitignore can be used to exclude files from both the repository and your distribution builds. This mostly obsoletes the need for [PruneCruft] and [ManifestSkip] to clean up your distribution build, but the bundle still includes them as they don't tend to cause any problems. In addition, the bundle will check for any uncommitted changes before releasing, and after releasing commit and tag the release (as well as a separate version bump commit if you also enable managed versions), and push to your Git origin if you have one configured.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;@Starter::Git&lt;/code&gt; bundle also comes with a matching &lt;a href="https://metacpan.org/pod/Dist::Zilla::MintingProfile::Starter::Git" rel="noopener noreferrer"&gt;Dist::Zilla minting profile&lt;/a&gt;, which is similar to the &lt;code&gt;@Starter&lt;/code&gt; profile but additionally adds a basic .gitignore to start you out, and initializes the new directory as a Git repository.&lt;/p&gt;

&lt;p&gt;I hope these new options are helpful in modernizing your distribution workflow. As always, any plugins used by the bundle can be fully configured by config slicing, you can even look at the new bundle's &lt;a href="https://metacpan.org/source/DBOOK/Dist-Zilla-PluginBundle-Starter-Git-v3.0.1/dist.ini" rel="noopener noreferrer"&gt;dist.ini&lt;/a&gt; for examples of using itself. Please stop by &lt;a href="https://kiwiirc.com/nextclient/#irc://irc.perl.org/#distzilla" rel="noopener noreferrer"&gt;#distzilla on irc.perl.org&lt;/a&gt; if you have any questions, big or small, we are happy to help.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Since the original publication of this post, &lt;code&gt;@Starter&lt;/code&gt; and &lt;code&gt;@Starter::Git&lt;/code&gt; have reached revision 5, with a few minor enhancements.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>perl</category>
    </item>
    <item>
      <title>Dist::Zilla @Starter - Revision 2</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Wed, 10 Mar 2021 20:41:13 +0000</pubDate>
      <link>https://dev.to/grinnz/dist-zilla-starter-revision-2-1bi</link>
      <guid>https://dev.to/grinnz/dist-zilla-starter-revision-2-1bi</guid>
      <description>&lt;p&gt;I recently released revision 2 of the &lt;a href="https://metacpan.org/pod/Dist::Zilla::PluginBundle::Starter" rel="noopener noreferrer"&gt;@Starter&lt;/a&gt; plugin bundle for Dist::Zilla. This revision brings small improvements to the default behavior, as well as the option to set a different installer plugin. In order to use the new revision, you must set the option "revision = 2" when using the bundle.&lt;/p&gt;

&lt;p&gt;Revision 2 uses &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::Pod2Readme" rel="noopener noreferrer"&gt;[Pod2Readme]&lt;/a&gt; instead of &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::ReadmeAnyFromPod" rel="noopener noreferrer"&gt;[ReadmeAnyFromPod]&lt;/a&gt; to generate the text README file. [ReadmeAnyFromPod] is a great and flexible plugin, but [Pod2Readme] is much simpler for the specific purpose of generating a text README. For any additional README files in other formats, I still recommend using [ReadmeAnyFromPod].&lt;/p&gt;

&lt;p&gt;This revision also sets the option &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::MetaProvides::Package#inherit_version" rel="noopener noreferrer"&gt;"inherit_version" in [MetaProvides::Package]&lt;/a&gt; to 0 by default. This makes no difference if your distribution contains uniform module versions, or for modules which have no version (they are still marked as having the distribution version unless you set "inherit_missing" to 0 as well), but if you have modules with different versions hardcoded, this will reflect that in the "provides" metadata.&lt;/p&gt;

&lt;p&gt;The new "installer" option allows you to swap out the default &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::MakeMaker" rel="noopener noreferrer"&gt;[MakeMaker]&lt;/a&gt; installer plugin. The primary reason to do this is to use &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::MakeMaker::Awesome" rel="noopener noreferrer"&gt;[MakeMaker::Awesome]&lt;/a&gt; when you need to customize portions of the generated "Makefile.PL". There is also the option to use &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::ModuleBuildTiny" rel="noopener noreferrer"&gt;[ModuleBuildTiny]&lt;/a&gt; or &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::ModuleBuildTiny::Fallback" rel="noopener noreferrer"&gt;[ModuleBuildTiny::Fallback]&lt;/a&gt; if your distribution is simple enough to use &lt;a href="https://metacpan.org/pod/Module::Build::Tiny" rel="noopener noreferrer"&gt;Module::Build::Tiny&lt;/a&gt; as your installer.&lt;/p&gt;

&lt;p&gt;I recommend upgrading to Revision 2 if you are currently using &lt;code&gt;@Starter&lt;/code&gt; or &lt;code&gt;@Basic&lt;/code&gt;. Check out the documentation for details, and come visit &lt;a href="https://kiwiirc.com/nextclient/#irc://irc.perl.org/#distzilla" rel="noopener noreferrer"&gt;#distzilla on irc.perl.org&lt;/a&gt; if you have any questions or issues.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Since the original publication of this post, &lt;code&gt;@Starter&lt;/code&gt; has reached revision 5 and the &lt;a href="https://metacpan.org/pod/Dist::Zilla::PluginBundle::Starter::Git" rel="noopener noreferrer"&gt;@Starter::Git&lt;/a&gt; variant bundle has been added for additional convenience. I will be republishing my other posts on &lt;code&gt;@Starter&lt;/code&gt; in the coming week.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>perl</category>
    </item>
    <item>
      <title>Dist::Zilla - Why you should use @Starter instead of @Basic</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Tue, 09 Mar 2021 19:07:20 +0000</pubDate>
      <link>https://dev.to/grinnz/dist-zilla-why-you-should-use-starter-instead-of-basic-22d7</link>
      <guid>https://dev.to/grinnz/dist-zilla-why-you-should-use-starter-instead-of-basic-22d7</guid>
      <description>&lt;p&gt;I posted previously about a new "starter" bundle for &lt;a href="http://dzil.org/" rel="noopener noreferrer"&gt;Dist::Zilla&lt;/a&gt;, the CPAN author's automation tool. I'd like to briefly try to answer the question: "Why should I care?"&lt;/p&gt;

&lt;p&gt;If you're already happily using Dist::Zilla with an extensive configuration or plugin bundle of your own, this bundle isn't for you. But maybe you can get some ideas from the included plugins, I added a few to my author bundle!&lt;/p&gt;

&lt;p&gt;If you're looking to get started in Dist::Zilla, the &lt;a href="https://metacpan.org/pod/Dist::Zilla::PluginBundle::Starter" rel="noopener noreferrer"&gt;@Starter&lt;/a&gt; bundle makes a great starting point. Usage is similar to &lt;a href="https://metacpan.org/pod/Dist::Zilla::PluginBundle::Basic" rel="noopener noreferrer"&gt;@Basic&lt;/a&gt; and all of the same information in the &lt;a href="http://dzil.org" rel="noopener noreferrer"&gt;dzil.org&lt;/a&gt; tutorial applies.&lt;/p&gt;

&lt;p&gt;If you're currently using &lt;code&gt;@Basic&lt;/code&gt;, there are a few reasons you should consider switching over. &lt;code&gt;@Basic&lt;/code&gt; has become somewhat outdated as it needs to maintain compatibility with existing configs; &lt;code&gt;@Starter&lt;/code&gt; modernizes the base plugin set. For example, it includes the important [MetaJSON] plugin for generating modern CPAN metadata, and it uses [RunExtraTests] to run xt/ (extra) tests directly, which is now generally preferred over rewriting them into the t/ directory with the [ExtraTests] plugin. It also adds a few popular plugins, such as [Test::ReportPrereqs], which generates a test that lists all distribution prereqs and the currently installed versions, very helpful for debugging test failures.&lt;/p&gt;

&lt;p&gt;Even if you're already including all of these improvements yourself on top of &lt;code&gt;@Basic&lt;/code&gt;, using &lt;code&gt;@Starter&lt;/code&gt; can cut down on the boilerplate in your dist.ini, and you can simply remove any plugins you want to leave out, or configure included plugins directly via config slicing. Plus, it can help incorporate new practices and features; &lt;code&gt;@Starter&lt;/code&gt; will include future updates as new revisions, which you can review and switch to by setting the revision number in your dist.ini. This allows it to stay modern without breaking existing configs.&lt;/p&gt;

&lt;p&gt;Switching from &lt;code&gt;@Basic&lt;/code&gt; to &lt;code&gt;@Starter&lt;/code&gt; is generally straightforward. Most minimal configurations can be directly switched over, removing any manually-included plugins that &lt;code&gt;@Starter&lt;/code&gt; adds itself. If you are using &lt;code&gt;@Filter&lt;/code&gt;, you can instead apply the -remove option directly to &lt;code&gt;@Starter&lt;/code&gt;. The &lt;a href="https://metacpan.org/pod/Dist::Zilla::PluginBundle::Starter#CONFIGURING" rel="noopener noreferrer"&gt;"CONFIGURING"&lt;/a&gt; section of the documentation goes over the most common ways to configure the bundle.&lt;/p&gt;

&lt;p&gt;Feel free to stop by &lt;a href="https://kiwiirc.com/nextclient/#irc://irc.perl.org/#distzilla" rel="noopener noreferrer"&gt;#distzilla on irc.perl.org&lt;/a&gt; or send me an email (address listed in module documentation) if you have any questions about the bundle, configuration, or Dist::Zilla in general. Happy releasing!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Since the original publication of this post, &lt;code&gt;@Starter&lt;/code&gt; has reached revision 5 and the &lt;a href="https://metacpan.org/pod/Dist::Zilla::PluginBundle::Starter::Git" rel="noopener noreferrer"&gt;@Starter::Git&lt;/a&gt; variant bundle has been added for additional convenience. I will be republishing my other posts on &lt;code&gt;@Starter&lt;/code&gt; in the coming week.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>perl</category>
    </item>
    <item>
      <title>Dist::Zilla::PluginBundle::Starter - A new way to start using Dist::Zilla</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Mon, 08 Mar 2021 20:04:20 +0000</pubDate>
      <link>https://dev.to/grinnz/dist-zilla-pluginbundle-starter-a-new-way-to-start-using-dist-zilla-38m6</link>
      <guid>https://dev.to/grinnz/dist-zilla-pluginbundle-starter-a-new-way-to-start-using-dist-zilla-38m6</guid>
      <description>&lt;p&gt;&lt;a href="https://metacpan.org/pod/Dist::Zilla" rel="noopener noreferrer"&gt;Dist::Zilla&lt;/a&gt; is an extremely powerful and versatile CPAN authoring tool, which has enabled me to reliably publish many &lt;a href="https://metacpan.org/author/DBOOK" rel="noopener noreferrer"&gt;distributions&lt;/a&gt; with minimal fuss. It has the ability to automate your entire distribution building, testing, and releasing process, customized to almost any workflow, but this ability does not come without cost. One of the biggest difficulties newcomers face is sorting out the overwhelming number of available plugins and how to use them together effectively. A good way to start is with the tutorials at &lt;a href="http://dzil.org" rel="noopener noreferrer"&gt;dzil.org&lt;/a&gt; and the standard &lt;a href="https://metacpan.org/pod/Dist::Zilla::PluginBundle::Basic" rel="noopener noreferrer"&gt;@Basic&lt;/a&gt; plugin bundle. Unfortunately, the &lt;code&gt;@Basic&lt;/code&gt; bundle is out of date; notably, it does not include the &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::MetaJSON" rel="noopener noreferrer"&gt;[MetaJSON]&lt;/a&gt; plugin, to generate META.json which is now the preferred metadata format for CPAN distributions. For backwards compatibility reasons the bundle itself can't easily be updated with new plugins.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://metacpan.org/pod/Dist::Zilla::PluginBundle::Starter" rel="noopener noreferrer"&gt;@Starter&lt;/a&gt; is an attempt at an improved, more customizable beginner's plugin bundle, with a revision feature to try to avoid the problem of stagnation while being able to retain backwards compatibility. The revision defaults to 1 unless set explicitly, and future incompatible changes will be made by adding new revisions, which must then be selected by the author using the bundle. Also, the popular PluginRemover and Config::Slicer plugin bundle roles are composed in, allowing the author to remove or configure bundled plugins as desired.&lt;/p&gt;

&lt;p&gt;The first revision also includes a number of improvements and updates to &lt;code&gt;@Basic&lt;/code&gt;, while remaining unopinionated and unobtrusive. The previously mentioned [MetaJSON] is included by default, as well as a few plugins for more &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::MetaConfig" rel="noopener noreferrer"&gt;complete&lt;/a&gt; &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::MetaProvides::Package" rel="noopener noreferrer"&gt;distribution&lt;/a&gt; &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::MetaNoIndex" rel="noopener noreferrer"&gt;metadata&lt;/a&gt;, and a few plugins that add basic sanity tests to the build. Two of the tests are author-only tests that check that the &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::PodSyntaxTests" rel="noopener noreferrer"&gt;pod syntax is valid&lt;/a&gt; and the &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::Test::Compile" rel="noopener noreferrer"&gt;modules compile&lt;/a&gt;. The third is a simple test that prints a &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::Test::ReportPrereqs" rel="noopener noreferrer"&gt;report of the installed prerequisites&lt;/a&gt;, useful for diagnosing test failures. &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::RunExtraTests" rel="noopener noreferrer"&gt;[RunExtraTests]&lt;/a&gt; is included instead of &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::ExtraTests" rel="noopener noreferrer"&gt;[ExtraTests]&lt;/a&gt;, because instead of moving and rewriting your extra tests (tests in xt/), it leaves them there and modifies Dist::Zilla's testing routines to run them directly. Finally, &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::ReadmeAnyFromPod" rel="noopener noreferrer"&gt;[ReadmeAnyFromPod]&lt;/a&gt; is used instead of &lt;a href="https://metacpan.org/pod/Dist::Zilla::Plugin::Readme" rel="noopener noreferrer"&gt;[Readme]&lt;/a&gt; to generate a text README from your main module's documentation, rather than a generic README.&lt;/p&gt;

&lt;p&gt;These plugins are sufficient to build and release a complete distribution reliably, but there are many more tasks Dist::Zilla can automate for you, like maintaining your module versions and automatically managing git or other version control. The &lt;a href="https://metacpan.org/pod/Dist::Zilla::PluginBundle::Starter#EXTENDING" rel="noopener noreferrer"&gt;"EXTENDING"&lt;/a&gt; section of the documentation describes some of the available options. Many of these are features of miyagawa's excellent &lt;a href="https://metacpan.org/pod/Dist::Milla" rel="noopener noreferrer"&gt;Dist::Milla&lt;/a&gt; bundle, which is much more opinionated, but can be another great way to start using Dist::Zilla if you use git version control, and heavily influenced &lt;a href="https://metacpan.org/pod/Dist::Zilla::PluginBundle::Author::DBOOK" rel="noopener noreferrer"&gt;my own author bundle&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I hope this new bundle is useful to those getting started with Dist::Zilla or just looking for an updated bundle similar to &lt;code&gt;@Basic&lt;/code&gt;, and as with all matters Dist::Zilla, please stop by &lt;a href="https://kiwiirc.com/nextclient/#irc://irc.perl.org/#distzilla" rel="noopener noreferrer"&gt;#distzilla on irc.perl.org&lt;/a&gt; if you need help!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Since the original publication of this post, &lt;code&gt;@Starter&lt;/code&gt; has reached revision 5 and the &lt;a href="https://metacpan.org/pod/Dist::Zilla::PluginBundle::Starter::Git" rel="noopener noreferrer"&gt;@Starter::Git&lt;/a&gt; variant bundle has been added for additional convenience. I will be republishing my other posts on &lt;code&gt;@Starter&lt;/code&gt; in the coming week.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>perl</category>
    </item>
    <item>
      <title>Encode::Simple - Encode and decode text, simply</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Thu, 04 Mar 2021 19:16:44 +0000</pubDate>
      <link>https://dev.to/grinnz/encode-simple-encode-and-decode-text-simply-7l9</link>
      <guid>https://dev.to/grinnz/encode-simple-encode-and-decode-text-simply-7l9</guid>
      <description>&lt;p&gt;Encode is a well known core module in Perl with support for encoding and decoding text from almost any character encoding you can think of. But it's also an old module with a large amount of historical cruft.&lt;/p&gt;

&lt;p&gt;With inspiration from #perl on freenode IRC, &lt;a href="https://metacpan.org/pod/Encode::Simple" rel="noopener noreferrer"&gt;Encode::Simple&lt;/a&gt; is an attempt to at least improve on its interface and usability issues. Rather than an awkward and unintuitive bitmask and the option of clobbering the input data, Encode::Simple exports straightforward encode and decode functions that simply return the encoded or decoded result or throw an exception. For the cases where you want to allow invalid characters or byte sequences, encode_lax and decode_lax are provided.&lt;/p&gt;

&lt;p&gt;Encode itself supports many more operations such as partial, mixed, and in-place encoding or decoding, where its options may make more sense, but these uncommon use cases are not supported by Encode::Simple.&lt;/p&gt;

&lt;p&gt;As a final note, if you are working strictly with UTF-8, I suggest avoiding Encode entirely and using the excellent &lt;a href="https://metacpan.org/pod/Unicode::UTF8" rel="noopener noreferrer"&gt;Unicode::UTF8&lt;/a&gt;, or the related filehandle layer &lt;a href="https://metacpan.org/pod/PerlIO::utf8_strict" rel="noopener noreferrer"&gt;:utf8_strict&lt;/a&gt;, for fast and correct encoding and decoding.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Since the original publication of this post, Encode::Simple has added &lt;code&gt;encode_utf8&lt;/code&gt; and &lt;code&gt;decode_utf8&lt;/code&gt; functions that directly use &lt;code&gt;Unicode::UTF8&lt;/code&gt; if installed.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>perl</category>
    </item>
    <item>
      <title>A Guide to Versions in Perl</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Wed, 03 Mar 2021 00:52:22 +0000</pubDate>
      <link>https://dev.to/grinnz/a-guide-to-versions-in-perl-3ng1</link>
      <guid>https://dev.to/grinnz/a-guide-to-versions-in-perl-3ng1</guid>
      <description>&lt;p&gt;Version numbers in Perl are very important; they allow orderly updating and maintenance of modules and distributions across the &lt;a href="https://metacpan.org" rel="noopener noreferrer"&gt;CPAN&lt;/a&gt;, and allow CPAN modules and consumers to require the versions of modules with the bugfixes or features they need. However, in this context, they are also a very unique beast with a complex and bumpy history that leads to some surprises for those who are not familiar with the nuances. These are the things CPAN authors should know about versions in Perl, and are nice for consumers to know as well.&lt;/p&gt;

&lt;p&gt;To summarize:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Versions in Perl come in two forms, decimal numbers and dotted decimal tuples.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The two formats can be compared using a defined conversion method, implemented by the &lt;a href="https://perldoc.perl.org/version" rel="noopener noreferrer"&gt;version&lt;/a&gt; module.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Versions for modules should be declared as string values.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Underscores can be used in either form of version to indicate a trial version, but have pitfalls to watch for.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The VERSION method can be used on any module to test if it's a certain version or greater, and version objects can be used for arbitrary version comparisons.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Version Schemes
&lt;/h1&gt;

&lt;p&gt;To start with, it's important to know that there are two distinct types of versions recognized by Perl. The first kind is simply a decimal number, with digits before and after a decimal separator, for example '1.0' or '0.003'. These versions are compared as numbers, so '1.1' and '1.10' refer to the same version. Despite being numbers, they should always be declared and referenced as strings within the code, so that any trailing zeroes are kept around for consistency in display, and to avoid possible floating point errors for versions with a particularly large number of digits.&lt;/p&gt;

&lt;p&gt;While decimal number versions are a simple concept, they are different from the versions used by most everything outside of Perl. For that, Perl recognizes a second type of version: a tuple (or sequence) of integers separated by dots, sometimes referred to as "dotted-decimal" versions, and used for the concept of &lt;a href="https://semver.org/" rel="noopener noreferrer"&gt;semantic versioning&lt;/a&gt;. These look like 'v1.2.3' and 'v0.0.30'. For these versions, each segment is an integer, so trailing zeroes are significant -- 'v1.2.3' is the same version as 'v1.02.03', but not the same as 'v1.20.30'. Each segment after the first must also be 999 or lower, to allow conversion as described in the next section.&lt;/p&gt;

&lt;p&gt;Neither of these version forms allow alphabetic characters or hyphens, as you may see in other versioning schemes. I'll go into the use of underscores later.&lt;/p&gt;

&lt;p&gt;Responsible for parsing and disambiguating these two types of versions, as well as performing version comparisons as described below, is the module &lt;a href="https://perldoc.perl.org/version" rel="noopener noreferrer"&gt;version.pm&lt;/a&gt; (referred to in this way to disambiguate from the word "version" itself). It has been a core module since Perl v5.10.0, and it is also dual-life, so you can install a newer version from CPAN on any version of Perl (which is helpful for reasons that will become apparent). It disambiguates these two types with simple rules: if the version contains a leading "v" or more than one decimal separator, it's a version tuple; otherwise, it's a decimal number. For this reason it's best to include both a leading "v" and at least two decimal separators for clarity when using tuple versions.&lt;/p&gt;

&lt;h1&gt;
  
  
  Comparing and Converting
&lt;/h1&gt;

&lt;p&gt;For the sake of comparison, a conversion method is defined between the two types of versions. The first integer in a tuple version and the integer component of a decimal version are considered the same, and each successive segment of the tuple version is considered equivalent to three decimal places in a decimal version. So for example, to convert the version '3.01002' to a tuple version, the first segment is 3, the second is 10, and the third is 20 (padding with zeroes so you have groups of 3 decimal places), resulting in 'v3.10.20'. To convert the version 'v0.4.1' to a decimal version, the integer component is 0, the first three decimal places after the separator are 004, and the next three are 001, resulting in '0.004001'.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AAA.BBBCCC &amp;lt;-&amp;gt; vAAA.BBB.CCC
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This method extends to however many segments or decimal places a version may have. The conversion is used by version.pm to compare version objects sourced from either scheme of version. In this way, Perl can determine how one version compares to another even when they are using different schemes.&lt;/p&gt;

&lt;h1&gt;
  
  
  Declaring Versions
&lt;/h1&gt;

&lt;p&gt;Version numbers of each of these forms are not only recognized by Perl for the purpose of checking module versions at runtime, but also by the PAUSE indexer when indexing CPAN modules. In this case and similarly when versions are extracted using &lt;a href="https://perldoc.perl.org/Module::Metadata" rel="noopener noreferrer"&gt;Module::Metadata&lt;/a&gt;, the behavior is to find the declaration of $VERSION and execute only that line in isolation, so your version declaration line must be executable on its own. The simplest and standard form of declaration is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;our&lt;/span&gt; &lt;span class="nv"&gt;$VERSION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.02&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt; &lt;span class="c1"&gt;# for decimal versions, or&lt;/span&gt;
&lt;span class="k"&gt;our&lt;/span&gt; &lt;span class="nv"&gt;$VERSION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;v1.2.3&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt; &lt;span class="c1"&gt;# for tuple versions&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As noted in David Golden's blog post &lt;a href="http://www.dagolden.com/index.php/369/version-numbers-should-be-boring/" rel="noopener noreferrer"&gt;Version Numbers Should Be Boring&lt;/a&gt;, support for tuple versions has varied widely among old versions of Perl. As support is mostly based on the version.pm module, which is core after Perl v5.10.0, you need to take special care if your module will use tuple versions on Perl v5.8.9 or older. Your module should declare a dependency on version.pm (at least version 0.77, but preferably more recent), and declare the version in this way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;version&lt;/span&gt; &lt;span class="mf"&gt;0.77&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;our&lt;/span&gt; &lt;span class="nv"&gt;$VERSION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;('&lt;/span&gt;&lt;span class="s1"&gt;v1.2.3&lt;/span&gt;&lt;span class="p"&gt;');&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keeping this whole declaration on a single line is important so that version.pm is always loaded when this line is executed by PAUSE or other version extraction tools. And of course, the simpler way to remain compatible with older versions of Perl is to stick to decimal number versions.&lt;/p&gt;

&lt;h1&gt;
  
  
  Underscores in Versions
&lt;/h1&gt;

&lt;p&gt;Another complex factor in Perl version numbers is the use of underscores. Underscores are, by convention, used to indicate a development or trial release of a module or distribution, which should not be &lt;a href="https://github.com/andk/pause/blob/master/doc/operating-model.md#3-indexing-permissions" rel="noopener noreferrer"&gt;indexed by PAUSE&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For decimal versions, it's mostly straightforward: an underscore is placed somewhere between the digits, and ignored for comparison purposes. However, since these versions look like decimal numbers, some may naively compare them using numeric operators, which will fail if they contain an underscore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;our&lt;/span&gt; &lt;span class="nv"&gt;$VERSION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.01_02&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$VERSION&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.0101&lt;/span&gt;&lt;span class="p"&gt;')&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This comparison will fail (and throw a non-numeric warning if warnings are enabled) because $VERSION is truncated to '0.01' when used as a number. (A less naive comparison may be performed using the VERSION method or version.pm objects as described later.) To account for this possibility while still leaving the underscore in the declaration for static parsers, a common idiom is to remove the underscore in a following line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;our&lt;/span&gt; &lt;span class="nv"&gt;$VERSION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.01_02&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;span class="nv"&gt;$VERSION&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;tr/_//d&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You may also see eval() used to remove the underscore, but the tr method is more straightforward and preserves trailing zeroes.&lt;/p&gt;

&lt;p&gt;Underscores in tuple versions have a significantly more complicated history, and may be interpreted wildly differently depending on the version of version.pm in use. My recommendation would be to avoid doing this entirely, but if you must, your distribution should declare a dependency on version.pm version 0.9915, when its interpretation of underscores in tuple versions was fixed in several ways, and so that it considers underscores in tuple versions the same way as in decimal versions (i.e. not as a separator).&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternative to Underscore Versions
&lt;/h2&gt;

&lt;p&gt;Rather than using underscores in your versions, there are other mechanisms to indicate a development or trial release of a distribution that don't involve module versions. If the archive file uploaded to CPAN has a name ending in -TRIAL (before the file extensions), PAUSE &lt;a href="https://github.com/andk/pause/blob/master/doc/operating-model.md#35-factors-considering-in-the-indexing-phase" rel="noopener noreferrer"&gt;will not index it as a stable release&lt;/a&gt;. Additionally, you can set the &lt;a href="https://perldoc.perl.org/CPAN::Meta::Spec#release_status" rel="noopener noreferrer"&gt;release_status&lt;/a&gt; metadata field in meta-spec 2; a value of "testing" or "unstable" will indicate that the release should not be indexed. The method of setting this &lt;a href="http://blogs.perl.org/users/neilb/2017/05/specifying-dependencies-for-your-cpan-distribution.html" rel="noopener noreferrer"&gt;depends on your authoring tool&lt;/a&gt;. At the time of writing, either of these methods is sufficient to prevent PAUSE from indexing the distribution, and both are performed automatically by the "--trial" option when releasing using Dist::Zilla or Minilla.&lt;/p&gt;

&lt;h1&gt;
  
  
  Checking for Versions
&lt;/h1&gt;

&lt;p&gt;With all of this in mind, the safest and most consistent way to check for a particular version of a module is with the &lt;a href="https://perldoc.perl.org/UNIVERSAL#VERSION" rel="noopener noreferrer"&gt;UNIVERSAL::VERSION&lt;/a&gt; method, which is implicitly used by the &lt;a href="https://perldoc.perl.org/functions/use" rel="noopener noreferrer"&gt;use Module::Name VERSION&lt;/a&gt; syntax. The VERSION method compares both the module's $VERSION and the passed version as version.pm objects, which automatically does the above-mentioned conversion between version schemes if needed, and throws an exception if the passed version is less than the module version. Like when declaring versions, the version passed to the VERSION method should always be a string or version object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;eval&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="nn"&gt;Module::&lt;/span&gt;&lt;span class="nv"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nn"&gt;Module::&lt;/span&gt;&lt;span class="nv"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="p"&gt;('&lt;/span&gt;&lt;span class="s1"&gt;v1.2.3&lt;/span&gt;&lt;span class="p"&gt;');&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;# Module::Name is able to be loaded and is at least version v1.2.3&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can of course use a &lt;a href="http://mvp.kablamo.org/cpan/exceptions/" rel="noopener noreferrer"&gt;nicer exception-handling method&lt;/a&gt; than bare eval if appropriate.&lt;/p&gt;

&lt;p&gt;On Perls older than v5.10.0 you should make sure to 'use version' before doing a comparison involving tuple versions, which will update the VERSION method to use version objects as it does on more recent perls. I would also, as above, recommend depending on version.pm version 0.9915 if you intend to do any comparisons involving versions with underscores. &lt;/p&gt;

&lt;p&gt;A more generic method of performing arbitrary version comparisons is to parse the versions into version.pm objects and compare them using standard numeric operators.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;('&lt;/span&gt;&lt;span class="s1"&gt;v1.0.3&lt;/span&gt;&lt;span class="p"&gt;')&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nv"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;('&lt;/span&gt;&lt;span class="s1"&gt;1.000003&lt;/span&gt;&lt;span class="p"&gt;'))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;# versions are equivalent&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Versions for Vendors
&lt;/h1&gt;

&lt;p&gt;Perl versions aren't just used within Perl, of course. If you are a CPAN author, you should be mindful that Perl modules from CPAN are packaged for use in various distributions, which primarily use the tuple version format. This doesn't mean you need to use it yourself, but to be polite to those translating your versions, you should follow these simple rules:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;If using decimal versions, never decrease the number of significant digits you use without a major version bump. For example, go from '1.19' to '1.20' or '2.0', not to '1.2'.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Never change version schemes without a major version bump. Even if you use the above translation correctly, the package vendor may not, and thus end up with a decreasing version.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Methods to Avoid
&lt;/h1&gt;

&lt;p&gt;There are a couple other ways to declare versions that should be wholly avoided. One is to declare a bare decimal number version, which means you will lose trailing zeroes and possibly encounter floating-point issues. Sometimes this is used because Perl has a feature that looks like underscores in version numbers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;our&lt;/span&gt; &lt;span class="nv"&gt;$VERSION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.01_02&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# don't do this&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, Perl will immediately compile this to the number 0.0102; underscores in numeric literals are only a visual-aid feature.&lt;/p&gt;

&lt;p&gt;Another method with a complicated history is the Perl &lt;a href="https://perldoc.perl.org/perldata#Version-Strings" rel="noopener noreferrer"&gt;vstrings&lt;/a&gt; feature. This was a feature added in Perl v5.6.0 that seemed to add a convenient syntax for declaring versions that would be stored as a binary string.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;our&lt;/span&gt; &lt;span class="nv"&gt;$VERSION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;v1&lt;/span&gt;&lt;span class="mf"&gt;.2.3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# don't do this&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example would create a string consisting of three characters, with ordinals 1, 2, and 3, equivalent to the string "\x01\x02\x03" (note: the vstring syntax uses decimal ordinals, but the '\x' syntax uses hexadecimal ordinals). While version.pm does parse and allow vstrings to be used to initialize version objects, their interpretation is inconsistent among older versions of Perl and their implementation is surprising in the context of versions (for instance, they are not numerically comparable), so it's better to just use a string. It turns out vstrings are most useful for creating binary string literals, and not versions.&lt;/p&gt;

&lt;h1&gt;
  
  
  Perl Perl Versions
&lt;/h1&gt;

&lt;p&gt;As you may notice, the versions of the Perl interpreter itself use the same rules as those for Perl modules. The &lt;a href="https://perldoc.perl.org/variables/$%5D" rel="noopener noreferrer"&gt;$]&lt;/a&gt; variable is a representation of the version of the current Perl interpreter as a decimal number, and the &lt;a href="https://perldoc.perl.org/variables/$%5EV" rel="noopener noreferrer"&gt;$^V&lt;/a&gt; variable is the version as a version object. From Perl v5.6.0 until Perl v5.10.0 $^V was a vstring rather than a version object, so it's not recommended to use this variable if your code will be running on Perls v5.8.9 or older.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://perldoc.perl.org/functions/use" rel="noopener noreferrer"&gt;use VERSION&lt;/a&gt; statement and runtime &lt;a href="https://perldoc.perl.org/functions/require" rel="noopener noreferrer"&gt;require VERSION&lt;/a&gt; allows one to require a certain version of the Perl interpreter using either scheme of version number. Note however that both of these forms require a bareword version rather than a string, and if you use a decimal version form, the three-decimal-places rule still applies; Perl 5.26 would be represented as '5.026', for example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;v5&lt;/span&gt;&lt;span class="mf"&gt;.14&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# also activates feature bundle and strict&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;Syntax::Keyword::&lt;/span&gt;&lt;span class="nv"&gt;Try&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="nv"&gt;v5&lt;/span&gt;&lt;span class="mf"&gt;.26.1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Perl is &amp;gt;= v5.26.1&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nv"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;say&lt;/span&gt; &lt;span class="p"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Old Perl: $@&lt;/span&gt;&lt;span class="p"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>perl</category>
    </item>
    <item>
      <title>Perl 7: A Modest Proposal</title>
      <dc:creator>Dan</dc:creator>
      <pubDate>Mon, 08 Feb 2021 02:02:57 +0000</pubDate>
      <link>https://dev.to/grinnz/perl-7-a-modest-proposal-434m</link>
      <guid>https://dev.to/grinnz/perl-7-a-modest-proposal-434m</guid>
      <description>&lt;p&gt;My previous two blog posts (&lt;a href="http://blogs.perl.org/users/grinnz/2020/07/perl-7-a-risk-benefit-analysis.html" rel="noopener noreferrer"&gt;Perl 7: A Risk-Benefit Analysis&lt;/a&gt; and &lt;a href="http://blogs.perl.org/users/grinnz/2020/08/perl-7-by-default.html" rel="noopener noreferrer"&gt;Perl 7 By Default&lt;/a&gt;) explored the reasons that a Perl 7 with incompatible interpreter defaults would be a mistake. Subsequently, Perl experienced a &lt;a href="https://perl7faq.grinnz.com/#what-happened-to-the-announced-plans-for-perl-7" rel="noopener noreferrer"&gt;crisis of governance authority&lt;/a&gt; as several core developers also expressed this view. So I will not be further discussing the idea of changing defaults in Perl major versions. But, as I had stated in conclusion:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I believe making good use of a new major version is extremely important to portraying the continued and forward development of Perl to the wider programming community. A major version with major features can be a significant boon to jumpstart the stagnating perception of Perl and bring it in line with the reality of its development.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So then, what should we do? I have some suggestions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stable signatures
&lt;/h2&gt;

&lt;p&gt;The widely lauded &lt;a href="https://perldoc.perl.org/feature#The-'signatures'-feature" rel="noopener noreferrer"&gt;signatures feature&lt;/a&gt; is currently still experimental to facilitate experimentation with &lt;a href="https://www.nntp.perl.org/group/perl.perl5.porters/2019/11/msg256677.html" rel="noopener noreferrer"&gt;several more important features&lt;/a&gt; that are needed for it to be considered feature-complete. However, at this point the basic design is well tested and stabilized, and has been unchanged for the requisite &lt;a href="https://perldoc.perl.org/perlpolicy#experimental" rel="noopener noreferrer"&gt;two stable releases&lt;/a&gt;. I propose that in Perl 7, the signatures feature be declared stable as-is, added to the &lt;code&gt;:7.0&lt;/code&gt; feature bundle, and these further additions to be developed as a separate initiative. The new additions could trigger distinct experimental warnings until stabilized, or be added under one or more new experimental features as appropriate. (Stabilization of the signatures feature has now been &lt;a href="https://github.com/Perl/perl5/issues/18537" rel="noopener noreferrer"&gt;proposed&lt;/a&gt; by Paul Evans.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Remove misfeatures
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://perldoc.perl.org/feature#The-'indirect'-feature" rel="noopener noreferrer"&gt;indirect&lt;/a&gt;, &lt;a href="https://github.com/Perl/perl5/pull/17808" rel="noopener noreferrer"&gt;multidimensional&lt;/a&gt;, and &lt;a href="https://github.com/Perl/perl5/pull/18073" rel="noopener noreferrer"&gt;bareword_filehandles&lt;/a&gt; features being added in Perl 5.34 (well, indirect is already in Perl 5.32) are "negative" features; the behavior has existed in Perl for quite a while, but the presence of the named features allow disabling them lexically. These misfeatures are not considered best practice and lead to confusing issues, and the ability to disable them, or at least complain loudly upon encountering their use, has been available from CPAN modules for some time; a modern feature bundle should disrecommend their use. I propose removing these three features from the &lt;code&gt;:7.0&lt;/code&gt; feature bundle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Apply warnings
&lt;/h2&gt;

&lt;p&gt;Since &lt;code&gt;v5.12&lt;/code&gt; or &lt;code&gt;5.012&lt;/code&gt;, the &lt;a href="https://perldoc.perl.org/functions/use" rel="noopener noreferrer"&gt;use VERSION&lt;/a&gt; keyword has enabled &lt;code&gt;strict&lt;/code&gt; alongside the appropriate feature bundle. I propose that Perl 7 finally has &lt;code&gt;use VERSION&lt;/code&gt; enable both the recommend &lt;code&gt;strict&lt;/code&gt; and &lt;code&gt;warnings&lt;/code&gt; pragmas when a version of 7 or higher is requested.&lt;/p&gt;

&lt;h2&gt;
  
  
  Apply utf8
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://perldoc.perl.org/utf8" rel="noopener noreferrer"&gt;utf8 pragma&lt;/a&gt; declares that the current source file is encoded in UTF-8 rather than the native single-byte encoding (usually ISO-8859-1). (This is unrelated to functions in that namespace such as &lt;code&gt;utf8::decode&lt;/code&gt; as well as other UTF-8 related behavior like that provided by the &lt;a href="https://perldoc.perl.org/open" rel="noopener noreferrer"&gt;open pragma&lt;/a&gt;.) Zefram &lt;a href="https://www.nntp.perl.org/group/perl.perl5.porters/2017/10/msg246838.html" rel="noopener noreferrer"&gt;previously proposed&lt;/a&gt; that this pragma be gradually made default and thus a no-op, to better match the expectations of modern programming. Along with and in anticipation of this step, I propose that Perl 7 has &lt;code&gt;use v7&lt;/code&gt; also do the equivalent of &lt;code&gt;use utf8&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  All Together
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Declare 'signatures' feature stable as is&lt;/li&gt;
&lt;li&gt;Add 'signatures' feature to :7.0 feature bundle&lt;/li&gt;
&lt;li&gt;Remove 'indirect', 'multidimensional', and 'bareword_filehandles' negative features from :7.0 feature bundle&lt;/li&gt;
&lt;li&gt;Apply effect of 'use warnings' with 'use v7' or higher&lt;/li&gt;
&lt;li&gt;Apply effect of 'use utf8' with 'use v7' or higher&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of this (note: &lt;code&gt;use v5.32&lt;/code&gt; already includes &lt;code&gt;strict&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight perl"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;v5&lt;/span&gt;&lt;span class="mf"&gt;.32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;warnings&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;utf8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nv"&gt;experimental&lt;/span&gt; &lt;span class="p"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;signatures&lt;/span&gt;&lt;span class="p"&gt;';&lt;/span&gt;
&lt;span class="nb"&gt;no&lt;/span&gt; &lt;span class="nv"&gt;feature&lt;/span&gt; &lt;span class="sx"&gt;qw(indirect multidimensional bareword_filehandles)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;New, modern code will simply be able to write:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;And instead of this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;perl &lt;span class="nt"&gt;-Mstrict&lt;/span&gt; &lt;span class="nt"&gt;-Mwarnings&lt;/span&gt; &lt;span class="nt"&gt;-Mutf8&lt;/span&gt; &lt;span class="nt"&gt;-Mexperimental&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;signatures
    &lt;span class="nt"&gt;-M-feature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;indirect,multidimensional,bareword_filehandles
    &lt;span class="nt"&gt;-E&lt;/span&gt;&lt;span class="s1"&gt;'sub dumphex ($str) { printf "%vX", $str } dumphex "☃"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Modern oneliners will be able to get the same effect from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;perl &lt;span class="nt"&gt;-M7&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt;&lt;span class="s1"&gt;'sub dumphex ($str) { printf "%vX", $str } dumphex "☃"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Looking to the Future
&lt;/h2&gt;

&lt;p&gt;We must consider not only what Perl 7 should be, but what Perl should be beyond this milestone. Following from the above proposal for what Perl 7 and &lt;code&gt;use v7&lt;/code&gt; could entail, this naturally leads to a flexible, powerful, and considerate method of promoting stable features and a modern programming environment.&lt;/p&gt;

&lt;p&gt;Past &lt;a href="https://perldoc.perl.org/feature#FEATURE-BUNDLES" rel="noopener noreferrer"&gt;feature bundles&lt;/a&gt; have been changed rather rarely but at seemingly random versions which are difficult to recall even for the most attentive Perl hacker. Since the introduction of feature bundles in Perl 5.10, they have only changed in 5.12, 5.16, 5.24, and 5.28. Thus my final proposal is that we no longer change feature bundles in arbitrary releases, but only in (true) major versions, which provide significantly more memorable junction points and opportunity for advertisement of these important features.&lt;/p&gt;

&lt;p&gt;There are several features currently in the experimental, design, or CPAN prototyping phase that portend to further improve the modern Perl experience, many of which Paul Evans discussed in his &lt;a href="https://video.fosdem.org/2021/D.perl/perl_in_2025.mp4" rel="noopener noreferrer"&gt;FOSDEM 2021 talk&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://perldoc.perl.org/feature#The-'isa'-feature" rel="noopener noreferrer"&gt;isa&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.nntp.perl.org/group/perl.perl5.porters/2019/11/msg256677.html" rel="noopener noreferrer"&gt;signatures improvements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Perl/perl5/issues/18504" rel="noopener noreferrer"&gt;try/catch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.nntp.perl.org/group/perl.perl5.porters/2020/06/msg257494.html" rel="noopener noreferrer"&gt;match/case&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Ovid/Cor/wiki" rel="noopener noreferrer"&gt;Cor OO&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Any of these features which are not stable and ready for inclusion in a &lt;code&gt;v7&lt;/code&gt; feature bundle, as well as any that are built in the meantime, can be revisited for &lt;code&gt;v8&lt;/code&gt;. Each successive major version bundle can continue to promote the best practices of Perl features and help users evolve their usage of modern Perl with a clear, simple declaration. And most importantly, each major version including 7 can be scheduled once a sufficiently exciting new modern feature set is stable and ready to &lt;code&gt;use&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Perl 7 is dead. Long live Perl 7.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.reddit.com/r/perl/comments/lfvtbi/perl_7_a_modest_proposal/" rel="noopener noreferrer"&gt;&lt;em&gt;Reddit comments&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

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