Shortcuts: s show h hide n next p prev

Toronto Perl Mongers / Stephen Zimmerman

The Perl and Raku Conference YouTube channel

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.

(dc) 17 great CPAN modules released last week

r/perl
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

RMG: note version.pm CUSTOMIZED special status

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.

Update .mailmap for Eric Herman

Perl commits on GitHub
Update .mailmap for Eric Herman
expand the dual-life synchronisation section

Co-authored-by: Eric Herman <eric@freesa.org>


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))

My Journey with Devel::ptkdb - Origins

dev.to #perl

This post explains the beginnings of my involvement with the Perl Tk debugger.

Origins

There are a number of well-known schisms in the world of computing:

  • Emacs vs Vi
  • Tabs vs Spaces
  • Perl vs Python
  • CLI vs GUI
  • Windows vs everything else

I’d like to add another one: Debuggers vs Print Statements.

I come down on the side of debuggers. I’m a visual person and I’m impatient. I don’t like to wait for results. I like to get in there, crawl around, change things, see what’s going on.

I first started using debuggers on Digital Equipment Corporation VAX machines running VMS. I moved to Unix and used gdb in Emacs and then found ddd. Any time I started with a new language, one of the first things I reached for was a visual debugger.

When I started using Perl in the waning years of the last century, I conducted my usual search and found Devel::ptkdb. It served me well for all the years in which my primary language was Perl. Now, it did have its quirks. The variable display was less than ideal; there was no way to sort the variables in the vertically oriented display list. If you happened to have an array displayed before other variables, then as the array expanded, the other variables would scroll beyond the bottom of the window. The map of loaded modules sometimes did not properly find the related code. The map’s sort order was alphabetical and did not bring the most common modules, nor the local modules, to the top of the list where it would be more convenient to access them.

Although I might have tried to fix some of these issues, I was intimidated by the fact that this was a debugger, that it was a rather large piece of complicated software that interfaced with the command line Perl debugger. For what it did, it made my programming life much easier, and I was able to work around the quirks.

That all ended in 2009 when I changed jobs. Perl was no longer my primary environment. I ended up using a proprietary language written by a particular financial institution. There, I was not so intimidated. I enhanced that language’s debugger by adding a screen to manage breakpoints.

My next job was at a Java shop where I naturally learned how to use the Java debugger in what I think was the Eclipse ecosystem. At this shop, I was given a task to work on an old Perl program. The program read and wrote various files, but the file names were hard coded. They wanted me to make those names variable. In the process of making this change, I had to work on a production system because there was no dedicated development system. In order to make sure that I didn’t disturb production data, I was put on a read-only file system.

So now I had a chance to go back and work with Perl, and by extension, Devel::ptkdb. Once I had made my changes, I stepped through the program in the debugger in order to check them. Along the way, I set breakpoints and added variables in the variable display. Devel::ptkdb allows you to save the breakpoints and the variable list in a .ptkdb state file, which I did.

Imagine my surprise when I started up the program again in the debugger and my saved state was not loaded. I scratched my head for about 10 seconds and realized, “Ah, I’m on a read-only partition and the default location of the state file is the directory where the Perl script lives. That location is a read-only file system. Let me save the state file in my home directory.” 1

Imagine my surprise when I started up the program again and my saved state did not reappear again. I scratched my head for a bit more than 10 seconds. I tried it again. It was still not saved. After about half a day of having to reset variables and breakpoints every time I ran the program, I decided that it was high time I took a look at the debugger code. I figured that it had to be something simple, related to just the input box for the name of the state file; it was not even a proper file dialog. I was sure I could handle that.

I was able to find the issue and correct it. By using the local corrected version of the debugger, I was able to save my state file to any writable directory.

It was at that point that something clicked in my head. If I could make that fix, maybe I could make other fixes. Maybe I could fix some of the quirks that bothered me all those years ago.

About two months and a huge changelog later, I had fixed some of those quirks. I fixed the sort problem for the variables. I fixed the mapping problem to the loaded code. I even made some improvements. The debugger used to not reload the state file if you restarted the debugger. Now it did. I programmed in a separate widget that I could use to print messages from inside the debugger while I was debugging the debugger.

I then realized I probably shouldn’t keep this to myself, so I contacted the author, figuring that they would like to take these changes and update the code. This was approximately 2013, and the debugger hadn’t been touched since 1999. However, it turned out that the author had moved on and would prefer that I just took over the project. I agreed, but before I could talk to legal about trying to let this code out of the shop, I ended up leaving that job.

I left all these changes behind a corporate firewall.

And that’s where they stayed. Over the years, I had occasion to use the debugger again, but never quite had the ‘tuits to recreate all these changes.

Well, now I have the ‘tuits. I’m currently unemployed and I have committed to making a presentation at the next Perl and Raku Conference about the debugger. It’s time to roll up my sleeves, dig in and see if I cannot recreate what I did over ten years ago.

Footnotes
  1. Which, all these years later begs the question, “If the file system was read only, how did you update the script you were supposed to be changing?” Let’s not let details get in the way of a good story, shall we?  ↩

When you have lots and lots of qcow2

Thank you Team PWC for your continuous support and encouragement.
Welcome to the Week #373 of The Weekly Challenge.
Thank you Team PWC for your continuous support and encouragement.
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.
Just to give you context, Gabor Szabo, while working on opensource projects recently, he picked up my latest creation DBIx::Class::Async. He noticed, I didn’t have workflow configuration file. He kindly created pull request and submitted: PR #3. Without wasting a moment, I accepted the pull request and merged.
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