Shortcuts: s show h hide n next p prev

The Long Road from CGI to Containers

Perl Hacks

One of the defining characteristics of a good programmer is an instinct for keeping implementation details in the correct layer of an application.

That sounds abstract, but it turns out to explain a huge amount of the progress we’ve made in software development over the last twenty-five years.

And nowhere is that clearer than in Perl web development.

Many of us who built web applications during the dotcom boom spent years learning this lesson the hard way.

We wrote CGI programs that:

  • parsed HTTP requests
  • generated HTML by hand
  • connected directly to databases
  • embedded SQL inline
  • mixed business logic with presentation
  • relied on Apache behaviour
  • assumed specific filesystem layouts
  • and often only worked on one particular server configuration

It all worked. Until it didn’t.

The history of Perl web development is, in many ways, the history of gradually moving implementation details into more appropriate architectural layers.


The Early CGI Years

Early Perl CGI applications were often a single giant script.

You’d open a file and see:

  • request handling
  • authentication
  • HTML generation
  • SQL queries
  • business logic
  • configuration
  • deployment assumptions

…all mixed together in a glorious ball of mud.

Something like this:

#!/usr/bin/perl

use CGI;
use DBI;

my $cgi = CGI->new;

print $cgi->header;
print "<html><body>";

my $dbh = DBI->connect(
  "dbi:mysql:test",
  "user",
  "pass"
);

my $sth = $dbh->prepare(
  "select * from users where id = ?"
);

$sth->execute($cgi->param('id'));

while (my $row = $sth->fetchrow_hashref) {
  print "<h1>$row->{name}</h1>";
}

print "</body></html>";

At the time, this felt perfectly normal.

And to be fair, it was a huge step forward from static HTML sites.

But the design had a fundamental problem:

Everything knew too much about everything else.

The application logic knew:

  • how HTTP worked
  • how HTML worked
  • how Apache launched CGI scripts
  • how the database worked
  • how the operating system was configured

Every concern leaked into every other concern.

That made systems:

  • hard to test
  • hard to reuse
  • hard to deploy
  • hard to scale
  • and terrifying to change

The First Big Lesson: Put Logic in Libraries

One of the first signs of a developer maturing is the realisation that application logic should live in reusable modules, not in front-end scripts.

Instead of this:

if ($user->{status} eq 'gold') {
  $discount = 0.2;
}

being embedded directly in a CGI script, it becomes:

my $discount = $user->discount_rate;

That sounds like a small change, but architecturally it’s enormous.

Now the business logic lives in a library.

And once that happens, several good things follow automatically.

Multiple Interfaces Become Possible

If the logic is in modules, then:

  • a web front-end
  • a CLI tool
  • a REST API
  • a cron job
  • a queue worker

…can all use the same underlying code.

The interface layer becomes thin.

The application itself becomes independent of how users interact with it.

That’s a huge increase in flexibility.

Testing Becomes Easier

Testing CGI scripts was always awkward.

Testing modules is straightforward.

You can instantiate objects, call methods, and inspect results without needing a web server or HTTP requests.

The easier code is to test, the more likely it is to be tested.

And tested code tends to survive longer.

Deployment Becomes Safer

Once the core behaviour is isolated from the interface layer, replacing the interface becomes far less risky.

You can redesign the UI without rewriting the application.

That separation is one of the foundations of maintainable software.


The PSGI Revolution

The next big architectural leap in Perl web development came with PSGI and Plack.

Younger developers may not fully appreciate how painful web deployment used to be.

In the early 2000s, moving an application between hosting environments could require substantial rewrites.

  • A CGI application worked one way.
  • A mod_perl application worked another way.
  • FastCGI had its own quirks.
  • Embedded Apache handlers behaved differently again.

Many Perl developers spent years repeatedly rewriting applications simply because deployment environments changed.

That was madness.

The deployment model is an operational concern.

It should not affect application architecture.

PSGI fixed this by defining a standard interface between web applications and web servers.

The core idea was beautifully simple:

A web application is just a function that receives an environment and returns a response.

Once that abstraction existed, applications no longer cared whether they were running:

  • as CGI
  • under mod_perl
  • inside FastCGI
  • under Starman
  • behind nginx
  • on a development laptop
  • or inside a cloud container

The deployment details moved down a layer.

Exactly where they belonged.

This was one of the most important architectural improvements Perl web development ever made.

And it reflected a broader truth:

Good abstractions stop lower-level implementation details leaking upward.


The Transitional Era: FatPacker and cpanfile

There was also an interesting intermediate stage between traditional Perl deployments and full containerisation.

For years, one of the hardest parts of deploying Perl applications was dependency management.

You’d move an application to a new server and discover:

  • the wrong module version
  • missing XS libraries
  • incompatible Perl versions
  • or an entire dependency tree that worked perfectly on the developer’s machine and nowhere else

Large parts of Perl deployment culture evolved around coping with this problem.

Tools like cpanfile improved things by making dependencies explicit and reproducible.

Instead of vaguely documenting requirements in a README, applications could formally declare:

requires 'Dancer2';
requires 'DBIx::Class';
requires 'Template';

That may seem obvious now, but it was a major improvement in deployment reliability.

Then tools like App::FatPacker went even further by packaging dependencies directly alongside applications.

Instead of relying on the target server’s Perl environment, applications could carry much of their runtime context with them.

These tools didn’t completely solve deployment portability:

  • system libraries still mattered
  • Perl versions still mattered
  • operating system differences still mattered

…but they represented an important shift in thinking.

The industry was gradually realising that:

  • deployment environments were part of the application
  • reproducibility mattered
  • and infrastructure assumptions needed to be controlled

Containers eventually pushed this idea to its logical conclusion by packaging not just Perl dependencies, but the entire runtime environment.

In hindsight, tools like cpanfile and FatPacker were stepping stones toward modern container-based deployment models.


Containers Are the Same Idea Again

Docker and containers are simply the same architectural principle repeated one layer lower.

Before containers, deployments were often fragile and highly environment-specific.

Applications depended on:

  • particular Linux distributions
  • specific Perl versions
  • installed system libraries
  • hand-configured servers
  • undocumented setup steps

Developers became experts in “works on my machine”.

Operations teams became experts in swearing.

Containers changed the model.

Instead of deploying:

  • source code

…you deploy:

  • a complete runtime environment

Now the application no longer cares whether it runs:

  • on bare metal
  • on a VPS
  • in Kubernetes
  • in ECS
  • in Cloud Run
  • or on someone’s laptop

Again:

  • infrastructure concerns move downward
  • application concerns stay upward

The boundaries become cleaner.


The Pattern Repeats Everywhere

Once you notice this pattern, you see it throughout software engineering.

Templates

Template systems separate:

  • presentation

from

  • application logic

HTML should not contain database code.

Business logic should not contain giant blobs of HTML.

ORMs and Database Layers

DBI separates applications from database engines.

ORMs separate applications from raw SQL structure.

Again:

  • implementation details move downward

Configuration

Configuration belongs outside code.

Deployment-specific values should not be embedded in applications.

APIs

Clients should not care whether data comes from:

  • PostgreSQL
  • Redis
  • another service
  • a queue
  • flat files
  • or magic elves

That’s the implementation’s problem.


The Goal Is Not Abstraction for Its Own Sake

Of course, experienced developers also know that abstractions can become ridiculous.

Some abstractions simplify systems.

Others merely hide complexity behind six additional layers of YAML.

Joel Spolsky’s “Law of Leaky Abstractions” remains painfully relevant.

The goal is not abstraction itself.

The goal is to isolate genuinely volatile details.

Good abstractions protect systems from change.

Bad abstractions merely obscure reality.


The Real Skill

The deeper lesson here is that software architecture is largely about deciding:

“What belongs where?”

Experienced developers develop an instinct for:

  • which details are likely to change
  • which layers should know about which concerns
  • and where boundaries should exist

That instinct is often more important than language choice, frameworks, or technology stacks.

And if you spent the early 2000s rewriting CGI applications to run under mod_perl, you probably learned that lesson the hard way.

Perl Web Development Over Time
Perl Web Development Over Time

The post The Long Road from CGI to Containers first appeared on Perl Hacks.

cpan/IO-Socket-IP - Update to version 0.44

0.44    2026-05-13
        [CHANGES]
         * Can `use parent` rather than `use base` (thanks James Raspass)
           (RT177570)

0.43    2024-11-25
        [CHANGES]
         * Swapped unit tests from `Test::More` to `Test2::V0`
         * Fixed some documentation typoes
           (thanks Igor Sobrado Delgado) (RT157201)
fix doc error on perlinterp
perlintro: Fix example code to fit description

Fixes #24422

Suggested by Eugene Smirnov

Originally published at Perl Weekly 773

Hi there!

Recently there were a number of days that the perl-tester Docker image did not build properly. It is always a bit of an issue with it, because there quite a few moving parts. Parts where the dependency isn't fixed. e.g. in most of the cases it installs the most recent version of the modules from CPAN. Which mean any release of any module might break the whole build process. This time, however, the source of the problem was the new release of App::cpm, the tool used to install the CPAN modules. As often the case the new release was intended to improve things: cpm v1: making installs stable, but it broke the build on some of the older versions of Perl just by increasing the minimum version of Perl required.

One solution would be to fix all the dependencies, both tooling and the modules we install, but then someone would need to keep track of changes (the way dependabot does) which is probably way too much work for the few people who contribute to this project. The other solution might be to create an easy way to see what changed between the last successful build and the current failing build. We have started to work on a tool that will help with that. It will also allow us to show exactly what is in every image. BTW If you have spare stars in your pocket, it would be nice if you gave one to the docker-perl-tester project.

A couple of days ago I started to play with FalkorDB, an Open Source Graph Database. I already gave a presentation in Hebrew on how to use in general and specifically in Python. In a couple of hours I am going to give another one - this time in English - an intro to GraphDB. I'll use Rust for the programatic examples. It seems there is no client for it in Perl so it might be an interesting project to build one. The one in Python uses the Redis module for connectivity so I looked at the options to use Redis in Perl. MetaCPAN showed the Redis module as the first hit. Unfortunately that module did not have a commit for 3 years and there are many outstanding Issues and even PRs. So I posted about it both in the Perl Maven WhatsApp group and in the Telegram channel. Within seconds I was pointed towards Mojo::Redis and Redis::XS as alternatives.

Online Events: If you are in an American time-zone then both the Boston Perl Mongers and the Toronto Perl Mongers have semi-regular online meetings in your evening hours with various interesting speakers. If you are in the European time-zones or you don't mind having a meeting in your morning hours in the Americas, then there is the Perl Maven group where it is mostly me giving a presentation or working on some code. For details check out the Perl Weekly events page.

Enjoy your week!

--
Your editor: Gabor Szabo.

Announcements

cpan.org email forwarding has been shut down

The Perl NOC team has shut down the forwarding of email to the cpan addresses. If you are a CPAN author, please make sure MetaCPAN displays ways to contact you. (link to the source git repository of your projects, a LinkedIn account, an email address, etc.)

Articles

cpm v1: making installs stable

I rarely include articles from Medium as most of them are spam, but this one is real. So here you are!

Is your account on blogs.perl.org registered with an @cpan.org email address?

Installing Bit::Vector on Debian 13 (Trixie)

It is good that this information can be found on a public blog post, but IMHO it would be event better if this was part of the README or the documentation of the project.

My Journey with Devel::ptkdb - Origins

Enabling AddressSanitizer (ASan) in Makefile.PL for Linux Environments

Introducing Time::Str

At first I was wondering why this new module when DateTime provides all the features, but then I read on and there are a few reasons. Interesting.

Discussion

Optional stricter normalization of raw ISBN input

An issue that gives an opportunity for you to share your thoughts.

Why does a call to ref on a reference to 'substr' produce 'LVALUE'?

Perl

This week in PSC (224) | 2026-05-11

The Weekly Challenge

The Weekly Challenge by Mohammad Sajid Anwar will help you step out of your comfort-zone. You can even win prize money of $50 by participating in the weekly challenge. We pick one champion at the end of the month from among all of the contributors during the month, thanks to the sponsor Marc Perry.

The Weekly Challenge - 374

Welcome to a new week with a couple of fun tasks "Count Vowel" and "Largest Same-digits Number". If you are new to the weekly challenge then why not join us and have fun every week. For more information, please read the FAQ.

RECAP - The Weekly Challenge - 373

Enjoy a quick recap of last week's contributions by Team PWC dealing with the "Equal List" and "List Division" tasks in Perl and Raku. You will find plenty of solutions to keep you busy.

Perl Weekly Challenge 373: Equal List

The clean, logical structure of Abigail's detailed technical analysis provides a very clear and rational basis for how best to apply mathematical theory to practical use. With a focus on optimising the algorithmic complexity rather than executing a brute force approach, Abigail delivers an incredibly efficient solution to this problem that will be valuable to all developers who wish to create highly efficient solutions to their problems.

Perl Weekly Challenge 373: List Division

Abigail's solution to the list partitioning problem is a beautifully crafted and idiomatic implementation that completely avoids the cumbersome index-tracking that traditional loop-based implementations require. The implementation is easy to read and is highly efficient because it leans heavily on the mechanics of the underlying language. This illustrates how an effective structural data transformation paradigm can result in simpler implementations.

List the List

Through a demonstration using gather and take in conjunction with native array splicing Arne demonstrates Raku's capabilities and gives a simple way to distribute remaining list offsets without having to rely on complex nested loops or overhead due to atypical index calculations. The result is a functional representation showing how Raku can eliminate complications associated with the partitioning of structural data, creating an intuitive self-documenting pattern.

Let's Dance to List Division

Bob has produced a superbly developer-oriented analysis addressing the pragmatic aspects of designing APIs using Perl's 'flat' argument list mechanism. Bob's approach to using array references in conjunction with a dual-while-loop, which uses 'destructive splice' calls to divide the input data into well-balanced partitions, enables this entire operation to occur without requiring any complex index-tracking cognitive load.

Divide and Concat

Jorg has provided a mathematically accurate and highly precise solution that demonstrates command of Perl's multidimensional array manipulation and list processing capabilities. The solution has been designed with a heavy emphasis on reducing iteration overhead, and uses a clean and logical approach to conditional checking. Overall, the implementation is an efficient way to manage data structures for all of the tasks required to complete this project.

Perl Weekly Challenge 373

W. Luis Mochan gives an interesting, very mathematical view of the difficulties and has elevated the difficulty of the tasks by discussing the different ways each of these tasks can be solved through their mathematical representations. The way the solution uses Perl Data Language is unique in its creativity and clearly shows how matrix operations and vector operations can be applied in a different manner to solve an algorithmic process much more efficiently and faster than typical procedural methods. This is a remarkable, challenging read, demonstrating the way that thinking in terms of vectors alone can change the way standard procedure of manipulating data can be made into a high level, abstract manner.

Because your list, your list I can’t resist

Packy offers a unique perspective on the challenge by framing the approach through an interesting musical context, followed by a really clean, multilingual show-off with a few different language options. As a polyglot expert, Packy's write-up shows a number of idiomatic and clean ways to solve problems in both Perl and Elixir. The solutions have been complimented for their clear structure, readable transformations of data, and the highly contrasting ways in which they use the procedural power of Perl with the functional, pipeline-based elegance of Elixir.

The week of lists

This paragraph describes the outstanding quality of Peter's work in executing his weekly assignments and projects using clear and detailed methods. He concentrates on providing clear and easy to understand explanations of all aspects of the problem using very pragmatic solutions with less complex algorithms than would be required to complete this task, and thus have produced solutions with low run times and high readability. Another benefit of using this strategy is that it will have produced many examples of good clean and maintainable code, as well as simple Perl code showing how to accomplish structural validation without additional runtime cost.

The Weekly Challenge - 373: Equal List

The analysis that Reinier provided on this challenge is truly impressive due to the systematic approach used to cover edges and validate input. The solution makes a great balance between how computer efficient it is to run while at the same time being easy to scan through for code due to well-named variables and clearly defined logical conditions. This is a great resource for developers looking to implement defensive programming and build highly maintainable systems.

The Weekly Challenge - 373: List Division

Reinier has presented a very clear and logical way to solve the list partitioning problem through clarity in procedural programming and appropriately managing data through effective use of algorithms. The implemented solution is easy to follow, with simple looping structures and clearly defined conditions used to divide the collection according to specification without introducing complexity into the underlying architecture. This solution is a perfect example of pragmatic programming, where simplicity, maintainability, and consistency take precedence over unnecessary abstraction.

The Weekly Challenge #373

The analysis provided by Robbie consists of an analysis of the weekly problems and an an idea of what you'd have to do. The breakdown of the problems will be thoroughly examined and will include thorough analysis of all the constraints on the solution as well as a commitment to validate input sufficiently to account for any and all edge cases and to deal with them accordingly. The combination of cleanly structured idiomatic programming style (including the use of loops) with clear and explicit comments that explain the logic behind the programming additions and modifications, make this a great reference source for new and experienced programmers to use.

There Is No Equality Without Division

Roger performs a beautiful and tidy example of modern solutions to solving problems through example in different programming languages and paradigms. The two different types of tasks, structural validation and partitioning, have been broken down into separate clear logical blocks that allow for high readability of solutions and the use of commonly used data structures without the use of complex loops. The write-up contains an excellent comparison of the different language features that reduce index-tracking overhead while still providing optimal run-time efficiency and successfully illustrates how functional programming techniques can be used successfully with non-functional programming techniques.

Joining and splitting lists

Simon has presented an impressively logical and practical polyglot demonstration that compares the elegant way of handling the first task in Python to how it is done through direct translations into Perl. The first task's solution is particularly notable for its concise efficiency and consists of a great, simply written one-liner using native methods to join strings and performing a direct comparison to form the structure of the list being checked. In the second task, Simon has shown a brilliant method for diving an array into equal components by taking advantage of the mathematical operation called divmod or remainder and relying on destructive splice operations to divide the arrays evenly without creating any overhead from having to manage cumbersome index numbers.

Videos

Parsing Perl Without Perl - A Rust LSP for Perl 5

A presentation by Steven Zimmerman, CPA, at the online event of the Toronto Perl Monger

Acting Out With Claude: MCPs in Perl

A presentation by Steven Lembark, at the online event of the Toronto Perl Monger

Weekly collections

NICEPERL's lists

Great CPAN modules released last week.

Events

Exploring Perl Modules

May 20, 2026

Toronto.pm - online - JSON Schema: language-agnostic typing / May TPM meeting

May 29, 2026

Boston Perl Mongers virtual monthly

June 9, 2026

The Perl and Raku Conference 2026

June 26-29, 2026, Greenville, SC, USA

You joined the Perl Weekly to get weekly e-mails about the Perl programming language and related topics.

Want to see more? See the archives of all the issues.

Not yet subscribed to the newsletter? Join us free of charge!

(C) Copyright Gabor Szabo
The articles are copyright the respective authors.

Thank you Team PWC for your continuous support and encouragement.
Welcome to the Week #374 of The Weekly Challenge.

Toronto Perl Mongers / Stephen Zimmerman

The Perl and Raku Conference YouTube channel

The unexpected intersection of maths literacy and coding confidence that every secondary educator should know about

As you know, The Weekly Challenge, primarily focus on Perl and Raku. During the Week #018, we received solutions to The Weekly Challenge - 018 by Orestis Zekai in Python. It was pleasant surprise to receive solutions in something other than Perl and Raku. Ever since regular team members also started contributing in other languages like Ada, APL, Awk, BASIC, Bash, Bc, Befunge-93, Bourne Shell, BQN, Brainfuck, C3, C, CESIL, Chef, COBOL, Coconut, C Shell, C++, Clojure, Crystal, CUDA, D, Dart, Dc, Elixir, Elm, Emacs Lisp, Erlang, Excel VBA, F#, Factor, Fennel, Fish, Forth, Fortran, Gembase, Gleam, GNAT, Go, GP, Groovy, Haskell, Haxe, HTML, Hy, Idris, IO, J, Janet, Java, JavaScript, Julia, K, Kap, Korn Shell, Kotlin, Lisp, Logo, Lua, M4, Maxima, Miranda, Modula 3, MMIX, Mumps, Myrddin, Nelua, Nim, Nix, Node.js, Nuweb, Oberon, Octave, OCaml, Odin, Ook, Pascal, PHP, PicoLisp, Python, PostgreSQL, Postscript, PowerShell, Prolog, R, Racket, Rexx, Ring, Roc, Ruby, Rust, Scala, Scheme, Sed, Smalltalk, SQL, Standard ML, SVG, Swift, Tcl, TypeScript, Typst, Uiua, V, Visual BASIC, WebAssembly, Wolfram, XSLT, YaBasic and Zig.
Last night, I published a blog post about JWT with Dancer2. It was something that I never had chance to play with. I thoroughly enjoyed the journey.
Thank you Team PWC for your continuous support and encouragement.

Then here is a reminder that in light of current events you will want to update your account to use a different email address. (There are about 130 of you that get to jump through this hoop now.)

If you need help, email contact@blogs.perl.org as per usual.

Updates for great CPAN modules released last week. A module is considered great if its favorites count is greater or equal than 12.

  1. App::DBBrowser - Browse SQLite/MySQL/PostgreSQL databases and their tables interactively.
    • Version: 2.441 on 2026-05-15, with 18 votes
    • Previous CPAN version: 2.440 was released 1 month, 3 days before
    • Author: KUERBIS
  2. App::Netdisco - An open source web-based network management tool.
    • Version: 2.098005 on 2026-05-10, with 865 votes
    • Previous CPAN version: 2.098004 was released 1 day before
    • Author: OLIVER
  3. App::zipdetails - Display details about the internal structure of Zip files
    • Version: 4.006 on 2026-05-16, with 66 votes
    • Previous CPAN version: 4.005 was released 2 months, 7 days before
    • Author: PMQS
  4. Archive::Tar - Manipulates TAR archives
    • Version: 3.06 on 2026-05-10, with 16 votes
    • Previous CPAN version: 3.04 was released 1 year, 2 months, 12 days before
    • Author: BINGOS
  5. Crypt::JWT - JSON Web Token
    • Version: 0.038 on 2026-05-16, with 54 votes
    • Previous CPAN version: 0.037_2 was released 5 days before
    • Author: MIK
  6. Crypt::Passphrase - A module for managing passwords in a cryptographically agile manner
    • Version: 0.023 on 2026-05-15, with 17 votes
    • Previous CPAN version: 0.022 was released 1 month, 24 days before
    • Author: LEONT
  7. CryptX - Cryptographic toolkit
    • Version: 0.089 on 2026-05-10, with 53 votes
    • Previous CPAN version: 0.088_005 was released 3 days before
    • Author: MIK
  8. Google::Ads::GoogleAds::Client - Google Ads API Client Library for Perl
    • Version: v32.1.0 on 2026-05-13, with 20 votes
    • Previous CPAN version: v32.0.0 was released 20 days before
    • Author: CHEVALIER
  9. Imager - Perl extension for Generating 24 bit Images
    • Version: 1.031 on 2026-05-15, with 68 votes
    • Previous CPAN version: 1.030 was released 1 month, 1 day before
    • Author: TONYC
  10. IO::Socket::IP - Family-neutral IP socket supporting both IPv4 and IPv6
    • Version: 0.44 on 2026-05-13, with 22 votes
    • Previous CPAN version: 0.43 was released 1 year, 5 months, 17 days before
    • Author: PEVANS
  11. JSON::Schema::Modern - Validate data against a schema using a JSON Schema
    • Version: 0.639 on 2026-05-09, with 16 votes
    • Previous CPAN version: 0.638 was released 21 days before
    • Author: ETHER
  12. LWP - The World-Wide Web library for Perl
    • Version: 6.83 on 2026-05-12, with 211 votes
    • Previous CPAN version: 6.82 was released 1 month, 13 days before
    • Author: OALDERS
  13. LWP::ConsoleLogger - LWP tracing and debugging
    • Version: 1.000002 on 2026-05-12, with 12 votes
    • Previous CPAN version: 1.000001 was released 2 years, 10 months, 21 days before
    • Author: OALDERS
  14. Mojo::Pg - Mojolicious ♥ PostgreSQL
    • Version: 5.0 on 2026-05-12, with 98 votes
    • Previous CPAN version: 4.29 was released 1 month, 19 days before
    • Author: SRI
  15. SPVM - The SPVM Language
    • Version: 0.990172 on 2026-05-13, with 36 votes
    • Previous CPAN version: 0.990171 was released 2 days before
    • Author: KIMOTO
  16. Win32 - Interfaces to some Win32 API Functions
    • Version: 0.62 on 2026-05-11, with 13 votes
    • Previous CPAN version: 0.61 was released the same day
    • Author: JDB
  17. YAML::LibYAML - Perl YAML Serialization using XS and libyaml
    • Version: v0.907.0 on 2026-05-10, with 60 votes
    • Previous CPAN version: v0.906.1 was released 14 days before
    • Author: TINITA

Whilst Bit::Vector is available as a Debian package in libbit-vector-perl, when installing it using cpanm the compile failed for me.

The installation crashed during the make stage, throwing a specific compiler error regarding false and true tokens:

Failure Output:
Building Bit-Vector-7.4
...
cc -c   -D_REENTRANT -D_GNU_SOURCE -fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2 -O2   -DVERSION=\"7.4\" -DXS_VERSION=\"7.4\" -fPIC "-I/home/dean/perl5/perlbrew/perls/perl-5.40.3/lib/5.40.3/x86_64-linux-thread-multi/CORE"   BitVector.c
In file included from BitVector.c:12:
ToolBox.h:98:20: error: cannot use keyword 'false' as enumeration constant
   98 |              enum { false, true };
      |                    ^~~~~
ToolBox.h:98:20: note: 'false' is a keyword with '-std=c23' onwards
make: *** [Makefile:343: BitVector.o] Error 1
-> FAIL Installing Bit::Vector failed.

Why this happens:

The issue stems from modern Linux distributions upgrading their default compiler (like GCC 15+) to use the C23 (ISO C 2023) standard. In C23, false and true became official, reserved language keywords[cite: 2]. Because Bit::Vector is an older module, its internal ToolBox.h file explicitly tries to define them inside an enum block for legacy compatibility, which modern C23 compliance strictly forbids[cite: 2].

A solution that worked was:

cpanm --configure-args="OPTIMIZE='-O2 -std=gnu17'" Bit::Vector

What this does:

  • --configure-args
    Passes arguments directly to the underlying Makefile.PL build script[cite: 2].
  • OPTIMIZE='-O2 -std=gnu17'
    Overrides the default compiler optimization settings[cite: 2]. It keeps standard -O2 optimization performance but strictly forces the compiler to treat the codebase as GNU C17 instead of C23[cite: 2]. This bypasses the keyword restrictions and allows the legacy enum declaration to succeed flawlessly[cite: 2].

Hopefully this will help someone else running into the same roadblock!

perlpolicy: better integrate version support table

This removes some recently introduced subheadings and drops some
now-redundant prose for brevity and flow, in hopes of encouraging
rather than discouraging readers from reading the section in its
entirety. (For full effect, compare the full section before and
after, rather than looking only at the diff.)
perlpolicy: minor SUPPORT section copyedits

These both work:

echo 'jg984tj89g02jg09248gj4209jg49' | perl -0lne 'print "$_\n" for /(\d)([a-z])/gs'
echo 'jg984tj89g02jg09248gj4209jg49' | perl -0lne '@m = /(\d)([a-z])/gs; print for @m'

But this doesn't:

echo 'jg984tj89g02jg09248gj4209jg49' | perl -0lne 'print "$1-->$2\n" for /(\d)([a-z])/gs'

(Basically, the last command outputs the capture groups over and over again for the last match, not iterating over each match.)

Why?

It would have been nice to control formatting with the last command. It could have been a quick, simple and convenient way of preparing / structuring the data for any next command.

I am stuck in a Perl script. The regex is verified, but Copy.pm complains: Use of uninitialized value $to in -d at /opt/homebrew/opt/perl/lib/perl5/5.42/File/Copy.pm line 255

What this script is doing, you will see in the comments. I tested also with a debugger, and the regex is matching.

Here is my attempt:

#!/opt/homebrew/bin/perl

# Change Filenames from: Free CCNA | Network Devices | Day 1 | CCNA 200-301 Complete Course [H8W9oMNSuwo]
# to:
# Free CCNA _ Day 01 _ Network Devices _ CCNA 200-301 Complete Course-H8W9oMNSuwo
# run it in shell like follows:
# ./rename_file03.pl .
# the point is the actual folder to start. Or an other path
# to the folder to start with ...
# change from:
# Free CCNA _ Day 33 Lab _ Configuring IPv6 (Part 3) _ CCNA 200-301 Complete Course-WSBEVFANMmc.mp4
# Free CCNA | Configuring IPv6 (Part 3) | Day 33 Lab | CCNA 200-301 Complete Course [WSBEVFANMmc].webm
# 1 step: remove `| (Day \d+ (Lab)?)` and capture it in `$day` to insert it later
# 2 step: capture extension: `(\.\w+)$`
# 2 step: replace all ` | ` with ` _ `
# 3 step: remove `\[([^]+\)]` and capture it in $yt
# 4 step: replace `Free CCNA ` with `\&$day`
# 5 step: aad to the filename `$yt$ext`
# (Free CCNA) | ([^|]+) | (Day \d+( Lab)?) | ([^]]+) (\[[^]\]+)(\..+)

use warnings;
use strict;
use feature 'say';
use File::Find;
use File::Copy;
# use String::Util qw(trim);

my @main_folders = @ARGV; # for example ./command + path/to/folder : ./rename_file.pl foo01/
# my $path = `pwd`; # for example foo01
# chomp($path); # now without \n
my $working_folder;

foreach my $main_folder (@main_folders) {

    $main_folder =~ s,/+$,,;    # remove trailing slashes
    $main_folder =~ s,^\./,,;    # remove ./ at the beginning
    $working_folder = $main_folder ;

    find( \&process, $working_folder );
    }

sub process{
    my $file = $File::Find::name;

    return unless /^Free /;
    # return unless $file =~ /^Free CCNA \_/;
    my $new_file_name;
    # return unless $file =~ /^./;
#                   $leading     $title             $day     $course                       $yt         $ext
#                   Free CCNA | Network Devices | Day 1 | CCNA 200-301 Complete Course [H8W9oMNSuwo].txt
#                   Free CCNA | Configuring IPv6 (Part 1) | Day 31 Lab | CCNA 200-301 Complete Course [BdsIahtrWIA].txt
#                   Free CCNA | Configuring IPv6 (Part 2) | Day 32 Lab | CCNA 200-301 Complete Course [Zfhpd7dl6QI].txt
#                   Free CCNA | Configuring OSPF (3) | Day 28 Lab | CCNA 200-301 Complete Course [Goekjm3bK5o].txt
#                   Free CCNA | Configuring Static Routes | Day 11 Lab 1 | CCNA 200-301 Complete Course [XHxOtIav2k8].txt
#                   Free CCNA | Configuring STP (PVST+) | Day 21 Lab | CCNA 200-301 Complete Course [5rpaeJNig2o].txt
    if ($file =~ m/(Free CCNA) | ([\w\s()+&,\/-]+?) | (Day \d+(?: [\w+\s()]+)?) | ([\w\s-]+?) \[([^\]]+)\](\..+)/) {

    my $leading = $1;
    my $title = $2;
    my $day = $3;
    my $course = $4;
    my $yt = $5;
    my $extension = $6;

    (my $day2 = $day) =~ s/(\d+)/sprintf('%02d', $1)/ge;
    $new_file_name = $working_folder . "/" . "$leading _ $day2 _ $title _ $course-$yt$extension";
    say "Here the files to rename:\n";
    say "Old file name\n$file\n";
    say "New file name\n$new_file_name\n";
    } else {
      say "file name not found"
    }

    if ( -e $new_file_name ) {
                    warn "$new_file_name already exists; skipping $file\n";
                    next;
                }
    move ( $file, $new_file_name )
                  or die "Can't rename $file to $new_file_name: $!\n";
                # continue;
}

Fuzzing Irssi with Perl Scripts

dev.to #perl

Fuzzing Irssi with Perl Scripts

TL;DR: Breaking tech news from Unnamed Source.

What Happened

📰 Unnamed Source is reporting on this story. This is a tech development worth watching closely.

Why It Matters

This story could have significant implications for the global community following tech trends.

Key Takeaways

Follow GlobalWFeed on Telegram →

🤖 Automatically posted by Global Feed Bot

Building a Lightweight Debugging Agent

Perl on Medium

Building a Lightweight Debugging Agent: Python, Perl, and Awk

My Journey with Devel::ptkdb - Origins

blogs.perl.org

This post is the first in a series that will follow my re-development of the Devel::ptkdb debugger. This post explains the beginnings of my involvement with the Perl Tk debugger.

PWC 373 Task 2: Let's Dance to List Division

dev.to #perl

The task title reminded me of the song Let's Dance to Joy Division. Oddly applicable lyrics for a blog about programming: "But I worked something out last night that changed this little boy's brain, a small piece of advice that took 22 years in the make, and I will break it for you now. Please learn from my mistakes." And who doesn't love a wombat?

Task Description

You are given a list and a non-negative integer, $n. Write a script to divide the given list into $n equal parts. Return -1 if $n is more than the size of the list.

Example 1
Input: @list = ( 1,2,3,4,5), $n = 2
Output: ((1,2,3), (4,5))
  • 5 / 2 = 2 remainder 1. The extra element goes into the first chunk.

Example 2

Input: @list = (1,2,3,4,5,6), $n = 3
Output: ((1,2), (3,4), (5,6))
  • 6 / 3 = 2 remainder 0.

Example 3

Input: @list = (1,2,3), $n = 2
Output: ((1,2), (3))

Example 4

Input: @list = (1,2,3,4,5,6,7,8,9,10), $n = 5
Output: ((1,2), (3,4), (5,6), (7,8), (9,10))

Example 5

Input: @list = (1,2,3), $n = 4
Output: -1

Example 6

Input: @list = (72,57,89,55,36,84,10,95,99,35), $n = 7;
Output: ((72,57), (89,55), (36,84), (10), (95), (99), (35))

Elaboration

There's some simple modulo division here, and then a decision about what to do if it doesn't divide evenly into $n chunks. We could put the remainder into a chunk of its own, ignore the remainder, or we could distribute the leftovers in some way that feels balanced -- here, the specification implies that the bigger divisions should go at the front of the list.

Handling an invalid input (where $n is too big) by returning -1 instead of an array is a code smell. Having a function that returns different types of things is awkward to handle and error-prone. It would be more consistent to either throw an exception, or return an out-of-range value of the same type, such as an empty array or a null reference. But that wanker Kevin with his six months of Javascript experience got promoted to project manager for some reason <cough/>nepotism<cough> and that's the requirement we have.

This task has six examples, and usually we're given five. Is there some significance to this? Example 6 doesn't seem to add any new information beyond what we've already been given. But then we notice that the numbers could be ASCII characters, spelling "H9Y7$T?_c#". I'm pretty sure this is Kevin's password. Watch your back, Kevin.

To the CodeMobile, Robin!

sub listDivision($list, $n)
{
    my $size = @$list;
    return -1 if $n > $size;

    my $chunk = floor($size / $n);
    my $extra = $size % $n;
    my @answer;

    while ( $extra-- ) { push @answer, [ splice(@$list, 0, $chunk + 1) ]; }
    while ( @$list   ) { push @answer, [ splice(@$list, 0, $chunk    ) ]; }
    return \@answer;
}

The input parameters are an array and a number, which forces us to confront the way that Perl passes arguments as a flat list. Here, I've chosen to pass an array reference for $list instead of an array, which accomplishes two things: it removes the flat list problem to make it obvious which parameter is $n, and it's more efficient than passing a copy of the array. I could have also passed the parameters in the other order, but "project manager" Kevin said according to ChatGPT and Claude it had to be in this order, so yeah, that's that then.

Time to be serious. We dispense with the special case of returning -1 (more on that later). Then we calculate the quantities involved, and set up an array for producing the answer, initially empty.

The answer has two segments: a head part where there might be one extra element, and the tail part where the segments are of the calculated chunk size. One while loop ticks off the extra-sized chunks, and the second while loop completes the division.

To grab a group of contiguous elements from a list, the splice function seems like the obvious thing to do. Each splice is surrounded with [] so that the chunks are treated as array references. An alternative would have been to take an array slice, but that would introduce index variables for the range being sliced, which looks and feels more complicated and error-prone.

splice reduces the size of the list every time it's called, so the second while loop can use the size of $list as its condition. However, we are destroying $list as we go, so the calling function needs to be aware that the array it passed in is no longer valid. If it were important to keep the original list, a copy would need to be made either from the caller, or near the beginning of listDivision().

Let's think a moment about how to use this function. When it's called it could return either an array of arrays (references actually), or it could return a scalar -1. Here's how I wanted to write the script to use this function, using -n as a command-line option to get that parameter:

use GetOpt::Long;
my $N = 1;
GetOptions("n:i" => \$N);
my $div = listDivision([@ARGV], $N);
say showAofA($div);

where showAofA() is a function that formats the array of arrays into a parenthesized list of comma-separated lists, as in the examples.

However, $div isn't always a reference; sometimes it's a scalar -1. That throws up an ugly error about trying to use a scalar value as a reference. The way to check what's behind a variable in Perl is to use the ref function. It will give a string identifying the variable type, or, for a scalar, it will give an empty string. In perl, an empty string counts as false. So, to satisfy the requirement, the script needs to test whether ref($div) is empty:

say ( ref($div) ? showAofA($div) : $div );

What I probably should have done is change listDivision so that it consistently returns an array reference, but for the invalid case, throws an error. Variations on try/catch have been available as modules in Perl for decades, but it finally (see what I did there?) became official in version 5.38. That simplifies the usage of the function (if you consider try/catch simpler, which some consider a debatable topic).

try          { say showAofA( listDivision([@ARGV], $N) ); }
catch ( $e ) { say "-1" }

To make the function throw an exception, we only need to change the early return from the function into a die:

sub listDivision($list, $n)
{
    my $size = @$list;
    die "N out of range (must be <= $size)" if $n > $size;
    # [ ... ]

That's cleaner, but it slightly complicates the unit testing, because now we have to test for exceptions. The incantation is:

sub runTest
{
    use Test2::V0;
    use Test2::Tools::Exception;
    # [Test cases that should work
    is( listDivision([1,2,3], 1), [[1,2,3]], "One chunk");
    # [ ... ]
    # Test things that throw exceptions
    like ( dies { listDivision( [1,2,3], 4) }, qr/out of range/);

The dies function returns the exception string that results from trying to execute a code block, and like does a pattern match against the expected exception.

And finally, to tidy up a loose end, here's the showAofA() function.

sub showAofA($ref)
{
    return '('. join(',', map { '('.join(',', $_->@*).')' } $ref->@*) .')';
}

Let's take a bunch of punctuation out of that so that we can see the structure:

return ( join( map { join } ) ref )

$ref is a reference to an array of references; hence, $ref->@* is de-referencing it to yield a list of array references.

Each of those array references is then transformed by map. Inside the map {} block, $_ refers to one of the inner arrays, so we de-reference that ($_->@*) to get a list of numbers, which we will join into a comma-separated string. Wrap that with a pair of parentheses, and out of the map comes the inner lists formatted as needed.

Now each of the inner lists is a string. The outer join inserts commas to make it a list of lists, and finally we wrap the whole thing in parentheses to complete the string.


Note: This method is designed for Linux systems where LD_PRELOAD is available.
AddressSanitizer (ASan) is a powerful tool for detecting memory corruption in C/C++ code. When developing Perl XS modules, you can integrate ASan support directly into your Makefile.PL to make debugging seamless.

Add the 'asan-on-linux' Option



First, use GetOptions to provide a dedicated flag for ASan. This allows users to enable memory sanitization explicitly. We also set up a temporary directory to store ASan's detailed log files.

use Getopt::Long;
use File::Path 'mkpath';

GetOptions('asan-on-linux' => \my $asan_on_linux);

my @ccflags;
my @ldflags;
my $asan_logs_dir = ".tmp/asan_logs";

if ($asan_on_linux) {
    push @ccflags, "-fsanitize=address", "-fno-omit-frame-pointer";
    push @ldflags, "-fsanitize=address";
    
    mkpath $asan_logs_dir unless -d $asan_logs_dir;
}

Automate Library Preloading via Makefile Macros



Since the standard perl binary isn't typically compiled with ASan, we must ensure libasan.so is correctly preloaded before the interpreter starts. By using the macro parameter in WriteMakefile, we can automate this process for make test.

use Config;

WriteMakefile(
    NAME              => 'My::Module',
    CCFLAGS           => "$Config{ccflags} " . join(' ', @ccflags),
    LDDLFLAGS         => "$Config{lddlflags} " . join(' ', @ldflags),
    # ...
    macro => {
        $asan_on_linux ? (
            'override FULLPERL' => qq|LD_PRELOAD=\$\$($Config{cc} -print-file-name=libasan.so) ASAN_OPTIONS="log_path=$asan_logs_dir/asan.log:exitcode=0" $^X|
        ) : (),
    },
);

How to Handle Memory Issues



When ASan is enabled, the behavior depends on the type of memory issue:


  • Memory Corruption: Issues like buffer overflows or use-after-free will cause a Segmentation Fault (Segfault) immediately. When this happens, you must fix the code until all tests pass without crashing.
  • Memory Leaks: Unlike corruption, memory leaks do not cause a crash. To find them, you must check the logs after running your tests.


ASan generates a separate log file for each process. To efficiently find both corruption reports and leaks related to your specific module, use the following Perl one-liner (Replace My::Module with your module's name):

perl -00 -ne 'print "--- File: $ARGV ---\n$_\n" if /My::Module/' .tmp/asan_logs/* > .tmp/asan_summary.log


This command uses Perl's "paragraph mode" (-00) to extract the entire stack trace, allowing you to see exactly where the issue (crash or leak) was triggered in your native code.

Appendix: Platform Compatibility

macOS (Untested Hint)



On macOS, you might try DYLD_INSERT_LIBRARIES instead of LD_PRELOAD. However, System Integrity Protection (SIP) often prevents preloading into system binaries like /usr/bin/perl. You would likely need to use a perl installed via perlbrew or plenv.

Windows (Not Supported)



This mechanism is not applicable to Windows. Windows lacks LD_PRELOAD, and memory sanitization requires a fundamentally different configuration, typically involving a specially compiled perl interpreter.


Author: Yuki Kimoto

Introducing Time::Str

blogs.perl.org

Time::Str is a Perl module for parsing and formatting date/time strings across 20+ standard formats. It has an optional C/XS backend, nanosecond precision, and rejects input it cannot parse unambiguously rather than guessing.

use Time::Str qw(str2time str2date time2str);

my $time = str2time('2024-12-24T15:30:45Z');
# 1735052445

my $str = time2str($time, format => 'RFC2822', offset => 60);
# 'Tue, 24 Dec 2024 16:30:45 +0100'

Standards Compliance

Each format is implemented according to its specification: RFC 3339, RFC 2822, RFC 2616, ISO 8601 (calendar dates), ISO 9075, ITU-T X.680 (ASN.1), RFC 5545.

RFC3339      2024-12-24T15:30:45+01:00
RFC2822      Tue, 24 Dec 2024 15:30:45 +0100
RFC2616      Tue, 24 Dec 2024 15:30:45 GMT
ISO8601      20241224T153045.500+0100
ISO9075      2024-12-24 15:30:45 +01:00
ASN1GT       20241224153045Z
CLF          24/Dec/2024:15:30:45 +0100
RFC5545      20241224T153045Z
ECMAScript   Tue Dec 24 2024 15:30:45 GMT+0100

RFC 2822 allows an optional day name and a comment; the regex accepts both. ISO 8601 calendar dates are supported in both basic and extended formats with optional fractional parts on the least significant component. RFC 2616 requires three date formats (IMF-fixdate, RFC 850, and asctime); all three are accepted.

Optional fields are optional. Constrained fields are validated. Day names, when present, are verified against the actual date.

No Guessing

If Time::Str cannot parse the input unambiguously, it croaks rather than returning a wrong answer.

The 01/02/2024 Problem

Is 01/02/2024 January 2nd or February 1st? It depends on who you ask:

  • Date::Parse assumes American (MM/DD). Documents this as a known bug with no workaround.
  • Date::Parse::Modern assumes European (DD/MM). Swaps day and month if the month exceeds 12.
  • Time::ParseDate assumes American by default. A UK option switches to European. Applies heuristics when values exceed 12.

Time::Str requires numeric dates in year-month-day order. Ambiguous formats are rejected. When the month is written as a name or Roman numeral, the order is flexible because the month is unambiguous:

str2date('2024-12-24',     format => 'DateTime');  # Y-M-D
str2date('24 Dec 2024',    format => 'DateTime');  # named month
str2date('Dec 24th, 2024', format => 'DateTime');  # named month
str2date('24.XII.2024',    format => 'DateTime');  # Roman numeral

str2date('12-24-2024',     format => 'DateTime');  # M-D-Y rejected
str2date('24-12-2024',     format => 'DateTime');  # D-M-Y rejected

Two-Digit Years

01/02/03: is that 2003, 1903, or 2001? Existing modules apply different heuristics, and some produce results that depend on today's date. Time::Str's DateTime parser requires a four-digit year. Formats that inherently use two-digit years (like ASN.1 UTCTime) provide a configurable pivot_year parameter with a documented default.

Timezone Abbreviations

IST could be India Standard Time (+05:30), Israel Standard Time (+02:00), or Irish Standard Time (+01:00).

Time::Str captures abbreviations in tz_abbrev without resolving them. str2time requires a UTC designator or numeric offset to produce a timestamp:

my %d = str2date('24 Dec 2024 15:30:45 IST', format => 'RFC2822');
# tz_abbrev => 'IST' -- you decide what it means

str2time('24 Dec 2024 15:30:45 IST', format => 'RFC2822');
# croaks: "Unable to convert: timestamp string without a UTC 
#          designator or numeric offset"

The DateTime Format

The DateTime format is a permissive parser for real-world dates that does not use heuristics. It accepts 12-hour clocks, ordinal suffixes, day names, Roman numeral months, and RFC 9557 timezone annotations:

str2date('Monday, 24th December 2024 at 3:30 PM UTC+01:00',
       format => 'DateTime');
# (year      => 2024, 
#  month     => 12, 
#  day       => 24, 
#  hour      => 15,   
#  minute    => 30,
#  tz_utc    => 'UTC', 
#  tz_offset => 60)

str2date('2024-12-24T15:30:45+01:00[Europe/Stockholm]',
       format => 'DateTime');
# ..., tz_offset => 60, tz_annotation => '[Europe/Stockholm]'

Every accepted date can be parsed deterministically. Ordinal suffixes must match the day number (24th is valid, 24st is rejected). Day names must match the actual date.

Optional C/XS

Time::Str has two backends. The XS backend (C99) is loaded when a compiler is available; otherwise it falls back to Pure Perl. The TIME_STR_PP environment variable forces the Pure Perl path.

say Time::Str::IMPLEMENTATION;  # "XS" or "PP"

Both backends share the same precompiled regexps from Time::Str::Regexp and produce identical results. The C backend implements token extraction and the time2str formatting engine natively.

Benchmarks

str2time: Parsing Performance

Parsing '2012-12-24T12:30:45.123456789+01:00':

                    Rate DT8601 DT3339 D::Parse T::Str T::Moment
DT::F::ISO8601   20935/s     --   -42%     -81%   -98%     -100%
DT::F::RFC3339   36127/s    73%     --     -68%   -97%      -99%
D::Parse        112320/s   437%   211%       --   -90%      -98%
T::Str         1093307/s  5122%  2926%     873%     --      -80%
Time::Moment   5543754/s 26381% 15245%    4836%   407%        --

With XS, str2time is ~10x faster than Date::Parse and ~30x faster than DateTime::Format::RFC3339. My other module Time::Moment is faster, but it's a purpose-built C library for a single format. Time::Str handles 20+ formats at over 1M parses/s.

Across Time::Str's own formats, named-format parsers (RFC3339, RFC4287, W3C) run at ~1M/s, while the permissive DateTime parser (which handles the full grammar) runs at ~500K/s:

             Rate  DateTime   W3C RFC3339 RFC4287
DateTime  503643/s       --  -50%    -52%    -52%
W3C      1005176/s     100%   --     -5%     -5%
RFC3339  1054837/s     109%    5%      --     -0%
RFC4287  1060112/s     110%    5%      1%      --

time2str: Formatting Performance

time2str is implemented in C with its own format-spec interpreter, independent of strftime and locale. RFC 3339 formatting runs at ~2x the speed of scalar gmtime:

                 Rate T::Moment    gmtime   RFC2822   RFC3339
T::Moment   2161089/s        --      -29%      -61%      -68%
gmtime      3060278/s       42%        --      -44%      -54%
RFC2822     5477189/s      153%       79%        --      -18%
RFC3339     6719250/s      211%      120%       23%        --

Light on Dependencies

Requires Perl 5.10.1 or later. Runtime dependencies are Carp and Exporter, both core modules. The XS backend needs a C99 compiler at build time. Without a compiler, the Pure Perl fallback has zero non-core dependencies.

Time::HiRes

str2time returns a floating-point Unix timestamp, the same representation Time::HiRes::time() uses. Fractional seconds are preserved up to nanosecond resolution:

use Time::HiRes qw(time);
use Time::Str   qw(str2time time2str);

# Round-trip a high-resolution timestamp
my $now  = time;             # e.g., 1735052445.123456
my $str  = time2str($now);   # '2024-12-24T15:30:45.123456Z'
my $back = str2time($str);   # 1735052445.123456

# Full nanosecond control with the nanosecond parameter
my ($sec, $us) = Time::HiRes::gettimeofday();
my $str = time2str($sec, nanosecond => $us * 1000, precision => 6);

Parsing truncates; formatting rounds. The nanosecond parameter bypasses rounding for exact output.

DateTime and Time::Moment

str2date returns parsed components that maps directly to Time::Moment and DateTime constructors:

use Time::Str qw(str2date);
use DateTime;
use Time::Moment;

my %d = str2date('2024-12-24T15:30:45.500+01:00');

# Feed directly into Time::Moment
my $tm = Time::Moment->new(
  year       => $d{year},
  month      => $d{month},
  day        => $d{day},
  hour       => $d{hour},
  minute     => $d{minute},
  second     => $d{second},
  nanosecond => $d{nanosecond},
  offset     => $d{tz_offset},
);

# Feed directly into DateTime
my $dt = DateTime->new(
  year       => $d{year},
  month      => $d{month},
  day        => $d{day},
  hour       => $d{hour},
  minute     => $d{minute},
  second     => $d{second},
  nanosecond => $d{nanosecond},
  time_zone  =>
    DateTime::TimeZone->offset_as_string($d{tz_offset} * 60)
);

This decouples parsing from representation. Time::Moment's constructor maps 1:1 with str2date's output: offset takes minutes and nanosecond takes the same integer range.

Tools for Custom Parsers

Time::Str also exposes its building blocks for writing custom parsers.

Time::Str::Regexp

Each format's precompiled regex is individually exportable, with named captures:

use Time::Str::Regexp qw($RFC3339_Rx $RFC2822_Rx $DateTime_Rx);

if ($line =~ $RFC3339_Rx) {
  my $year   = $+{year};
  my $month  = $+{month};
  my $offset = $+{tz_offset};
  # ...
}

All regexes are anchored and use consistent named captures: year, month, day, hour, minute, second, fraction, tz_offset, tz_utc, tz_abbrev, tz_annotation, day_name, meridiem.

Time::Str::Token

Token parsers convert the raw captured strings into semantic values:

use Time::Str::Token qw(parse_month parse_day parse_tz_offset);

parse_month('Dec');        # 12
parse_month('XII');        # 12
parse_month('December');   # 12

parse_day('24th');         # 24
parse_day('1st');          # 1

parse_tz_offset('+05:30'); # 330 (minutes)
parse_tz_offset('0530');   # 330

Time::Str::Calendar

Calendar utilities for validation and conversion:

use Time::Str::Calendar qw( leap_year 
                            valid_ymd
                            ymd_to_dow );

leap_year(2024);            # true
valid_ymd(2024, 2, 29);     # true
valid_ymd(2023, 2, 29);     # false
ymd_to_dow(2024, 12, 24);   # 2 (Tuesday; 1=Mon, 7=Sun)

These three modules can be combined to build parsers for other date formats, using the same validation and calendar logic as the built-in formats.

What's Next: Native C Parsers

Currently, the XS backend uses Perl's regex engine for the initial string match, then switches to C for token extraction, validation, and epoch calculation. The next step is moving the parsers themselves into native C, eliminating the regex overhead entirely and closing the gap with Time::Moment's parsing speed.


Time::Str is available on CPAN and GitHub.

cpanm Time::Str

This week in PSC (224) | 2026-05-11

blogs.perl.org

All three of us attended further final release preparation. Issue triage continued; a number of small issues came in late, and we merged some of them. We also reverted a late small fix that we had merged recently which turned out to cause problems. Overall we once again left the meeting without open release blockers.

[P5P posting of this summary]

Weekly Challenge: Joining and splitting lists

dev.to #perl

Weekly Challenge 373

Each week Mohammad S. Anwar sends out The Weekly Challenge, a chance for all of us to come up with solutions to two weekly tasks. My solutions are written in Python first, and then converted to Perl. Unless otherwise stated, Copilot (and other AI tools) have NOT been used to generate the solution. It's a great way for us all to practice some coding.

Challenge, My solutions

Task 1: Equal List

Task

You are given two arrays of strings.

Write a script to return true if the two given array represent the same strings otherwise false.

My solution

For input from the command line, I take a string with items concatenated by commas to generate the two lists. This seems to the easiest way to handle this, allowing for empty items as per the fourth example.

def main():
    result = equal_list(sys.argv[1].split(","), sys.argv[2].split(","))
    print("true" if result else "false")

This function is a one liner. I join the items in each list and then compare them to see if they are the same.

def equal_list(arr1: list[str], arr2: list[str]) -> bool:
    return ''.join(arr1) == ''.join(arr2)

The Perl solution has the same functionality.

sub main ( $str1, $str2 ) {
    my @arr1 = split /,/, $str1;
    my @arr2 = split /,/, $str2;

    say join( "", @arr1 ) eq join( "", @arr2 ) ? "true" : "false";
}

Examples

$ ./ch-1.py "a,bc" "ab,c"
false

$ ./ch-1.py "a,bc" "ab,c"
true

$ ./ch-1.py "a,b,c" "a,bc"
true

$ ./ch-1.py "a,bc" "a,c,b"
false

$ ./ch-1.py "ab,c," ",a,bc"
true

$ ./ch-1.py "p,e,r,l" "perl"
true

Task 2: List Division

Task

You are given a list and a non-negative integer.

Write a script to divide the given list into given non-negative integer equal parts. Return -1 if the integer is more than the size of the list.

My solution

For this task, I use the divmod function to calculate the number of items from the list each part needs, and the number of parts that require an extra item. These are stored as the variables item_length and extra_first.

I also have a variable called pos to store the position of the first letter. I have a loop i that runs n times. If i is less than extra_first, I take item_length + 1 items, otherwise item_length times, adding to pos as I go.

def list_division(input_list: list[int], n: int) -> list[list[int]] | None:
    result = []
    pos = 0

    if len(input_list) < n:
        return None

    item_length, extra_first = divmod(len(input_list), n)

    for i in range(n):
        this_length = item_length + 1 if i < extra_first else item_length
        result.append(input_list[pos:pos+this_length])
        pos += this_length

    return result

The Perl solution is similar. It doesn't have the pos variable, as it uses the splice function to remove the necessary number of items from the array. This function returns the items removed.

sub main (@list) {
    # The last value is the 'n' value
    my $n = pop(@list);
    my $length = scalar(@list);

    my @result = ();

    if ( $length < $n ) {
        say -1;
        return;
    }

    my $item_length = int( $length / $n );
    my $extra_first = $length % $n;

    foreach my $i ( 1 .. $n ) {
        my $this_length = $i <= $extra_first ? $item_length + 1 : $item_length;
        push @result, "(" . join( ",", splice( @list, 0, $this_length ) ) . ")";
    }

    say "(" . join( ", ", @result ) . ")";
}

Examples

$ ./ch-2.py 1 2 3 4 5 2
((1,2,3), (4,5))

$ ./ch-2.py 1 2 3 4 5 6 3
((1,2), (3,4), (5,6))

$ ./ch-2.py 1 2 3 2
((1,2), (3))

$ ./ch-2.py 1 2 3 4 5 6 7 8 9 10 5
((1,2), (3,4), (5,6), (7,8), (9,10))

$ ./ch-2.py 1 2 3 4
-1

$ ./ch-2.py 72 57 89 55 36 84 10 95 99 35 7 
((72,57), (89,55), (36,84), (10), (95), (99), (35))

When you have lots and lots of qcow2

Updates for great CPAN modules released last week. A module is considered great if its favorites count is greater or equal than 12.

  1. App::cpm - a fast CPAN module installer
    • Version: v1.1.0 on 2026-05-07, with 178 votes
    • Previous CPAN version: v1.0.4 was released the same day
    • Author: SKAJI
  2. App::Netdisco - An open source web-based network management tool.
    • Version: 2.098004 on 2026-05-08, with 862 votes
    • Previous CPAN version: 2.098003 was released 3 days before
    • Author: OLIVER
  3. App::perlimports - Make implicit imports explicit
    • Version: 0.000060 on 2026-05-06, with 24 votes
    • Previous CPAN version: 0.000059 was released 12 days before
    • Author: OALDERS
  4. App::rdapper - a command-line RDAP client.
    • Version: 1.25 on 2026-05-07, with 21 votes
    • Previous CPAN version: 1.24 was released 2 months, 15 days before
    • Author: GBROWN
  5. Attean - A Semantic Web Framework
    • Version: 0.037 on 2026-05-04, with 19 votes
    • Previous CPAN version: 0.036_01 was released the same day
    • Author: GWILLIAMS
  6. CGI - Handle Common Gateway Interface requests and responses
    • Version: 4.72 on 2026-05-05, with 48 votes
    • Previous CPAN version: 4.71 was released 7 months, 4 days before
    • Author: LEEJO
  7. CPANSA::DB - the CPAN Security Advisory data as a Perl data structure, mostly for CPAN::Audit
    • Version: 20260503.001 on 2026-05-04, with 25 votes
    • Previous CPAN version: 20260430.001 was released 3 days before
    • Author: BRIANDFOY
  8. DBIx::Lite - Chained and minimal ORM
    • Version: 0.38 on 2026-05-05, with 30 votes
    • Previous CPAN version: 0.37 was released the same day
    • Author: AAR
  9. Gazelle - a Preforked Plack Handler for performance freaks
    • Version: 0.50 on 2026-05-07, with 26 votes
    • Previous CPAN version: 0.49 was released 6 years, 5 months before
    • Author: KAZEBURO
  10. HTTP::Tinyish - HTTP::Tiny compatible HTTP client wrappers
    • Version: 0.20 on 2026-05-04, with 16 votes
    • Previous CPAN version: 0.19 was released 2 years, 1 month, 26 days before
    • Author: MIYAGAWA
  11. lazy - Lazily install missing Perl modules
    • Version: 1.000002 on 2026-05-09, with 16 votes
    • Previous CPAN version: 1.000001 was released the same day
    • Author: OALDERS
  12. Mojolicious - Real-time web framework
    • Version: 9.45 on 2026-05-05, with 512 votes
    • Previous CPAN version: 9.44 was released the same day
    • Author: SRI
  13. Plack - Perl Superglue for Web frameworks and Web Servers (PSGI toolkit)
    • Version: 1.0054 on 2026-05-05, with 496 votes
    • Previous CPAN version: 1.0053 was released 6 days before
    • Author: MIYAGAWA
  14. Rose::DB::Object - Extensible, high performance object-relational mapper (ORM).
    • Version: 0.823 on 2026-05-04, with 22 votes
    • Previous CPAN version: 0.822 was released 1 year, 3 months, 29 days before
    • Author: JSIRACUSA
  15. Sidef - The Sidef Programming Language - A modern, high-level programming language
    • Version: 26.05 on 2026-05-05, with 123 votes
    • Previous CPAN version: 26.04 was released 1 month, 4 days before
    • Author: TRIZEN
  16. SPVM - The SPVM Language
    • Version: 0.990169 on 2026-05-08, with 36 votes
    • Previous CPAN version: 0.990168 was released 11 days before
    • Author: KIMOTO
  17. Starlet - a simple, high-performance PSGI/Plack HTTP server
    • Version: 0.32 on 2026-05-06, with 18 votes
    • Previous CPAN version: 0.31 was released 9 years, 4 months, 25 days before
    • Author: KAZUHO
  18. Sys::Virt - libvirt Perl API
    • Version: v12.3.0 on 2026-05-06, with 17 votes
    • Previous CPAN version: v12.2.0 was released 1 month, 4 days before
    • Author: DANBERR
  19. Test::MockModule - Override subroutines in a module for unit testing
    • Version: v0.185.0 on 2026-05-07, with 18 votes
    • Previous CPAN version: v0.184.0 was released 1 day before
    • Author: GFRANKS
  20. Test::Most - Most commonly needed test functions and features.
    • Version: 0.42 on 2026-05-07, with 37 votes
    • Previous CPAN version: 0.41 was released 6 days before
    • Author: DCANTRELL
  21. Win32 - Interfaces to some Win32 API Functions
    • Version: 0.60 on 2026-05-05, with 13 votes
    • Previous CPAN version: 0.59_02 was released 1 day before
    • Author: JDB

One of my modules report 99.999% coverage due to a single // usage which I'm trying to understand. Simplifying things, consider this program:

sub scalar_rhs
{
    my $a;
    my $b = 1;

    $a // $b
}

sub hash_rhs
{
    my $a;
    my %b = ( x => 1 );

    $a // $b{x}
}

die 'scalar failed' unless &scalar_rhs;
die 'hash failed' unless &hash_rhs;

Running:

perl -MDevel::Cover test.pl
cover -report text

Generates:

line  err      %      l  !l&&r !l&&!r   expr
----- --- ------ ------ ------ ------   ----
6     ***     33      0      1      0   $a // $b
15    ***     33      0      0      1   $a // $b{'x'}

How come $b{x} is seen as false by Devel::Cover? How can I make this pass as !l&&r?

Açık kaynak dünyasında bazen en masum görünen modüller bile ciddi güvenlik riskleri taşıyabiliyor. Dün yayınlanan CVE-2026–5081, tam da bu…

Answer

It’s kinda complicated. i3 exposes a scratchpad_state on every node, but it is not relevant for the node you initially check. The window node of the application you are targetting. Today we are scratching an itch.

When I saw this question posted on Reddit I first thought: let’s look at the data. My Workspace on Demand daemon has an IPC event debugger. So I fired it up and went looking at the data, my debugger told me:

I was working on some code that creates a reference to a substring call, and then passes that. I assumed this would be a SCALAR ref, since it seems like it would just be a SCALAR with a string in it? Why does this ref return LVALUE?

use strict;
use warnings;
use feature 'say';

my $str = "hello";
my $lv = \substr($str, 1, 2);
say ref($lv);          # LVALUE

I did a little dig in perlguts and I do see the LVALUE SVTYPE, so I assume this is intended behavior.

Updates for great CPAN modules released last week. A module is considered great if its favorites count is greater or equal than 12.

  1. App::ClusterSSH - Cluster administration tool
    • Version: 4.19 on 2026-04-28, with 980 votes
    • Previous CPAN version: 4.18_09 was released 1 month, 7 days before
    • Author: DUNCS
  2. App::cpm - a fast CPAN module installer
    • Version: v1.0.3 on 2026-05-02, with 178 votes
    • Previous CPAN version: v1.0.2 was released the same day
    • Author: SKAJI
  3. App::Music::ChordPro - A lyrics and chords formatting program
    • Version: v6.101.0 on 2026-04-30, with 469 votes
    • Previous CPAN version: v6.100.0 was released 8 days before
    • Author: JV
  4. Cache::FastMmap - Uses an mmap'ed file to act as a shared memory interprocess cache
    • Version: 1.61 on 2026-04-30, with 25 votes
    • Previous CPAN version: 1.60 was released 10 months, 12 days before
    • Author: ROBM
  5. CPANSA::DB - the CPAN Security Advisory data as a Perl data structure, mostly for CPAN::Audit
    • Version: 20260430.001 on 2026-04-30, with 25 votes
    • Previous CPAN version: 20260426.001 was released the same day
    • Author: BRIANDFOY
  6. DBD::Pg - DBI PostgreSQL interface
    • Version: 3.20.2 on 2026-05-02, with 103 votes
    • Previous CPAN version: 3.20.1 was released 2 days before
    • Author: TURNSTEP
  7. Encode - character encodings in Perl
    • Version: 3.24 on 2026-04-29, with 65 votes
    • Previous CPAN version: 3.23 was released 2 days before
    • Author: DANKOGAI
  8. MetaCPAN::Client - A comprehensive, DWIM-featured client to the MetaCPAN API
    • Version: 2.043000 on 2026-04-29, with 29 votes
    • Previous CPAN version: 2.042000 was released 3 days before
    • Author: MICKEY
  9. Plack - Perl Superglue for Web frameworks and Web Servers (PSGI toolkit)
    • Version: 1.0053 on 2026-04-28, with 496 votes
    • Previous CPAN version: 1.0052 was released 1 day before
    • Author: MIYAGAWA
  10. PPI - Parse, Analyze and Manipulate Perl (without perl)
    • Version: 1.291 on 2026-04-25, with 64 votes
    • Previous CPAN version: 1.290 was released the same day
    • Author: MITHALDU
  11. SPVM - The SPVM Language
    • Version: 0.990168 on 2026-04-27, with 36 votes
    • Previous CPAN version: 0.990167 was released 2 days before
    • Author: KIMOTO
  12. Starman - High-performance preforking PSGI/Plack web server
    • Version: 0.4018 on 2026-04-27, with 297 votes
    • Previous CPAN version: 0.4017 was released 2 years, 7 months, 13 days before
    • Author: MIYAGAWA
  13. Test::MockModule - Override subroutines in a module for unit testing
    • Version: v0.183.0 on 2026-05-01, with 18 votes
    • Previous CPAN version: v0.182.0 was released the same day
    • Author: GFRANKS
  14. Test::Most - Most commonly needed test functions and features.
    • Version: 0.41 on 2026-04-30, with 37 votes
    • Previous CPAN version: 0.40 was released the same day
    • Author: DCANTRELL
  15. Test2::Harness - A new and improved test harness with better Test2 integration.
    • Version: 1.000172 on 2026-04-29, with 28 votes
    • Previous CPAN version: 1.000171 was released 5 days before
    • Author: EXODIST
  16. Text::CSV_XS - Comma-Separated Values manipulation routines
    • Version: 1.62 on 2026-04-29, with 104 votes
    • Previous CPAN version: 1.61 was released 9 months, 2 days before
    • Author: HMBRAND
  17. YAML::LibYAML - Perl YAML Serialization using XS and libyaml
    • Version: v0.906.0 on 2026-04-26, with 60 votes
    • Previous CPAN version: v0.906.0 was released the same day
    • Author: TINITA

TPRC Announces Post Conference Class

Perl Foundation News

TPRC is proud to announce the post-conference class on Monday, June 29. Steven Lembark is presenting: Teaching AI New Tricks: Perly MCP’s for Claude. The class will be from 9am to 4pm in the Palmetto Room at the Conference Hotel. SHORT DESCRIPTION: MCP definitions are not your mother’s API call. They are natural language descriptions meant for the tool to process and integrate into its own workflow. With proper description, the MCP’s are simple to use and can be daisy-chained to produce quite flexible results. Claude’s different models — Haiku, Sonnet, Opus — offer different options for cost, speed, and depth and require different definitions. In the spirit of the Perl Tester’s Notebook, this class covers a very basic tool then expands it for general use, one step at a time, looking at the necessary changes to Perl and the MCP. The result is a lightweight, fast interface that handles a common task easily and can be incorporated with other tools. For a more complete class description, please visit: https://tprc.us/tprc-2026-gsp/class/ Tickets for the class are $120 and are available at: https://perlfoundation.fcsuite.com/erp/donate/list/event?event_date_id=1002

Toronto Perl Mongers / March 2026 Talk

The Perl and Raku Conference YouTube channel

From April 23-26, 2026, the invite-only Perl Toolchain Summit (PTS) brought together about 30 of the ecosystem’s most active maintainers — including four first-timers — in Vienna, Austria for four days of uninterrupted deep-dive collaboration in pair-programming sessions, consensus discussions, and critical infrastructure work. Attendees tackled security tooling and infrastructure, modernization and redesign proposals, several CI and test harness improvements, Perl core optimizations, and metadata/spec updates.

Thanks to all the sponsors’ support (financial, in-kind, and community), this year’s Summit was a success. It produced multiple module releases, consensus on future smoke-testing and CPAN Testers architecture, and a new CPANSec advisory feed that will allow developers to quickly assess any Perl project’s security using either CLI tools or the MetaCPAN website itself. Those advancements benefit all organizations relying on Perl directly or indirectly.

PTS 2026 Key Results & Deliverables

Security

CPANSec took it to another level, getting faster at discovering vulnerabilities (in modules, infrastructure and core) and improving its process:

  • Vulnerability triage;
  • CNA improvements;
  • Meta V3 is moving forward;
  • Deprecated Module::Signature, considered “security theater”.

Testing and Quality Assurance

Testing and QA work included:

  • On the road to Devel::Cover 2.00;
  • Several improvements made to Test::Smoke, with 3 releases: removal of dual PerlIO/stdio testing, making install more robust (and portable);
  • Test::Smoke backend full rewrite to ensure sustainability with new features and better performance;
  • The Test2 family of modules, including the new web user interface, was greatly improved, with many issues fixed and new features implemented;
  • Syncing from backpan.perl.org to fill in CPAN Testers’ backpan;
  • New MCP server mcp.cpantesters.org to browse CPAN Testers reports from your preferred LLM CLI.

Supply Chain and Other Modules

Many CPAN authors and maintainers worked on:

PAUSE

Very hacktive PAUSE table:

  • Implemented new API token access;
  • Security fixes (“rand rand rand rand”, “ABRA time” and “META symlinks”);
  • New dockerized PAUSE;
  • Various pentesting (e.g. reviewing YAML parser);
  • Ongoing work on OAuth/OIDC;
  • Several Pull Requests merged.

Funding

Recent years brought the topic of funding to the front of the stage. In particular to ensure the sustainability of Perl maintenance funds, accelerate some initiatives (e.g. CPAN Security efforts) and finance community events (like this one!).

A lot of things happened on this front during the Perl Toolchain Summit:

  • A strong effort towards funding security work;
  • General discussions about funding of the community.

Group discussions

The Perl Toolchain Summit also provides a lot of opportunity for interaction. Whether they’re corridor discussions, small talk to get to know each other and build trust, discussions around a drink or group discussions (that led in the past to “consensus” or “amendment” papers), it all ends up strengthening the Perl toolchain.

During this PTS in particular, there were a lot of group discussions, probably helped by having a dedicated meeting room.

On the topic of Toolchain

  • META V3
  • CPAN clients

On the topic of AI

  • AI Policies Materials
  • AI Policies Governance
  • Share your AI tooling and tips!

On the topic of Security

  • CRA presentation and Q&A

On the topic of Perl core

  • Perl Ongoing and future features
  • Perl core class/roles implementation
  • Configure
  • UTF-8
  • Plan for Perl Platforms

Podcasts

As in 2025, PTS 2026 was an opportunity to record new episodes for The Underbar. There were over five hours of conversations recorded, about:

  • Configure
  • Vienna.pm
  • PPI
  • the Perl Steering Council
  • Karl Williamson

Why Sponsor Support Matters

Bringing 30–35 experts under one roof enabled unprecedented collaboration with real-time problem solving, saving months of remote coordination and alignment. That kind of accelerated development and knowledge transfer not only brings the community together but fuels the contributors of critical open source projects for the rest of the year so they can renew their shared goals and work in the same direction. Having four first-time attendees gaining direct mentorship is also fundamental to seed future contributions and expand the volunteer base, ensuring the longevity of the Perl ecosystem and toolchain.

The continued support of our sponsors ensures that the Perl Toolchain Summit remains a catalyst for Perl sustainability — translating sponsor investment into tangible improvements in performance, security, and ecosystem features and coherence. We look forward to partnering again to power the next wave of innovation in Perl’s toolchain.

Sponsors

Last week the Perl Toolchain Summit took place in Vienna (the second time, we also hosted the event in 2010). I participated mostly in the role of local orga, helping the international team finding a venue and a hotel, a place for the social event etc.

For the venue, Michael suggested Hauswirtschaft, where Geizhals sometimes hold meetings and events. This turned out to be an excellent choice. Not only did we get the rooms at a reasonable price (at least when compared to some of the more mainstream hotels), but the rooms and the whole venue were very nice and extremely accommodating: We were served vegetarian lunch each day, could bring our own snacks and drinks (the delicious apple juice Hauswirtschaft provided was not enough for some of the very specific Cola needs of some attendees; luckily there's a supermarket right across) and have a Pizza-and-Chartreuse-Party on Saturday (which I have been told ended quite late). Transporting 16 boxes of pizza on my bike trailer was also fun!

I had little time for technical contributions, as I was busy organizing dinners, answering peoples questions about Vienna and generally having a nice time. But I managed to code up a local development environment for PAUSE based on docker compose. Andreas merged it on Sunday, so if you want to have a local PAUSE (for testing and developing new features), you can now do so via a simple docker compose up pause paused. Detailed instructions can be found here and I would appreciate it if people give it a try and report back any problems they have. Having a working local dev setup is IMO crucial for getting meaningful contributions.

Together with Michael I was interviewed by Philippe for his podcast. We talked about the history and future of Vienna.pm, Geizhals, Koha and some other topics. The interview and the whole event motivated me to keep Vienna.pm going and maybe try to host a Perl-and-related-tech-events (again) in the future. We'll see...

To summarize, I really enjoyed the event, hanging around with Perl people & talking about basically everything. It was a nice reminder that this community is exactly my kind of crazy! Looking forward to the next PTS or similar event!

And no post about the PTS is complete without thanking the sponsors (is it ok to thank yourself, as I'm involved with two of the sponsors (Vienna.pm and HSK3)? I say it is...)

Updates for great CPAN modules released last week. A module is considered great if its favorites count is greater or equal than 12.

  1. App::Music::ChordPro - A lyrics and chords formatting program
    • Version: v6.100.0 on 2026-04-21, with 468 votes
    • Previous CPAN version: v6.090.1 was released 3 months, 18 days before
    • Author: JV
  2. App::Netdisco - An open source web-based network management tool.
    • Version: 2.098002 on 2026-04-20, with 864 votes
    • Previous CPAN version: 2.098001 was released 3 days before
    • Author: OLIVER
  3. App::perlimports - Make implicit imports explicit
    • Version: 0.000059 on 2026-04-24, with 24 votes
    • Previous CPAN version: 0.000058 was released 5 months, 26 days before
    • Author: OALDERS
  4. Bitcoin::Crypto - Bitcoin cryptography in Perl
    • Version: 4.005 on 2026-04-23, with 18 votes
    • Previous CPAN version: 4.004 was released 1 month, 5 days before
    • Author: BRTASTIC
  5. CPANSA::DB - the CPAN Security Advisory data as a Perl data structure, mostly for CPAN::Audit
    • Version: 20260419.002 on 2026-04-19, with 25 votes
    • Previous CPAN version: 20260412.001 was released 7 days before
    • Author: BRIANDFOY
  6. CryptX - Cryptographic toolkit
    • Version: 0.088 on 2026-04-23, with 53 votes
    • Previous CPAN version: 0.087_008 was released the same day
    • Author: MIK
  7. DateTime::TimeZone - Time zone object base class and factory
    • Version: 2.68 on 2026-04-23, with 22 votes
    • Previous CPAN version: 2.67 was released 1 month, 17 days before
    • Author: DROLSKY
  8. DBIx::Class::InflateColumn::Serializer - Inflators to serialize data structures for DBIx::Class
    • Version: 0.10 on 2026-04-19, with 13 votes
    • Previous CPAN version: 0.09 was released 9 years, 3 months, 4 days before
    • Author: MRUIZ
  9. Encode - character encodings in Perl
    • Version: 3.22 on 2026-04-25, with 65 votes
    • Previous CPAN version: 3.21 was released 2 years, 1 month, 28 days before
    • Author: DANKOGAI
  10. Google::Ads::GoogleAds::Client - Google Ads API Client Library for Perl
    • Version: v32.0.0 on 2026-04-22, with 20 votes
    • Previous CPAN version: v31.1.0 was released 27 days before
    • Author: CHEVALIER
  11. Log::Any - Bringing loggers and listeners together
    • Version: 1.720 on 2026-04-25, with 69 votes
    • Previous CPAN version: 1.719 was released 1 month, 8 days before
    • Author: PREACTION
  12. MetaCPAN::Client - A comprehensive, DWIM-featured client to the MetaCPAN API
    • Version: 2.041000 on 2026-04-25, with 29 votes
    • Previous CPAN version: 2.040000 was released 1 month, 16 days before
    • Author: MICKEY
  13. Module::CoreList - what modules shipped with versions of perl
    • Version: 5.20260420 on 2026-04-20, with 45 votes
    • Previous CPAN version: 5.20260330 was released 21 days before
    • Author: BINGOS
  14. PPI - Parse, Analyze and Manipulate Perl (without perl)
    • Version: 1.290 on 2026-04-25, with 64 votes
    • Previous CPAN version: 1.289 was released the same day
    • Author: MITHALDU
  15. SPVM - The SPVM Language
    • Version: 0.990167 on 2026-04-24, with 36 votes
    • Previous CPAN version: 0.990166 was released the same day
    • Author: KIMOTO
  16. Test2::Harness - A new and improved test harness with better Test2 integration.
    • Version: 1.000171 on 2026-04-23, with 28 votes
    • Previous CPAN version: 1.000170 was released 13 days before
    • Author: EXODIST
  17. YAML::LibYAML - Perl YAML Serialization using XS and libyaml
    • Version: v0.905.0 on 2026-04-24, with 60 votes
    • Previous CPAN version: v0.905.0 was released 1 day before
    • Author: TINITA
  18. YAML::PP - YAML 1.2 Processor
    • Version: v0.40.0 on 2026-04-24, with 27 votes
    • Previous CPAN version: v0.40.0 was released 1 day before
    • Author: TINITA
  19. YAML::Syck - Fast, lightweight YAML loader and dumper
    • Version: 1.45 on 2026-04-23, with 18 votes
    • Previous CPAN version: 1.44 was released 20 days before
    • Author: TODDR

cpan.org email forwarding has been shut down

The Perl NOC

We know this will disappoint many of you, but it was not feasible to keep it running anymore with a reasonable quality.

Several factors led to the decision:

  • Communication has moved on. 25 years ago it was important to provide a consistent way for users to contact CPAN module authors.  Today people use rt.cpan.org, forums, and other channels..

  • Over 99% of mail was spam.  Even two layers of spam filtering let some through, hurting deliverability for our other outbound mail.

  • Modern email requires ARC, DKIM, DMARC, and SPF. Providing these correctly on a forwarding service is hard, so legitimate mail often fails to be delivered.

  • We approached several email providers, but were unable to find one to host the service.

  • The number of active users was small compared to the number of CPAN authors. During a recent extended, unannounced outage, we received only two inquiries.


We will work with the cpan-security team so they keep a way to reach authors.


Bounces will soon report that the MX cpan.org-email-is-gone-use-http-rt.cpan.org cannot be found as a breadcrumb pointing toward alternatives.


cpan.org email was one of the first services we ran for the Perl community; over the years we've added others, some for the wider internet. The perl.org mailing lists have been running for 28 years and continue to operate. We also still help run PAUSE and the CPAN archive system. rt.cpan.org remains available, thanks to The Perl Foundation and Request Tracker.


For most of its 25 years, cpan.org email was widely used, and running it was a pleasure. The last seven or eight became mostly spam fights and deliverability work — a big part of why we're stopping now.


Please don't ask us to reconsider. We recognize this change will affect some users more than others.  We wrestled with this for a long time and are confident that it is the right call. 


Sincerely,


The perl noc volunteers


TL;DR

This is a rant, a developer war story of how to use docker to work around a problem that shouldn’t exist in the first place. Configure your PHP project with a different, lower version, of PHP than you are using yourself. Read how I spent an evening fighting PHP.

The bare minimum

Can someone in PHP land please tell me why composer is unable to create a project on PHP version 8.2 when I’m running PHP version 8.4? I’m creating a PHP app that needs to run on bookworm, aka, Debian 12, which ships PHP 8.2.

Perl · Objective-C · Visual Basic · CoffeeScript · Ruby

TPRC Talk Submission Deadline in 2 days!

Perl Foundation News

There are only 2 days left to submit a talk for TPRC! The cutoff is April 21. If you have an idea for a talk, it is definitely time to get it submitted. We need a wide variety of speakers and topics, so give it a try! Go to https://tprc.us/ to make your submission.

Updates for great CPAN modules released last week. A module is considered great if its favorites count is greater or equal than 12.

  1. App::Netdisco - An open source web-based network management tool.
    • Version: 2.098001 on 2026-04-16, with 859 votes
    • Previous CPAN version: 2.098000 was released the same day
    • Author: OLIVER
  2. Authen::Passphrase - hashed passwords/passphrases as objects
    • Version: 0.009 on 2026-04-15, with 14 votes
    • Previous CPAN version: 0.008 was released 14 years, 2 months, 11 days before
    • Author: LEONT
  3. Convert::Pheno - A module to interconvert common data models for phenotypic data
    • Version: 0.31 on 2026-04-17, with 15 votes
    • Previous CPAN version: 0.30 was released 2 days before
    • Author: MRUEDA
  4. CPANSA::DB - the CPAN Security Advisory data as a Perl data structure, mostly for CPAN::Audit
    • Version: 20260412.001 on 2026-04-12, with 25 votes
    • Previous CPAN version: 20260405.001 was released 7 days before
    • Author: BRIANDFOY
  5. Finance::Quote - Get stock and mutual fund quotes from various exchanges
    • Version: 1.69 on 2026-04-18, with 149 votes
    • Previous CPAN version: 1.68_02 was released 1 month, 5 days before
    • Author: BPSCHUCK
  6. Imager - Perl extension for Generating 24 bit Images
    • Version: 1.030 on 2026-04-13, with 68 votes
    • Previous CPAN version: 1.029 was released 6 months, 7 days before
    • Author: TONYC
  7. JSON::Schema::Modern - Validate data against a schema using a JSON Schema
    • Version: 0.638 on 2026-04-18, with 16 votes
    • Previous CPAN version: 0.637 was released 10 days before
    • Author: ETHER
  8. SPVM - The SPVM Language
    • Version: 0.990162 on 2026-04-18, with 36 votes
    • Previous CPAN version: 0.990161 was released the same day
    • Author: KIMOTO
  9. version - Structured version objects
    • Version: 0.9934 on 2026-04-12, with 22 votes
    • Previous CPAN version: 0.9933 was released 1 year, 7 months, 17 days before
    • Author: LEONT