Shortcuts: s show h hide n next p prev

sbox32_hash.h: Add #undef's

Perl commits on GitHub
sbox32_hash.h: Add #undef's

These case statements need not be visible outside this header.  Putting
these here avoids cluttering up embed.h, where the same #undef lines
would otherwise be generated

embed.pl: Remove no longer used sub

Perl commits on GitHub
embed.pl: Remove no longer used sub

embed.pl: Also consider #undef's

Perl commits on GitHub
embed.pl: Also consider #undef's

This code looks to see what conditions must apply before a #define
happens.  This commit extends that to also look for #undef commands.

The end result is that for symbols that are visible to XS code, but
aren't supposed to be, embed.h contains an #undef so it isn't visible.
But if it already has been #undef'ed, there is no need to do this.

But a symbol can be defined and undefined many times, and the conditions
for doing an #undef may be different than what the symbol was #defined
under.

The consequences of not realizing that a symbol gets undefined are
simply that we generate an unnecessary #undef.  The consequences of
failing to generate one when the symbol is defined is that it is
visibile when not intended to be so.

So, there are various restrictions to try to make sure that we don't
err in the latter direction.
embed.pl: Consider symbols visible only to extensions

Two commits ago, the code was extended to compare the C preprocessor
visibility of a symbol with what the desired visibility of a symbol is.
It assumed that everything not constrained to core was visible
everywhere.  This commit extends that to look for being visible only to
extensions.  As a result, the large number of symbols added to the
override list in that commit are now removed.

embed.pl: Add cpp constraints for .h files

Perl commits on GitHub
embed.pl: Add cpp constraints for .h files

Many of the header files in our source have guards that keep them from
being recursively called, with a convention as to how their name is
derived from the file name.  This commit changes to now consider these
when computing what a cpp conditional evaluates to.  It follows the
convention, except in those few places where it is violated, and sets up
the infrastructure so that this mechanism could be applied for other
cases.

Since this commit was originally written, all but one header file has
been changed to follow the convention, so after rebasing,  only one line
is now being added.

I just released version 5 of Venus, (vns (https://github.com/usevenus/vns) on GitHub), along with two companion repos:

Venus is opinionated but pragmatic. The goal has always been to give modern Perl 5 developers a cohesive set of modern primitives for data modeling, validation, error handling, roles, CLI tooling, and functional-style helpers, without abandoning Perl idioms or core sensibilities.

v5 is the largest release so far and includes both new features and some intentional breaking changes to clean up long-standing design constraints.

Highlights from v5.01:

This project is very much for people who still like Perl, want stronger structure, and prefer libraries that help you model intent rather than just shuffle data.

Feedback, criticism, and questions are all welcome. If nothing else, I hope it sparks some interesting discussion about what "modern Perl" can look like today.

Retrospective on the Perl Development Release 5.43.7

r/perl

Perl.org error fetching content from CDN?

r/perl

I'm getting

503 hostname doesn't match against certificate

Which makes the website look more like wall.org

submitted by /u/brtastic
[link] [comments]

SBOM::CycloneDX 1.07 is released

blogs.perl.org

I've released a new version of SBOM::CycloneDX with support for the OWASP CycloneDX 1.7 specification (ECMA-424).

This release includes the new elements introduced in 1.7, with a focus on:

  • Enhancements to Cryptography Bill of Materials (CBOM)
  • Citations: references and sources for evidence/metadata
  • Intellectual Property Transparency: references to associated patents (number, jurisdiction, link, assignee) for compliance / due diligence needs

New experimental "SBOM::CycloneDX::Lite" interface: A lightweight module designed to generate BOMs with a simpler API, using the most common CycloneDX properties.

Examples included in the distribution (use them as a starting point to build your own applications/tools that generate BOM files): - "x509-to-cbom" : generates a CBOM from an X.509 certificate - "rpm-to-sbom" : generates a SBOM from installed RPM packages (on RHEL-based)

The goal of this module is to help the Perl community generate BOM files more easily, improving security and compliance across the ecosystem and making the software supply chain more transparent.

SBOM::CycloneDX is available on CPAN / MetaCPAN: https://metacpan.org/pod/SBOM::CycloneDX

Related projects: - App::CPAN::SBOM - https://metacpan.org/dist/App-CPAN-SBOM - Modules::CoreList::SBOM - https://github.com/giterlizzi/perl-Module-CoreList-SBOM

Retrospective on the Perl Development Release 5.43.7

blogs.perl.org

(cross-posted from my blog)

Last Monday I did the Perl Developer Release of Perl 5.43.7. As usual, I worked from the Release Managers Guide . Everything worked well, even if everything was cutting it a bit close. My video setup on the desktop was not suited for streaming anymore, so I had to do a stream consisting only of the console window and me talking over it, and no floating head of me available.

What worked well

The Twitch chat was the most active that I witnessed when streaming a Perl release. We chatted about organizing Perl conferences and also the Perl release process. One realization for me was that the RMG process is mostly there to exercise the Perl build machinery and testing that the generated tarball does not have deficiencies. This means that testing that Perl can build through Configure is important, but testing different Perl configurations like ithreads or userelocatableinc is not that important.

The dashboard for tracking my progress through the release worked well up to the release. I had modified it in the weeks leading up to the release to not only show the human step description but also to show the command line steps that should be undertaken, where applicable. I see this as a first step in automating these steps where possible and sensible.

What didn't work out

The dashboard can use some improvements:

  • The script did not cope well with the events after the release when the repo version number was bumped from 5.43.7 to 5.43.8. This part needs to be investigated but is easy to replicate by simply launching the dashboard with a version number before the current version number.

  • The script could highlight the current position in the sequence better. For console output this would likely mean inverting the line where the next applicable step is, but this means moving the output from Text::Table to a custom table generation or post-patching the string from Text::Table with the appropriate console commands.

  • The script should generate HTML and terminal output at the same time. Having output visible in a browser feels less retro but makes things like publishing the progress elsewhere easier.

  • The script should have a feature to simply output the next step. This could be integrated into the shell prompt to give a guided message in the console window. Maybe the console output and the HTML output should be done as files when in "interactive" mode?

Improvements to the Perl Release Process

  • More parallelism - the current release manager guide uses make test in many places. This runs the test suite in serial mode, which takes on my machine about 10 minutes. Running the test suite in parallel takes about 4-5 minutes. This is implemented using the make test_harness command. Whether Perl should move the default of parallel testing to make testfrom make test_harness is debatable. Most likely everybody who cares about speed already runs the test suite in parallel.

  • Remove sequences of shell commands - comparing the file names between the previous and current Perl version is done using a sequence of shell commands involving sort, diff`. I have a patch that adds a small tool to do that within Perl (mostly powered by Algorithm::Diff ).

I'll Have a Mojolicious::Lite

blogs.perl.org

I’ve built mojoeye, a tiny Perl app to run system and security checks across our internal Linux hosts:

It’s built for environments where time, attention, and continuity are scarce. Checks are plain Perl scripts, the server is a single-file Mojolicious::Lite web app, and each host runs a small single-file client that reports back. There’s a short tutorial that gets someone productive in about 30 minutes.

Thank you, Mojolicious!

MIT licensed; currently tested on Debian- and Fedora-like systems.

— Gwyn
screenshot.png

Venus v5 released: Modern OO standard library (and more) for Perl 5

r/perl

I just released version 5 of Venus, (vns on GitHub), along with two companion repos:

  • bye: An introduction to Venus by example
  • cfu: A set of Claude Code instructions for writing Perl using Venus ideas and primitives

Venus is opinionated but pragmatic. The goal has always been to give modern Perl 5 developers a cohesive set of modern primitives for data modeling, validation, error handling, roles, CLI tooling, and functional-style helpers, without abandoning Perl idioms or core sensibilities.

v5 is the largest release so far and includes both new features and some intentional breaking changes to clean up long-standing design constraints.

Highlights from v5.01:

  • First class support for private instance data
  • Thoroughly documented type system and parser, see Venus::Type, Venus::Check
  • New core utilities: Venus::Map, Venus::Set, Venus::Range, Venus::Collect, Venus::Result
  • Myriad ways to validate data, e.g., Venus::Data, Venus::Validate, and Venus::Schema
  • Improved error and fault handling with Venus::Error, Venus::Try, and Resultable roles
  • Keyword functions like gets, sets, mask, kvargs, unpack, and cli
  • Refactored container and factory model (i.e., dependency injection)
  • Method modifiers, lifecycle hooks, coercion-by-type, and richer role composition
  • A much more capable CLI framework with routing, dispatching, and spec-driven configuration
  • Better configuration handling, including support for .env files and multiline environment variables
  • Significant internal refactors to simplify extension and documentation
  • Overhauled test framework with more features, automation, and POD generation

This project is very much for people who still like Perl, want stronger structure, and prefer libraries that help you model intent rather than just shuffle data.

Feedback, criticism, and questions are all welcome. If nothing else, I hope it sparks some interesting discussion about what "modern Perl" can look like today.

submitted by /u/iamalnewkirk
[link] [comments]

How can we make this Moose faster?

r/perl

Live streaming the Perl 5.43.7 development release

blogs.perl.org

I was on the schedule for 2025, but by swapping the release version, I skipped doing a release in 2025. This year, I'm doing the dev release live stream again on Twitch, for version 5.43.7.

And again, you can watch it live on Monday 19th of January on Twitch.

You can expect to watch me talk through the steps of the Perl Release Managers Guide and if you join the Twitch chat, or

p5p on irc.perl.org, we can chat a bit.

I assume I'll start Monday at 16:00 UTC (17:00 CET), and the whole thing will take around 4 hours unless there are some major mishaps. In the middle, I'll join a call of the organizers of the German Perl Workshop 2026 in Berlin, where we will likely go through organizing the social event and the pre-conference meeting.

This week in PSC (212) | 2026-01-19

blogs.perl.org

All of us were present.

  • We discussed the recent p5p thread about the proposed class :abstract attribute. Paul wants to write that because it’s a simple addition on current code and avoids design complications about roles. Aristotle doesn’t wish to introduce a new special-purpose feature now that will become redundant when a more general one is available later and wondered whether it can be introduced as roles that currently only support a small subset of features. No call has been made.
  • The class discussions also extended to looking at the meta module and API, and the common idea between the two that it would be useful to get more people to use them and discuss future ideas. We would like people to step forward here.
  • We have PR #24059 to implement the retraction of the deprecation of being able to call undefined import methods (and the reinstatement of a default-enabled warning for that case), thanks to haarg. We are keen to get it merged so we will provide feedback soon.
  • The maint-votes process came up. We pondered whether we can conceive of something less obscure and will post to the list about this.

[P5P posting of this summary]

Weekly Challenge: Fractional Constant

dev.to #perl

Weekly Challenge 357

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. It's a great way for us all to practice some coding.

Challenge, My solutions

Task 1: Kaprekar Constant

Task

Write a function that takes a 4-digit integer and returns how many iterations are required to reach Kaprekar's constant (6174).

My solution

This is where GitHub Copilot really scars me somewhat. Without mentioning "kaprekar" at all, and after typing while number != 6174: it auto-completed the rest of the code.

For this solution, I start by checking that the number is between 1 and 9999, and that it is not divisible by 1111. If any of these are false, I return -1.

I create a variable called count, starting at 0. If number is not 6174, I take the following steps

  1. Set digits to be the individual digits, left padded with zeros if needed.
  2. Set asc_digits to the above digits list, sorted numerically (lowest first). Set desc_digits to the same, but in reversed sorted order.
  3. Set small_num to the integer that concatenates asc_digits.
  4. Set large_num to the integer that concatenates desc_digits.
  5. Set number to be large_num minus small_num.
  6. If this is not 6174, repeat the loop again.
def kaprekar_constant(number: int) -> int:
    if not 0 < number < 10000:
        return -1

    if number % 1111 == 0:
        return -1

    count = 0
    while number != 6174:
        digits = [int(d) for d in str(number).zfill(4)]
        asc_digits = sorted(digits)
        desc_digits = sorted(digits, reverse=True)
        small_num = int(''.join(map(str, asc_digits)))
        large_num = int(''.join(map(str, desc_digits)))
        number = large_num - small_num
        count += 1

    return count

The Perl solution is a little shorter, as I don't need to worry about finicky things like converting integers to strings :P

sub main ($int) {
    if ($int < 1 or $int > 9999 or $int % 1111 == 0) {
        say -1;
        return;
    }

    my $count = 0;
    while ($int != 6174) {
        my $small_number = join("", sort { $a <=> $b } (split //, sprintf("%04d", $int)));
        my $big_number = reverse($small_number);
        $int = $big_number - $small_number;
        $count++
    }

    say $count;
}

Examples

$ ./ch-1.py 3524
3

$ ./ch-1.py 6174
0

$ ./ch-1.py 9998
5

$ ./ch-1.py 1001
4

$ ./ch-1.py 9000
4

$ ./ch-1.py 1111
-1

Task 2: Unique Fraction Generator

Task

Given a positive integer n, generate all unique fractions you can create using integers from 1 to n and follow the rules below:

  • Use numbers 1 through n only (no zero)
  • Create fractions like numerator/denominator
  • List them in ascending order (from smallest to largest)
  • If two fractions have the same value (like 1/2 and 2/4), only show the one with the smallest numerator

My solution

Python has the fractions module as standard, while Perl has a CPAN module called Numbers::Fraction.

Both exhibit the same behaviors:

  • Takes the numerator (top part) and denominator (bottom part) as input variables
  • Will automatically convert to have the lowest unique values. For example, Fraction(2, 4) automatically is Fraction(1, 2).
  • Annoyingly for this task, will print a whole number if the denominator is 1.
  • Two fractions variables can be compared to be sorted correctly (by the number they represent). For example ¼ < ½.

With that in mind, this task involves having a double loop for n and d (both from 1 to number), removing the duplicates with the set function, and then sorting them numerically. Finally, I turn the Fraction object into strings, and return the list.

def unique_fraction_generator(number: int) -> list[str]:
    fractions = sorted(set(
        Fraction(n,d)
        for d in range(1, number + 1)
        for n in range(1, number+1)
    ))

    return [f"{frac.numerator}/{frac.denominator}" for frac in fractions]

The Perl solution follows the same logic. It uses grep to check if a fraction is added previously, and pushes it to the fractions array if it is not.

use Number::Fraction;

sub main ($int) {
    my @fractions = ();
    foreach my $n (1 .. $int) {
        foreach my $d (1 .. $int) {
            my $fraction = Number::Fraction->new($n, $d);
            push @fractions, $fraction if not grep { $_ == $fraction} @fractions;
        }
    }

    my @sorted_fractions = sort { $a <=> $b } @fractions;
    say join(", ", map({ "$_->{num}/$_->{den}" } @sorted_fractions));
}

Examples

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

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

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

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

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

Perl 🐪 Weekly #756 - Perl in 2026

dev.to #perl

Originally published at Perl Weekly 756

Hi there,

Perl continues to show remarkable momentum in early 2026, with Dean highlighting the language's improved position in the TIOBE Index, signaling renewed attention and ongoing relevance. This renewed visibility is supported by active development and innovative tooling, from Toby Inkster's performance-boosting Moose extensions to William McLean's demonstration of deploying Perl MCP servers on Cloud Run.

Community and ecosystem engagement remain strong, as seen with CosmoShop sponsoring the German Perl Workshop and the launch of the Thunderhorse web framework beta, offering modern features like WebSockets and SSE. Open-source contributions continue to thrive, exemplified by Corion's 2025 module releases and Robert Acock's work on practical data structures, helping developers build efficient, real-world applications.

The Perl community also places emphasis on knowledge-sharing and accessibility. Dave Cross's slide archives provide a wealth of training resources, while the Perl Ad Server enables easy promotion of community events, jobs, and podcasts, strengthening connections across the ecosystem.

Finally, discussions within the Perl Steering Council, such as those on experimental features like refaliasing and declared_refs, demonstrate ongoing efforts to evolve the language responsibly. Alongside a growing focus on transparency and sustainability, as highlighted in Makoto Nozaki's financial analysis of TPRF, these developments show a community that balances innovation, support, and stewardship.

Stay positive and healthy, enjoy rest of the newsletter.

--
Your editor: Mohammad Sajid Anwar.

Announcements

This week in PSC (211) | 2026-01-12

We mostly discussed the experimental refaliasing and declared_refs features to see if we can find a path towards declaring at least the latter non-experimental.

Cosmoshop supports the German Perl Workshop 2026

Max Maischein announces that CosmoShop, one of the world’s largest pure‑Perl shop systems, is once again sponsoring the German Perl Workshop in 2026, strengthening community support for this key Perl/Raku conference. This continued backing highlights the vibrant ecosystem and industry engagement around Perl events.

Thunderhorse Beta released!

The blog announces the beta release of Thunderhorse, a new Perl web framework drawing on lessons from Kelp and built natively on PAGI, with real‑time features like WebSocket and SSE support and a focus on extensibility and high code quality.

Slide archive: Learn with Dave Cross

Dave Cross has published an archive of slides from his long‑running technical training courses on Perl and other developer topics, going back many years and available for free download. These slide decks offer a valuable resource for anyone wanting concise, well‑structured material from experienced instruction.

The corner of Gabor

A couple of entries sneaked in by Gabor.

Perl code reading and open source contribution

One of the best ways to learn is by reading other people's code, making small contributions and getting feedback. That's exactly what we do at these online sessions. The next one taking place on January 24 in a Zoom near you. Join us!

Articles

What I released in 2025

In his year‑in‑review post, Corion reflects on a productive 2025 by highlighting several useful Perl modules he published, including Text::HTML::Turndown for converting HTML to Markdown and Date::Find for extracting dates from filenames. He also shares a paranoid Mojo::UserAgent extension and contributions to core modules, giving readers insight into both his releases and ongoing development work.

How can we make this Moose faster?

Toby Inkster introduces performance‑boosting extensions to Moose with MooseX::XSAccessor and the new MooseX::XSConstructor, showing significant speedups in object creation and method access. His benchmarks suggest up to ~76 % faster performance using XS‑based accessors and constructors, offering a practical way to accelerate Moose‑based Perl code.

Understanding TPRF's Finance, 2026 Edition

Makoto Nozaki takes a clear, numbers‑driven look at The Perl and Raku Foundation’s 2024 financials, showing a significant increase in revenue but expenses that far exceeded income and halved its assets. His breakdown highlights both positive trends in donations and a strong call for greater transparency to ensure the foundation’s long‑term sustainability.

Taking the Win - Perl in the TIOBE Index

Dean celebrates Perl’s improved position in the TIOBE Index during 2025 and highlights the ongoing momentum in the Perl community, from steady releases to vibrant events and tooling support. While acknowledging healthy skepticism about popularity metrics, he encourages readers to "take the win" and appreciate the positive signals for Perl’s ecosystem.

Firestore MCP Development with Perl, Cloud Run, and Gemini CLI

William McLean walks through building a minimal Perl‑based MCP (Model Context Protocol) server backed by Firestore, showing how to validate it locally and deploy it to Google Cloud Run using the Gemini CLI. The article highlights practical steps for integrating Perl with modern AI‑oriented workflows beyond the usual Python ecosystem and gives clear pointers for developers looking to experiment with MCP and Cloud Run deployments.

Doubly: Why Arrays Aren't Always Enough

Robert explores when traditional arrays fall short and makes a compelling case for using doubly linked lists instead, especially for operations like O(1) insertions and intuitive cursor navigation. Through Perl examples and performance trade‑offs across multiple implementations, from pure Perl to thread‑safe C registries, the article highlights practical data‑structure choices and when they pay off.

Perl Ad Server

The Perl Ad Server makes it easy to promote Perl‑related announcements, from events and podcasts to jobs and newsletters, by embedding a tiny JavaScript snippet that displays rotating banners on your website. It’s simple to style and control, and contributions are welcomed via GitHub for anyone who wants to add or manage ads for the community.

Grants

Maintaining Perl 5 Core (Dave Mitchell): December 2025

Maintaining Perl (Tony Cook) December 2025

PEVANS Core Perl 5: Grant Report for December 2025

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 Lance Wicks.

The Weekly Challenge - 357

Welcome to a new week with a couple of fun tasks "Kaprekar Constant" and "Unique Fraction Generator". 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 - 356

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

Kolakoski Wins

The article clearly demonstrates a thoughtful Raku solution to generating the Kolakoski sequence and counting 1s, leveraging Raku’s gather/take constructs for elegant lazy sequence generation. The examples and code comments make the approach easy to understand.

Perl Weekly Challenge: Week 356

The post delivers a technically clear explanation of both the Kolakoski Sequence and Who Wins tasks with illustrative examples and thoughtful insight into simplifying the problem logic—showcasing an effective balance between correctness and practical Perl coding. The walkthroughs help demystify the challenge specifications and offer useful implementation perspectives for Perl developers.

Self-Generating Games

The post delivers clear, well-structured solutions to both tasks, especially with its concise explanation of generating the Kolakoski sequence and counting elements. The breakdowns and examples make the logic easy to follow and practically useful for coding challenges.

Perl Weekly Challenge 356

The post showcases concise and effective Perl implementations for both the Kolakoski‑Sequence and Who‑Wins tasks, with a compact self‑referential sequence generator and a structured playoff progression model. The code is thoughtfully organised and demonstrates practical mastery of sequence construction and game logic within Perl’s syntax.

Kolakoski called, he wants his sequence back(!)

The post offers a thoughtful, well-commented Perl exploration of the Kolakoski sequence that breaks down the generation logic with clear analogies and illustrative code, making the algorithm approachable even for those new to the concept. Its lively explanation paired with working examples enhances understanding and practical problem-solving.

Who’s Kolakoski?

The write-up presents a thoughtful multilingual exploration of the Kolakoski challenge with clear logic and practical code that demonstrates command over sequence generation and problem constraints, making it both accessible and instructive. Packy’s commentary and stepwise approach enhance readability and offer valuable insights for anyone tackling the Weekly Challenge tasks.

Sequence and consequence

The post provides a clear, well-reasoned implementation of both tasks, with the Kolakoski solution closely following the Wikipedia algorithm and demonstrating impressive performance at scale. The NFL playoff logic is neatly modeled with concise Perl code, showing careful handling of seeding, sorting, and edge cases in a readable and maintainable way.

The Weekly Challenge #356

The post offers clear, well-structured Perl solutions for both the Kolakoski sequence and "Who Wins" tasks, closely following the problem definitions with readable logic and solid use of Perl idioms. The explanations make the algorithms accessible while the included references help ground the implementation in established techniques.

Kolakoski Wins

The post presents elegant and thoughtfully implemented solutions to both tasks, with the Kolakoski sequence logic clearly articulated and efficiently expressed in Raku. The playoff "Who Wins" solution demonstrates solid handling of round progression and seed logic, showcasing clean algorithm design and practical Rust usage.

Winning sequence

The write-up delivers concise and effective Python solutions for both the Kolakoski Sequence and Who Wins tasks, with a clever analytical shortcut for the sequence count and a clean stepwise modeling of the playoff progression. The inclusion of examples and clear logic makes the implementations easy to follow and practically useful.

Rakudo

2026.02 Resolutions

Weekly collections

NICEPERL's lists

Great CPAN modules released last week;
MetaCPAN weekly report.

Events

Perl Maven online: Live Open Source contribution

January 24, 2025

Boston.pm - online

February 10, 2025

German Perl/Raku Workshop 2026 in Berlin

March 16-18, 2025

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.

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

Leveraging Gemini CLI and the underlying Gemini LLM to build Model Context Protocol (MCP) AI applications in Perl with Google Cloud Run.

Leveraging Gemini CLI and the underlying Gemini LLM to build Model Context Protocol (MCP) AI applications in Perl with Google Cloud Run.

Why not just use Python?

Python has traditionally been the main coding language for ML and AI tools. One of the strengths of the MCP protocol is that the actual implementation details are independent of the development language. The reality is that not every project is coded in Python- and MCP allows you to use the latest AI approaches with other coding languages.

Perl? Is that even a language anymore?

The goal of this article is to provide a minimal viable basic working MCP server in Perl that can be run locally without any unneeded extra code or extensions.

The Perl MCP module is here:

MCP-0.06

What Is Perl?

Perl is a general-purpose, high-level programming and scripting language, primarily known for its powerful text manipulation capabilities. Originally created by Larry Wall in 1987 for easier report processing, it has evolved to be used for a wide range of tasks, including system administration, web development, and network programming.

The main site for Perl is :

The Perl Programming Language - www.perl.org

Installing Perl

The step by step instructions vary by platform- for a basic Debian system here are the steps:

sudo apt-get install perl cpanminus

xbill@penguin:~/gemini-cli-codeassist/firstore-https-perl$ perl --version

This is perl 5, version 36, subversion 0 (v5.36.0) built for x86_64-linux-gnu-thread-multi
(with 60 registered patches, see perl -V for more detail)

Gemini CLI

If not pre-installed you can download the Gemini CLI to interact with the source files and provide real-time assistance:

npm install -g @google/gemini-cli

Testing the Gemini CLI Environment

Once you have all the tools and the correct Node.js version in place- you can test the startup of Gemini CLI. You will need to authenticate with a Key or your Google Account:

gemini

Node Version Management

Gemini CLI needs a consistent, up to date version of Node. The nvm command can be used to get a standard Node environment:

GitHub - nvm-sh/nvm: Node Version Manager - POSIX-compliant bash script to manage multiple active node.js versions

Perl MCP Documentation

The official MCP CPAN page provides samples and documentation for getting started:

MCP

Where do I start?

The strategy for starting MCP development is a incremental step by step approach.

First, the basic development environment is setup with the required system variables, and a working Gemini CLI configuration.

Then, a minimal Hello World Style Perl MCP Server is built with HTTP transport. This server is validated with Gemini CLI in the local environment.

This setup validates the connection from Gemini CLI to the local process via MCP. The MCP client (Gemini CLI) and the MCP server both run in the same local environment.

Next- the basic MCP server is extended with Gemini CLI to add several new tools in standard code.

Setup the Basic Environment

At this point you should have a working Perl environment and a working Gemini CLI installation. The next step is to clone the GitHub samples repository with support scripts:

cd ~
git clone https://github.com/xbill9/gemini-cli-codeassist

Then run init.sh from the cloned directory.

The script will attempt to determine your shell environment and set the correct variables:

cd gemini-cli-codeassist
source init.sh

If your session times out or you need to re-authenticate- you can run the set_env.sh script to reset your environment variables:

cd gemini-cli-codeassist
source set_env.sh

Variables like PROJECT_ID need to be setup for use in the various build scripts- so the set_env script can be used to reset the environment if you time-out.

Hello World with HTTP Transport

One of the key features that the standard MCP libraries provide is abstracting various transport methods.

The high level MCP tool implementation is the same no matter what low level transport channel/method that the MCP Client uses to connect to a MCP Server.

The simplest transport that the SDK supports is the stdio (stdio/stdout) transport — which connects a locally running process. Both the MCP client and MCP Server must be running in the same environment.

The HTTP MCP transport allows the client and server to be on the same machine or distributed over the Internet.

The connection over HTTP will look similar to this:

# Use HTTP transport via Mojolicious
any '/mcp' => $server->to_action;

Perl Package Information

The Perl code depends on several standard libraries for MCP and logging:

requires 'Mojolicious::Lite';
requires 'MCP::Server';
requires 'JSON::MaybeXS';
requires 'WWW::Google::Cloud::Auth::ServiceAccount';
requires 'URI::Encode';
requires 'LWP::Protocol::https';

Installing and Running the Perl Code

Run the install make release target on the local system:

xbill@penguin:~/gemini-cli-codeassist/firestore-https-perl$ make
Installing dependencies...
--> Working on .
Configuring /home/xbill/gemini-cli-codeassist/firestore-https-perl ... OK
<== Installed dependencies for .. Finishing.
Running tests...
t/00_compile.t ................... ok   
t/01_firestore_client_compile.t .. ok   
All tests successful.
Files=2, Tests=2, 0 wallclock secs ( 0.01 usr 0.01 sys + 0.34 cusr 0.05 csys = 0.41 CPU)
Result: PASS

To test the code:

xbill@penguin:~/gemini-cli-codeassist/firestore-https-perl$ make test
Running tests...
t/00_compile.t .. ok   
All tests successful.
Files=1, Tests=1, 0 wallclock secs ( 0.02 usr 0.00 sys + 0.19 cusr 0.05 csys = 0.26 CPU)
Result: PASS

Gemini CLI settings.json

In this example — the Perl source code uses a Perl interpreter that can be called directly from Gemini CLI.

The default Gemini CLI settings.json has an entry for the source:

 {
    "mcpServers": {
    "firebase-https-perl": {
      "httpUrl": "http://127.0.0.1:8080/mcp"
    }
  }
}

Start the Local Server

Open a new terminal to run the local MCP Perl server :

xbill@penguin:~/gemini-cli-codeassist/firestore-https-perl$ make run
Running the application...
{"asctime":"2026-01-12T22:10:06.21872Z","levelname":"INFO","message":"Initializing Firestore for project: comglitn","name":"root"}
{"asctime":"2026-01-12T22:10:06.2188Z","levelname":"INFO","message":"Firestore initialized successfully","name":"root"}
{"asctime":"2026-01-12T22:10:06.21881Z","levelname":"INFO","message":"Starting MCP server","name":"root"}
{"asctime":"2026-01-12T22:10:06.22059Z","levelname":"INFO","message":"Listening at \"http://0.0.0.0:8080\"","name":"root"}
Web application available at http://0.0.0.0:8080

Validation with Gemini CLI

Leave the local server running and open a new Terminal window. Gemini CLI is used to validate the MCP connection over HTTP to the Perl Code:

> /mcp list

Configured MCP servers:

🟢 firebase-https-perl - Ready (8 tools)
  Tools:
  - add_product
  - batch_delete
  - delete_product
  - find_products
  - get_product
  - greet
  - list_products
  - update_product

> find_products Coffee

✦ I will search for products matching "Coffee".
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ? find_products (firebase-https-perl MCP Server) {"name":"Coffee"} ← │
│ │
│ MCP Server: firebase-https-perl │
│ Tool: find_products │
│ │
│ Allow execution of MCP tool "find_products" from server "firebase-https-perl"? │
│ │
│ 1. Allow once │
│ 2. Allow tool for this session │
│ ● 3. Allow all server tools for this session │
│ 4. No, suggest changes (esc) │
│ │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

✦ I will search for "Coffee Beans" specifically, as it exists in the inventory.
╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ find_products (firebase-https-perl MCP Server) {"name":"Coffee Beans"} │
│ │
│ {"products":[{"actualdateadded":"2026-01-07T16:53:00.672Z","id":"37kWbZHTwg5nbrSD13PB","imgfile":"product-images\/coffeebeans. │
│ png","name":"Coffee Beans","price":6,"quantity":375,"timestamp":"2024-11-30T08:40:02.515Z"}]} │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ I found the product you were looking for: Coffee Beans (ID: 37kWbZHTwg5nbrSD13PB). It is priced at $6 and there are 375 in
  stock.

Deploying to Cloud Run

After the HTTP version of the MCP server has been tested locally — it can be deployed remotely to Google Cloud Run.

First- switch to the directory with the HTTP MCP sample code:

cd ~/gemini-cli-codeassist/firestore-https-perl

Deploy the project to Google Cloud Run with the pre-built cloudbuild.yaml and Dockerfile:

cd ~/gemini-cli-codeassist/firestore-https-perl
xbill@penguin:~/gemini-cli-codeassist/firestore-https-perl$ make deploy

The Cloud Build will start:

> make deploy

✦ I will read the Makefile to understand the deployment process and then execute make deploy.

╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ ReadFile Makefile │
│ │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ I will read cloudbuild.yaml to verify the build configuration.

╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ✓ ReadFile cloudbuild.yaml │
│ │
╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
✦ I will execute make deploy to submit the build to Google Cloud Build.

✦ I will execute make deploy to submit the build to Google Cloud Build and deploy the application.

╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ ⊶ Shell make deploy [current working directory /home/xbill/gemini-cli-codeassist/firestore-https-perl] (Submit build to Goog… │
│ │
│ Step #0: 7703c2863431: Pulling fs layer │
│ Step #0: d4d869c8f88d: Pulling fs layer │
│ Step #0: 8b22c905be5d: Pulling fs layer │
│ Step #0: 8b22c905be5d: Waiting │
│ Step #0: 7703c2863431: Download complete │
│ Step #0: 8b22c905be5d: Verifying Checksum │
│ Step #0: 8b22c905be5d: Download complete │
│ Step #0: d4d869c8f88d: Verifying Checksum │
│ Step #0: d4d869c8f88d: Download complete │
│ Step #0: 7bbf972c6c2f: Verifying Checksum │
│ Step #0: 7bbf972c6c2f: Download complete │
│ │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

It can take 15–30 minutes to complete the build.

The cloud build needs to pull in all Perl libraries in the build environment and generate the entire package from scratch.

When the build is complete- an endpoint will be returned:

│ Starting Step #2 │
│ Step #2: Already have image (with digest): gcr.io/cloud-builders/gcloud │
│ Step #2: Deploying container to Cloud Run service [firestore-https-perl] in project [comglitn] region [us-central1] │
│ Step #2: Deploying... │
│ Step #2: Setting IAM Policy.........done │
│ Step #2: Creating │
│ Revision...................................................................................................................... │
│ .............................................................................................................................. │
│ .................done │
│ Step #2: Routing traffic.....done │
│ Step #2: Done. │
│ Step #2: Service [firestore-https-perl] revision [firestore-https-perl-00002-v5g] has been deployed and is serving 100 percent │
│ of traffic. │
│ Step #2: Service URL: https://firestore-https-perl-1056842563084.us-central1.run.app │
│ Finished Step #2 │
│ PUSH │
│ Pushing gcr.io/comglitn/firestore-https-perl:latest │
│ The push refers to repository [gcr.io/comglitn/firestore-https-perl] │

The service endpoint in this example is :

https://firestore-https-perl-1056842563084.us-central1.run.app

The actual endpoint will vary based on your project settings.

Review Service in Cloud Run

Navigate to the Google Cloud console and search for Cloud Run -

and then you can detailed information on the Cloud Run Service:

Cloud Logging

The remote server writes logs to stderr in standard JSON format. These logs are available from the deployed Cloud Run Service:

Validate HTTP connection

Once you have the Endpoint — you can attempt a connection- navigate to in your browser:

https://firestore-https-perl-1056842563084.us-central1.run.app

You will need to adjust the exact URL to match the URL returned from Cloud Build.

You will get an error- this connection is expecting a message in the MCP format:

Not Found

Gemini CLI settings.json.cloudrun

Replace the default Gemini CLI configuration file —  settings.json with a pre-configured sample- settings.json.cloudrun to use the Cloud Run version of the connection:

 {
    "mcpServers": {
    "firestore-cloudrun-perl": {
      "httpUrl": "https://firestore-https-perl-$PROJECT_NUMBER.us-central1.run.app/mcp"
    }
  }
}

Copy the Cloud Run version of the Gemini CLI configuration file:

xbill@penguin:~/gemini-cli-codeassist/firestore-https-perl$ cd .gemini
cp settings.json.cloudrun settings.json
xbill@penguin:~/gemini-cli-codeassist/firestore-https-perl/.gemini$

Validation with Gemini CLI

The final connection test uses Gemini CLI as a MCP client with the deployed Cloud Run Service in Perl providing the MCP server. Startup Gemini CLI with the updated settings :

gemini

> /mcp list

Configured MCP servers:

🟢 firestore-cloudrun-perl - Ready (8 tools)
  Tools:
  - add_product
  - batch_delete
  - delete_product
  - find_products
  - get_product
  - greet
  - list_products
  - update_product

✦ I have retrieved the list of products from the inventory. There are currently 34 products available, ranging from fresh produce
  like Apples and Bananas to pantry staples like Rice and Coffee Beans. Some items, such as Wasabi Party Mix and Jalapeno
  Seasoning, are currently out of stock.

> how can I generate the most revenue from my inventory?

✦ Based on your current inventory, here is a breakdown of how to maximize revenue:

  Top Revenue Drivers (High Price × High Volume)
  These products currently hold the most value in your inventory. Prioritize selling these to unlock the most cash flow.
   1. Whole Wheat Bread ($3,280 potential) — High price ($10) and good stock.
   2. Pineapple Kombucha ($3,216 potential) — Premium price ($8) with high volume.
   3. Green Tea ($2,844 potential) — Mid-range price ($6) but very high quantity.
   4. Beef ($2,380 potential) — High price ($10) item.
   5. Maple Almond Butter ($2,355 potential).

  Strategic Opportunities
   * Restock Alerts:
       * Wasabi Party Mix and Jalapeno Seasoning are completely out of stock ($0 revenue).
       * Walnuts (2 left) and Smores Cereal (23 left) are running low. Walnuts are a higher-price item ($7), so missing sales here
         is a lost opportunity.
   * Volume Movers (High Quantity / Low Price):
       * Eggs (496 units @ $1) and Black Beans (486 units @ $3) are abundant. Consider bundling these or running "buy one get one"
         promotions to clear space and generate liquidity.
   * Premium Items:
       * Cola and Whole Chicken are priced at $10. Even small increases in sales volume for these items will significantly impact
         your bottom line.

Summary

MCP development with Perl using Gemini CLI was validated with an incremental step by step approach.

A minimal streaming HTTP transport MCP Server was built from source code and validated with Gemini CLI running as a MCP client in the same local environment.

Then — the MCP server was wrapped in a container and submitted to Google Cloud Build for deployment to Google Cloud Run. The remote MCP server was validated with a standard browser, and Gemini CLI.

Finally- remote MCP operations were performed from the local Gemini CLI installation to the Perl MCP server hosted in Google Cloud Run.

This approach can be extended to more complex deployments and Cloud based options.

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

  1. CPANSA::DB - the CPAN Security Advisory data as a Perl data structure, mostly for CPAN::Audit
    • Version: 20260110.003 on 2026-01-11, with 25 votes
    • Previous CPAN version: 20260104.001 was 6 days before
    • Author: BRIANDFOY
  2. FFI::Platypus - Write Perl bindings to non-Perl libraries with FFI. No XS required.
    • Version: 2.11 on 2026-01-12, with 69 votes
    • Previous CPAN version: 2.10 was 1 year, 24 days before
    • Author: PLICEASE
  3. Firefox::Marionette - Automate the Firefox browser with the Marionette protocol
    • Version: 1.70 on 2026-01-11, with 18 votes
    • Previous CPAN version: 1.69 was before
    • Author: DDICK
  4. Module::Starter - a simple starter kit for any module
    • Version: 1.82 on 2026-01-10, with 34 votes
    • Previous CPAN version: 1.81 was before
    • Author: XSAWYERX
  5. Net::DNS - Perl Interface to the Domain Name System
    • Version: 1.54 on 2026-01-16, with 29 votes
    • Previous CPAN version: 1.53 was 4 months, 18 days before
    • Author: NLNETLABS
  6. Net::SSH::Perl - Perl client Interface to SSH
    • Version: 2.144 on 2026-01-14, with 20 votes
    • Previous CPAN version: 2.143 was 1 year, 10 days before
    • Author: BRIANDFOY
  7. Sidef - The Sidef Programming Language - A modern, high-level programming language
    • Version: 26.01 on 2026-01-13, with 121 votes
    • Previous CPAN version: 25.12 was 23 days before
    • Author: TRIZEN
  8. Sys::Virt - libvirt Perl API
    • Version: v12.0.0 on 2026-01-16, with 17 votes
    • Previous CPAN version: v11.10.0 was 1 month, 14 days before
    • Author: DANBERR
  9. utf8::all - turn on Unicode - all of it
    • Version: 0.025 on 2026-01-16, with 30 votes
    • Previous CPAN version: 0.024 was 8 years, 11 days before
    • Author: HAYOBAAN

(dcxxii) metacpan weekly report - Marlin

Niceperl

This is the weekly favourites list of CPAN distributions. Votes count: 89

Week's winner: Marlin (+6)

Build date: 2026/01/18 10:13:31 GMT


Clicked for first time:


Increasing its reputation:

Thank you Team PWC for your continuous support and encouragement.
Thank you Team PWC for your continuous support and encouragement.
Thank you Team PWC for your continuous support and encouragement.

JSON parse array of data

Perl questions on StackOverflow

I have the following program with JSON:

use strict;
use warnings;

use Data::Dumper qw( );
use JSON qw( );

my $json_text = '[
  {
    "sent": "2026-01-16T17:00:00Z",
    "data": [
      {
        "headline": "text1",
        "displayText": "text2"
      },
      {
        "displayText": "text3"
      },
      {
        "displayText": "text4"
      }
    ]
  },
  {
    "sent": "2026-01-16T17:00:00Z",
    "data": [
      {
        "headline": "text5",
        "displayText": "text6"
      },
      {
        "displayText": "text7"
      },
      {
        "displayText": "text8"
      },
      {
        "headline": "text9",
        "displayText": "text10"
      }
    ]
  }
]';

my $json = JSON->new;
my $data = $json->decode($json_text);

print Data::Dumper->Dump($data);

# This is pseudocode:
foreach ( $data->[] ) {
    print "\$_ is $_";
}

I would like to walk through elements in JSON and find all sent and all displayText values. But, I do not know how to dereference first element. First element is array without any name in this case.

Thunderhorse beta released!

dev.to #perl

Thunderhorse framework was just released as beta. Read more about it on my blog: https://bbrtj.eu/blog/article/thunderhorse-beta-released

Leveraging Gemini CLI and the underlying Gemini LLM to build Model Context Protocol (MCP) AI applications in Perl with a local development…

Leveraging Gemini CLI and the underlying Gemini LLM to build Model Context Protocol (MCP) AI applications in Perl with Google Cloud Run.


Dave writes:

During December, I fixed assorted bugs, and started work on another tranche of ExtUtils::ParseXS fixups, this time focussing on:

  • adding and rewording warning and error messages, and adding new tests for them;

  • improving test coverage: all XS keywords have tests now;

  • reorganising the test infrastructure: deleting obsolete test files, renaming the t/*.t files to a more consistent format; splitting a large test file; modernising tests;

  • refactoring and improving the length(str) pseudo-parameter implementation.

By the end of this report period, that work was about half finished; it is currently finished and being reviewed.

Summary: * 10:25 GH #16197 re eval stack unwinding * 1:39 GH #23903 BBC: bleadperl breaks ETHER/Package-Stash-XS-0.30.tar.gz * 0:09 GH #23986 Perl_rpp_popfree_to(SV sp**) questionable design * 3:02 fix Pod::Html stderr noise * 27:47 improve Extutils::ParseXS * 1:47 modernise perlxs.pod

Total: * 44:49 (HH::MM)


Tony writes:

``` [Hours] [Activity] 2025/12/01 Monday 0.23 memEQ cast discussion with khw 0.42 #23965 testing, review and comment 2.03 #23885 review, testing, comments 0.08 #23970 review and approve 0.13 #23971 review and approve

0.08 #23965 follow-up

2.97

2025/12/02 Tuesday 0.73 #23969 research and comment 0.30 #23974 review and approve 0.87 #23975 review and comment 0.38 #23975 review reply and approve 0.25 #23976 review, research and approve 0.43 #23977 review, research and approve

1.20 #23918 try to produce expected bug and succeed

4.16

2025/12/03 Wednesday 0.35 #23883 check updates and approve with comment 0.72 #23979 review, try to trigger the messages and approve 0.33 #23968 review, research and approve 0.25 #23961 review and comment 2.42 #23918 fix handling of context, testing, push to update,

comment on overload handling plans, start on it

4.07

2025/12/04 Thursday 2.05 #23980 review, comment and approve, fix group_end() decorator and make PR 23983 0.25 #23982 review, research and approve 1.30 #23918 test for skipping numeric overload, and fix, start

on force overload

3.60

2025/12/05 Friday

0.63 #23980 comment

0.63

2025/12/08 Monday 0.90 #23984 review and comment 0.13 #23988 review and comment 2.03 #23918 work on force overload implmentation

1.45 #23918 testing, docs

4.51

2025/12/09 Tuesday 0.32 github notifications 1.23 #23918 add more tests 0.30 #23992 review 0.47 #23993 research, testing and comment

0.58 #23993 review and comment

2.90

2025/12/10 Wednesday 0.72 #23992 review updates, testing and comment 1.22 #23782 review (and some #23885 discussion in irc) 1.35 look into Jim’s freebsd core dump, reproduce and find cause, email him and briefly comment in irc, more 23885

discussion and approve 23885

3.29

2025/12/11 Thursday 0.33 #23997 comment 1.08 #23995 research and comment 0.47 #23998 review and approve

1.15 #23918 cleanup

3.03

2025/11/15 Saturday 0.20 #23998 review updates and approve 0.53 #23975 review comment, research and follow-up 1.25 #24002 review discussion, debugging and comment 0.28 #23993 comment 0.67 #23918 commit cleanup 0.20 #24002 follow-up

0.65 #23975 research and follow-up

3.78

2025/12/16 Tuesday 0.40 #23997 review, comment, approve 0.37 #23988 review and comment 0.95 #24001 debugging and comment 0.27 #24006 review and comment 0.23 #24004 review and nothing to say

1.27 #23918 more cleanup, documentation

3.49

2025/12/17 Wednesday 0.32 #24008 testing, debugging and comment 0.08 #24006 review update and approve 0.60 #23795 quick re-check and approve 1.02 #23918 more fixes, address each PR comment and push for CI 0.75 #23956 work on a test and a fix, push for CI 0.93 #24001 write a test, and a fix, testing 0.67 #24001 write an inverted test too, commit message and push for CI 0.17 #23956 perldelta 0.08 #23956 check CI results, make PR 24010

0.15 #24001 perldelta and make PR 24011

4.77

2025/12/18 Thursday 0.27 #24001 rebase, local testing, push for CI 1.15 #24012 research 0.50 #23995 testing and comment

0.08 #24001 check CI results and apply to blead

2.00

Which I calculate is 43.2 hours.

Approximately 32 tickets were reviewed or worked on, and 1 patches were applied. ```


Paul writes:

A mix of focus this month. I was hoping to get attributes-v2 towards something that could be reviewed and merged, but then I bumped into a bunch of refalias-related issues. Also spent about 5 hours reviewing Dave's giant xspod rewrite.

  • 1 = Rename THING token in grammar to something more meaningful
    • https://github.com/Perl/perl5/pull/23982
  • 4 = Continue work on attributes-v2
  • 1 = BBC Ticket on Feature-Compat-Class
    • https://github.com/Perl/perl5/issues/23991
  • 2 = Experiment with refalias parameters with defaults in XS-Parse-Sublike
  • 1 = Managing the PPC documents and overall process
  • 2 = Investigations into the refalias and declared_refs features, to see if we can un-experiment them
  • 2 = Add a warning to refalias that breaks closures
    • https://github.com/Perl/perl5/pull/24026 (work-in-progress)
  • 3 = Restore refaliased variables after foreach loop
    • https://github.com/Perl/perl5/issues/24028
    • https://github.com/Perl/perl5/pull/24029
  • 3 = Clear pad after multivariable foreach
    • https://github.com/Perl/perl5/pull/24034 (not yet merged)
  • 6 = Github code reviews (mostly on Dave's xspod)
    • https://github.com/Perl/perl5/pull/23795

Total: 25 hours

Leveraging Gemini CLI and the underlying Gemini LLM to build Model Context Protocol (MCP) AI applications in Perl with a local development…

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::Greple - extensible grep with lexical expression and region handling
    • Version: 10.02 on 2026-01-09, with 56 votes
    • Previous CPAN version: 10.01 was 9 days before
    • Author: UTASHIRO
  2. App::Netdisco - An open source web-based network management tool.
    • Version: 2.097002 on 2026-01-09, with 818 votes
    • Previous CPAN version: 2.097001 
    • Author: OLIVER
  3. App::Sqitch - Sensible database change management
    • Version: v1.6.1 on 2026-01-06, with 3087 votes
    • Previous CPAN version: v1.6.0 was 3 months before
    • Author: DWHEELER
  4. CPANSA::DB - the CPAN Security Advisory data as a Perl data structure, mostly for CPAN::Audit
    • Version: 20260104.001 on 2026-01-04, with 25 votes
    • Previous CPAN version: 20251228.001 was 6 days before
    • Author: BRIANDFOY
  5. DateTime::Format::Natural - Parse informal natural language date/time strings
    • Version: 1.23 on 2026-01-04, with 19 votes
    • Previous CPAN version: 1.23 was 5 days before
    • Author: SCHUBIGER
  6. Firefox::Marionette - Automate the Firefox browser with the Marionette protocol
    • Version: 1.69 on 2026-01-10, with 19 votes
    • Previous CPAN version: 1.68 was 3 months, 26 days before
    • Author: DDICK
  7. GD - Perl interface to the libgd graphics library
    • Version: 2.84 on 2026-01-04, with 32 votes
    • Previous CPAN version: 2.83 was 1 year, 6 months, 11 days before
    • Author: RURBAN
  8. IO::Socket::SSL - Nearly transparent SSL encapsulation for IO::Socket::INET.
    • Version: 2.098 on 2026-01-06, with 49 votes
    • Previous CPAN version: 2.097 
    • Author: SULLR
  9. JSON::Schema::Modern - Validate data against a schema using a JSON Schema
    • Version: 0.632 on 2026-01-06, with 16 votes
    • Previous CPAN version: 0.631 was 12 days before
    • Author: ETHER
  10. MetaCPAN::Client - A comprehensive, DWIM-featured client to the MetaCPAN API
    • Version: 2.037000 on 2026-01-07, with 27 votes
    • Previous CPAN version: 2.036000 
    • Author: MICKEY
  11. MIME::Lite - low-calorie MIME generator
    • Version: 3.035 on 2026-01-08, with 35 votes
    • Previous CPAN version: 3.034 was 2 days before
    • Author: RJBS
  12. Module::Starter - a simple starter kit for any module
    • Version: 1.81 on 2026-01-09, with 34 votes
    • Previous CPAN version: 1.80 
    • Author: XSAWYERX
  13. Perl::Tidy - indent and reformat perl scripts
    • Version: 20260109 on 2026-01-08, with 147 votes
    • Previous CPAN version: 20250912 was 3 months, 26 days before
    • Author: SHANCOCK
  14. perlsecret - Perl secret operators and constants
    • Version: 1.018 on 2026-01-09, with 55 votes
    • Previous CPAN version: 1.017 was 4 years, 2 months before
    • Author: BOOK
  15. Type::Tiny - tiny, yet Moo(se)-compatible type constraint
    • Version: 2.010001 on 2026-01-06, with 148 votes
    • Previous CPAN version: 2.010000 was 7 days before
    • Author: TOBYINK
  16. UV - Perl interface to libuv
    • Version: 2.001 on 2026-01-06, with 14 votes
    • Previous CPAN version: 2.000 was 4 years, 5 months, 8 days before
    • Author: PEVANS

In a script I'm using constants (use constant ...) to allow re-use ion actual regular expressions, using the pattern from https://stackoverflow.com/a/69379743/6607497. However when using a {...} repeat specifier following such constant expansion, Perl wants to tread the constant as a hash variable.

The question is how to avoid that.

Code example:

main::(-e:1):   1
  DB<1> use constant CHARSET => '[[:graph:]]'

  DB<2> x "foo" =~ qr/^[[:graph:]]{3,}$/
0  1
  DB<3> x "foo" =~ qr/^${\CHARSET}{3,}$/
Not a HASH reference at (eval 8)[/usr/lib/perl5/5.26.1/perl5db.pl:738] line 2.
  DB<4> x "foo" =~ qr/^${\CHARSET}\{3,}$/
  empty array
  DB<5> x $^V
0  v5.26.1

According to https://stackoverflow.com/a/79845011/6607497 a solution may be to add a space that's being ignored, like this: qr/^${\CHARSET} {3,}$/x; however I don't understand why this works, because outside of a regular expression the space before { is being ignored:

  DB<6> x "foo" =~ qr/^${\CHARSET} {3,}$/x
0  1
  DB<7> %h = (a => 3)

  DB<8> x $h{a}
0  3
  DB<9> x $h {a}
0  3

The manual page (perlop(1) on "Quote and Quote-like Operators") isn't very precise on that:

For constructs that do interpolate, variables beginning with "$" or "@" are interpolated. Subscripted variables such as $a[3] or "$href->{key}[0]" are also interpolated, as are array and hash slices. But method calls such as "$obj->meth" are not.

foobar is a Perl script that prints to both standard output and standard error. In a separate Perl script echo-stderr, I run foobar and capture its standard error using IPC::Open3's open3 function, and simply echo it back.

Here's the code for echo-stderr:

#!/usr/bin/perl -w

use IPC::Open3;
use Symbol 'gensym';

$fh = gensym;
$pid = open3('STDIN', 'STDOUT', $fh, './foobar') or die "$0: failed to run ./foobar\n";

while ( <$fh> ) {
    print STDERR $_;
}

close $fh;
waitpid($pid, 0);

The result is that whatever foobar writes to standard error is printed, nothing that it writes to standard output is. And there is an error at the end:

<message written to STDERR>
<message written to STDERR>
...
Unable to flush stdout: Bad file descriptor

What is the reason for this error?

Software developed in Perl, using Catalyst DBIx JS SQL
Version Control SVN

App::HTTPThis: the tiny web server I keep reaching for

Perl Hacks

Whenever I’m building a static website, I almost never start by reaching for Apache, nginx, Docker, or anything that feels like “proper infrastructure”. Nine times out of ten I just want a directory served over HTTP so I can click around, test routes, check assets, and see what happens in a real browser.

For that job, I’ve been using App::HTTPThis for years.

It’s a simple local web server you run from the command line. Point it at a directory, and it serves it. That’s it. No vhosts. No config bureaucracy. No “why is this module not enabled”. Just: run a command and you’ve got a website.

Why I’ve used it for years

Static sites are deceptively simple… right up until they aren’t.

  • You want to check that relative links behave the way you think they do.

  • You want to confirm your CSS and images are loading with the paths you expect.

  • You want to reproduce “real HTTP” behaviour (caching headers, MIME types, directory handling) rather than viewing files directly from disk.

Sure, you can open file:///.../index.html in a browser, but that’s not the same thing as serving it over HTTP. And setting up Apache (or friends) feels like bringing a cement mixer to butter some toast.

With http_this, the workflow is basically:

  • cd into your site directory

  • run a single command

  • open a URL

  • get on with your life

It’s the “tiny screwdriver” that’s always on my desk.

Why I took it over

A couple of years ago, the original maintainer had (entirely reasonably!) become too busy elsewhere and the distribution wasn’t getting attention. That happens. Open source is like that.

But I was using App::HTTPThis regularly, and I had one small-but-annoying itch: when you visited a directory URL, it would always show a directory listing – even if that directory contained an index.html. So instead of behaving like a typical web server (serve index.html by default), it treated index.html as just another file you had to click.

That’s exactly the sort of thing you notice when you’re using a tool every day, and it was irritating enough that I volunteered to take over maintenance.

(If you want to read more on this story, I wrote a couple of blog posts.)

What I’ve done since taking it over

Most of the changes are about making the “serve a directory” experience smoother, without turning it into a kitchen-sink web server.

1) Serve index pages by default (autoindex)

The first change was to make directory URLs behave like you’d expect: if index.html exists, serve it automatically. If it doesn’t, you still get a directory listing.

2) Prettier index pages

Once autoindex was in place, I then turned my attention to the fallback directory listing page. If there isn’t an index.html, you still need a useful listing — but it doesn’t have to look like it fell out of 1998. So I cleaned up the listing output and made it a bit nicer to read when you do end up browsing raw directories.

3) A config file

Once you’ve used a tool for a while, you start to realise you run it the same way most of the time.

A config file lets you keep your common preferences in one place instead of re-typing options. It keeps the “one command” feel, but gives you repeatability when you want it.

4) --host option

The ability to control the host binding sounds like an edge case until it isn’t.

Sometimes you want:

  • only localhost access for safety;

  • access from other devices on your network (phone/tablet testing);

  • behaviour that matches a particular environment.

A --host option gives you that control without adding complexity to the default case.

The Bonjour feature (and what it’s for)

This is the part I only really appreciated recently: App::HTTPThis can advertise itself on your local network using mDNS / DNS-SD – commonly called Bonjour on Apple platforms, Avahi on Linux, and various other names depending on who you’re talking to.

It’s switched on with the --name option.

http_this --name MyService

When you do that, http_this publishes an _http._tcp service on your local network with the instance name you chose (MyService in this case). Any device on the same network that understands mDNS/DNS-SD can then discover it and resolve it to an address and port, without you having to tell anyone, “go to http://192.168.1.23:7007/”.

Confession time: I ignored this feature for ages because I’d mentally filed it under “Apple-only magic” (Bonjour! very shiny! probably proprietary!). It turns out it’s not Apple-only at all; it’s a set of standard networking technologies that are supported on pretty much everything, just under a frankly ridiculous number of different names. So: not Apple magic, just local-network service discovery with a branding problem.

Because I’d never really used it, I finally sat down and tested it properly after someone emailed me about it last week, and it worked nicely, nicely enough that I’ve now added a BONJOUR.md file to the repo with a practical explanation of what’s going on, how to enable it, and a few ways to browse/discover the advertised service.

(If you’re curious, look for _http._tcp and your chosen service name.)

It’s a neat quality-of-life feature if you’re doing cross-device testing or helping someone else on the same network reach what you’re running.

Related tools in the same family

App::HTTPThis is part of a little ecosystem of “run a thing here quickly” command-line apps. If you like the shape of http_this, you might also want to look at these siblings:

  • https_this : like http_this, but served over HTTPS (useful when you need to test secure contexts, service workers, APIs that require HTTPS, etc.)

  • cgi_this : for quick CGI-style testing without setting up a full web server stack

  • dav_this : serves content over WebDAV (handy for testing clients or workflows that expect DAV)

  • ftp_this : quick FTP server for those rare-but-real moments when you need one

They all share the same basic philosophy: remove the friction between “I have a directory” and “I want to interact with it like a service”.

Wrapping up

I like tools that do one job, do it well, and get out of the way. App::HTTPThis has been that tool for me for years and it’s been fun (and useful) to nudge it forward as a maintainer.

If you’re doing any kind of static site work — docs sites, little prototypes, generated output, local previews — it’s worth keeping in your toolbox.

And if you’ve got ideas, bug reports, or platform notes (especially around Bonjour/Avahi weirdness), I’m always happy to hear them.

The post App::HTTPThis: the tiny web server I keep reaching for first appeared on Perl Hacks.

(dlxxxi) 8 great CPAN modules released last week

Niceperl
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: 0.998003 on 2025-12-29, with 177 votes
    • Previous CPAN version: 0.998002 was 24 days before
    • Author: SKAJI
  2. App::Greple - extensible grep with lexical expression and region handling
    • Version: 10.01 on 2025-12-31, with 56 votes
    • Previous CPAN version: 10.00 was 19 days before
    • Author: UTASHIRO
  3. App::Music::ChordPro - A lyrics and chords formatting program
    • Version: v6.090.1 on 2026-01-03, with 432 votes
    • Previous CPAN version: v6.090.0 was 2 months, 3 days before
    • Author: JV
  4. CPANSA::DB - the CPAN Security Advisory data as a Perl data structure, mostly for CPAN::Audit
    • Version: 20251228.001 on 2025-12-29, with 25 votes
    • Previous CPAN version: 20251221.001 was 7 days before
    • Author: BRIANDFOY
  5. DBD::SQLite - Self Contained SQLite RDBMS in a DBI Driver
    • Version: 1.78 on 2026-01-02, with 107 votes
    • Previous CPAN version: 1.76 was 1 year, 2 months, 14 days before
    • Author: ISHIGAKI
  6. Module::Starter - a simple starter kit for any module
    • Version: 1.79 on 2026-01-03, with 33 votes
    • Previous CPAN version: 1.78 was 7 months, 30 days before
    • Author: XSAWYERX
  7. Type::Tiny - tiny, yet Moo(se)-compatible type constraint
    • Version: 2.010000 on 2025-12-30, with 148 votes
    • Previous CPAN version: 2.009_003 was 7 days before
    • Author: TOBYINK
  8. WebService::Dropbox - Perl interface to Dropbox API
    • Version: 2.10 on 2025-12-29, with 12 votes
    • Previous CPAN version: 2.09 was 4 years, 6 months, 14 days before
    • Author: ASKADNA

Horror Movie Month 2024

rjbs forgot what he was saying

Yesterday, I posted about the books I read in 2025, which made me remember that I never posted about the (horror) movies we watched in October 2024. So, I thought I’d get around to that. Of course this will be short and lossy, right? It’s been over a year.

Here’s what we watched for Horror Movie Month in 2024, at least according to my notes!

October 1: Raw (2016)

Girl goes to college, finally lets loose by becoming a cannibal. This movie was French and you’d know it even if you watched it dubbed. It was okay. It was worth my time.

October 2: Tragedy Girls (2017)

Two high school girls who are interested in death try to make more of it happen. It was a horror-comedy, and it was fun. Brianna Hildebrand, who you may remember as Negasonic Teenage Warhead, was in it.

October 4: V/H/S/Beyond (2024)

Honestly, apart from the 2025 one, most of the V/H/S movies are about the same to me: mixed bags, but usually not quite worth the whole watch. This one was that too. It had its moments.

October 5: Humanist Vampire Seeking Consenting Suicidal Person (2023)

Honestly, I’d watch just for “Want to see a French-Canadian horror movie?”

A young woman in a family of vampires really doesn’t want to go hunt for blood, but her parents have reluctantly become insistent. She decides she’ll look for somebody who’d be willing to donate.

It was good, and sort of a horror-comedy. It didn’t feel like every other movie, which was good.

October 6: Onyx the Fortuitous and the Talisman of Souls (2023)

I liked this the least of everybody in my household, I think. It was sometimes pretty funny, but the main character got on my nerves. I got the impression he is a YouTube character with some following, maybe? Like Ernest P. Worrell or other over the top “originally in small doses” characters, he was just too much here.

That said, we still make references to the guy’s catch phrase, so it stuck with us.

October 6: Cuckoo (2024)

This was one of the big hits of “general horror movies of 2024”, so I was glad we got to watch it. I liked it! It wasn’t perfect, but it did well at being one of those “Why can’t everybody else see how messed up this lovely place really is?” movies.

October 7: Let the Wrong One In (2021)

This movie was really stupid and I liked it. First off, there was a character named Deco, which made me think of The Commitments, which won points. Also, Anthony Stewart Head.

Basically it’s sort of a slapstick farcical vampire movie set in Ireland. Honestly, “What if [some successful movie] but the protagonists were idiots?” is a pretty good formula.

October 8: The Witches of Eastwick (1987)

Still a classic.

Sure, it’s kind of a mess here and there, but it’s got a great cast and it just goes for it. I read recently that there was talk about casting other people (other than Jack Nicholson) as Daryl Van Horne, which seems like it could only have been worse. One name mentioned was Bill Murray. What?! This was a nearly perfect vehicle for Jack Nicholson doing comedy, and Cher, Susan Sarandon, and Michelle Pfeiffer were a lot of fun, too.

The cherry scene!

October 9: Courtney Gets Possessed (2023)

I barely remember this one. I think it was funny enough? Demonic hijinks at a bachelorette party.

October 10: There’s Something Wrong with the Children (2023)

Two parents, their two kids, and an adult friend take a camping trip. The kids wander off in the woods and when they come back, they are… off. Things keep getting worse.

This was good. It wasn’t great, but it was good. You want to yell, “Wake up, people, your kids are busted!”

October 12: 6:45 (2021)

It took me a while to remember this one. It was okay. A couple take a ill-advised holiday to an island town, which leads to a deadly time loop. It was okay, but there are many better movies to watch instead. (Look, maybe it’s better than I remember, but given I barely remember it…)

October 13: Oddity (2024)

I didn’t remember this until reading the synopsis, but it was quite good. So maybe my “it’s bad because I don’t remember it” take above is wrong!

A woman is murdered at her secluded fixer-upper in the countryside. Later, her twin sister shows up and is really weird. What’s going on? You should just watch it, probably. Not a comedy.

October 14: Mr. Crocket (2024)

This is sort of like “what if there was a haunted video tape that showed you a cutesy TV show for kids, but also it was evil?” I wanted to like it, but it was just ugly. It wasn’t fun or funny, just dark. It wasn’t darkly funny, although maybe that was the goal.

October 15: Evil Dead Ⅱ (1987)

I think we watched this because Marty hadn’t seen it. Look, it’s fine. It’s a lot better than the first version. I think it’s just not exactly my bag. (I really like Bruce Campbell, though!)

October 16: Cube (2021)

I really liked Cube! This is not that movie, though, it’s a 2021 remake from Japan. Don’t bother. It is worse in every way. Maybe it’s okay, but it’s not significantly different, so go with the original.

October 18: Zombie Town (2023)

A reclusive movie director releases one more movie, and it turns everybody in town into zombies. Kids fight back.

This kind of movie could’ve been fun, but it wasn’t. It had two of the Kids in the Hall in it! What a waste.

October 19: The Finale (2023)

Oh yeah, this one.

Murders start happening at a summer theater camp. Everybody has a motive. Who did it?

Well, look, I think this was maybe better than the related Stage Fright, but it was bad. It was way too long. It was sometimes nonsensical. I do not recommend it.

October 19: Invitation to Hell (1984)

This gets huge points from me for “picked a weird premise and didn’t back down.” Wes Craven directs. A family moves to a new planned town where the father has taken a great new job. Everybody is obsessed with the local country club and its manager. Like, weirdly obsessed. What the heck is going on in town? Also, Robert Urich and Susan Lucci? Wild.

Not great, but I am glad I watched it.

October 20: Corporate Animals (2019)

A bunch of coworkers on a team-building exercise end up trapped in a cave. Demi Moore?! We had fun. It was stupid in a good way. The company specialized in edible cutlery, which paid off a few ways.

October 20: Stranger in Our House (1978)

Wes Craven again, this time with Linda Blair. It wasn’t great, sadly, and the concept has been done a bunch of times. Orphaned kid moves in with other family, and only one family member realizes that maybe this is a bad idea. It was… fine.

October 24: Little Evil (2017)

Adam Scott becomes the step-dad to the Antichrist and really tries to make things work. This was not amazing, but it was much better than I expected. I don’t mind having watched it, but I wouldn’t watch it again.

Good job casting the really creepy kid, though!

October 25: Deer Camp ‘86 (2022)

A bunch of guys go hunting and get into trouble. I remember nothing.

October 26: The Day of the Beast (1995)

A priest figures out how to predict the exact birth of the Antichrist, and enlists the help of a headbanger and a TV occultist to save the world. Was this a comedy on purpose? I just don’t know. It was weird, and unpredictable, and so I liked it.

October 27: The Strangers (2008)

What a lousy movie to end on. It’s a boring, tedious home invasion movie. I see it was 86 minutes long, but I remember it feeling much longer. Also, I think they remade it into a three part movie? I can’t imagine.

I just didn’t care about anyone or anything in this movie.

the books I read in 2025

rjbs forgot what he was saying

I don’t take the Goodreads “reading challenge” too seriously, but I did hit my target last year, and it felt good. I thought I’d try again this year and I did get it done – only just, though, as I finished my last three books in the last two days of the year. I think I would’ve liked to read a bit more through the year, but sometimes I just wasn’t feeling it. So it goes! I think this is a “structure your time” problem, but also it’s not the most pressing thing on my agenda, you know?

So, here’s what I read, not in order, and some brief notes.

Greg Egan

Last year, I read five Greg Egan books. This year, just two. First, I read The Book of All Skies, which I enjoyed. It’s the story of a group of people investigating the frontiers of their very weirdly-shaped world. As with many Egan books, there’s a lot of very weird math and physics under the hood, but it wasn’t critical to think too hard about them, and I think that made the story more enjoyable for me. In this book, they would’ve gotten in the way. That said, when I finished the book I went and read a bunch of Egan’s notes on the underlying ideas, which were interesting (insofar as I understood them).

Later, I read Schild’s Ladder, which was roughly the opposite. That is, it was one of the most physics-heavy Egan books I’ve read. More than once, I wanted to take photos of the page because it was a wall of thick jargon. I did not enjoy the book. At the beginning, I said, “Oh, this is going to be Egan’s take on Cat’s Cradle!” That would’ve been very interesting, especially because Egan and Vonnegut are so, so different. Or: maybe it was that, but I didn’t care to think about the comparison by the end. It reminded me of Vinge, too, but not in a way that excited me. Anyway, look, I’ve read a lot of Egan, and I will read more. This just didn’t hit home.

Effectiveness

“Effectiveness” is my shelf (or label or tag or whatever they call it now) in Goodreads for books on productivity and management. I have a lot of books in that queue, but I only make slow progress, for many reasons.

My favorite of the ones I read this year, by a long way, was Radical Candor. This is one of those books that I’d read about many times. It sounded not bad, but not amazing. But, of course, I’d only been seeing the shadows on the wall. It was great, and I hope I will go back to it in the future to try to puzzle out more ways to do better at my job. It really resonated with me, and I’ve brought it up over and over when talking to other managers, this year.

I also read Laziness Does Not Exist, which I didn’t love. It was okay. I feel the author would probably just give me a knowing “don’t you hear yourself??” look, but I kept wanting to say, “Yes, don’t work yourself sick, but honestly you are going too far.” I think the issue is that an indictment of a society-wide problem requires a massive-scaled critique. But “the Laziness Lie has you in its grip!”, over and over, was too much for me. (It was also funny that I finished this book just today, December 31st, and it had text saying “Don’t get worked up trying to meet your Goodreads goals”!)

Finally, as I wanted to get a bit more handle on some of my team’s rituals, I read Liftoff: Start and Sustain Agile Teams. I found it totally unremarkable, so I have no remarks.

Boss Fight Books

Boos Fight Books publishes short books about influential or otherwise important video games. The books are written by people who found the books to be important to them.

The first one I read was Animal Crossing by Kelsey Lewin. I’ve played all the main Animal Crossing games and have enjoyed them all. (Well, no, the iOS one was awful.) This book, at a pleasing 2⁸ pages, talked about the origin of the game, its weird launch history starting with the Nintendo64 DD, how it changed over time, and how the author enjoyed it (or didn’t) over time. I enjoyed the book, and felt like I’d read more like this – but it was also clear that a lot of the book was about the author’s life, which wasn’t really what I wanted. So, it wasn’t a bad book, it just wasn’t exactly what I wanted.

PaRappa the Rapper and ZZT books, which were similarly a mix of “I am very interested!” and “I am not particularly interested”. I knew what I was getting into, though, so I had no complaint for the authors. I just sort of wish there were more books about these games, focused more exclusively on the history and technology behind them.

I was surprised by how few of my peers remembered ZZT. I remember it being both impressive and influential. I was also surprised to learn how programmable its world builder was, and that ZZT (the game)’s author was that Tim Sweeney. (The book’s author was Anna Anthropy, which was one of the reasons I wanted to read this book.)

Finally, I read the book on Spelunky. I almost didn’t, but then I saw that the author was Derek Yu, also the primary creator of Spelunky itself! This book was by far closest to what I’d want from these books, if I was in charge. I got a copy for my nephews, too, who I introduced to the game a few years ago.

Stephen King

I read three Stephen King books this year, all story collections. I’ve been trying to catch up on reading all his story collections, and I’m very nearly done, now.

First, Four Past Midnight, from 1990. It contains four novellas, all of which I liked okay. I read it in part because I’d been doing some idle research into King’s repeated setting of Castle Rock, and saw that The Sun Dog (a story in this collection) was in some ways tied up with Needful Things.

After that, I read Hearts in Atlantis. This was a frustrating experience, because I kept thinking that maybe I’d read it already, twenty years ago, but I couldn’t be sure. This was extra frustrating because it seemed to me like one of King’s best books. Structurally and textually, it was excellent. I would recommend this to somebody who wasn’t sure they wanted to read Stephen King.

Finally, You Like It Darker. This is a collection of short stories published just last year. It was good! I enjoyed just about all of it, maybe most especially the final three stories. One of these was a sequel to Cujo, which I definitely did not expect to be reading!

Technical Books

This year, I’ve become the full-time lead of Fastmail’s Cyrus team. A big part of my team’s work is maintaining the open source Cyrus IMAP server. It’s written in C. My C is miserable, and was probably at its best in 1992. I need to get better. I read two C books this year: Effective C and Understanding and Using C Pointers. I think both were fine, but it’s hard to say. I’m not writing much C, day to day, so probably some of what I learned has already faded away. Still, I thought they were both clear and explained a bunch of topics that I hadn’t understood or only barely understood. Hard to judge, but definitely not bad. I can imagine going back to them later, when doing real work.

I already read tmux 3, a book about tmux. I like tmux quite a lot, and this isn’t the first little book I’ve read about it. It’s hard for me to say what I thought of it. I think it was a bit of a mish-mash for me. I was coming to it with a pretty long history with tmux, so lots of things were old hat and not worth my time. But as with many complex tools, even among the fundamentals there were lots of things I didn’t know. Here’s my biggest praise for the book: After I read it, I went back to a few sections I’d flagged and worked through my .tmux.conf, making improvements based on what the book taught me.

Slough House

Okay, so my biggest category of books was the Slough House series by Mick Herron. A full third of the books I read this year were these books.

Here are the titles:

  • Dead Lions
  • Real Tigers
  • Standing by the Wall
  • Spook Street
  • Nobody Walks
  • London Rules
  • Joe Country
  • Slough House
  • Bad Actors
  • The Secret Hours
  • Reconstruction
  • Clown Town

Look, they’re all very good. That’s why I read them! The only notable exception, I think, is Reconstruction. It’s fine. It’s just the least Slough House-y book, really tied in only by one character, and structured very differently from the rest. I’d almost recommend skipping it. It was a bit of a bummer that it was the last one I read for months. The last one I read, Clown Town, was only released this year, and I read it roughly immediately. (Thanks, Gloria, for giving me a surprise copy!)

Other Fiction

I read Thorns by Robert Silverberg, which was a 1967 nominee for the Nebula and Hugo. I can’t remember why I read it. I think it got onto my reminders list ages ago, and then it was on deep discount. I would’ve done better to just not read it. In 1967, it may have been interesting, but it didn’t age well.

I read How Long ‘til Black Future Month? by N.K. Jemisin, whose massively successful Broken Earth series I enjoyed a few years ago. This is a short story collection, and I’m a sucker for a good short story collection. And this was good. I’m told that LeVar Burton read two of these stories on his podcast LeVar Burton Reads, and I look forward to listening to them.

A few years ago, I finally read A Fire Upon the Deep, by Vinge. It was excellent, with a sprawling scope, a complex and coherent setting, and a whole mess of interesting ideas that all slotted together. Mark Dominus told me that the sequel, A Deepness in the Sky, was even better, but “very lonesome”. I agree! Vinge’s ability to spin so many plates, each one interesting on its own, and then to land them all into one neat pile was impressive and satisfying.

I read Ship Breaker and its sequel, The Drowned Cities, by Paolo Bacigalupi. They were okay, but I didn’t bother with the third book. Bacigalupi’s sci-fi work for adults is very good, and I’ve re-read a bunch of it. (I don’t think I re-read Pump 6 in its entirety this year, but I re-read a bunch of it.) The Ship Breaker books are young adult fiction, and all I could see on the page was all the depth and nuance missing compared to his other work. It probably would’ve been better when I was twelve. Given that it’s a book for that audience, who am I to complain?

I read Dungeon Crawler Carl because Bryan was reading it and said it sounded fun. It was fun, but I think too long for me. Everything about it was just a bit much. That could’ve been fun for two short books or so, but it was the first book in a seven book series, with books topping six hundred pages. I tapped out, and will probably read a summary some day.

Finally, I read Virtual Unrealities, a sci-fi story collection by the great Alfred Bester. I think I picked it up because I wanted to read Fondly Farenheit, which was good. I read it in the first week of January, so it’s been a while and I don’t remember it terribly well. My recollection was that I thought it was okay, but on the whole not anywhere near as good as The Demolished Man or The Stars My Destination. That’s the problem with writing massive, incredible successes, I guess!

Other Nonfiction

The Society of the Spectacle is the longest 150 page book I’ve ever read. According to Goodreads, I spent almost nine years reading it. It’s a lot, but it’s very good, and I think I will re-read parts of it again, probably several times. It’s one of the key texts of Situationism, a movement in post-WWII European socialism. The book is made up of 221 numbered paragraphs, which construct and explain the concept of “the spectacle”, a 20th (and, I’d say, 21st) conception of the problems of capitalism and, to an extent, imagined solutions. It’s short, but each paragraph deserves a good long think. You can’t just sit down and read the book in an afternoon the way you could a 150 page book about Animal Crossing.

For a long time, I have wanted to read more detailed writing on the Noble Eightfold Path, so I finally did. I read The Noble Eightfold Path: Way to the End of Suffering by Bhikku Bodhi. I’m glad I did, but it’s not easy to recommend generally. First, you need to be interested in Buddhism in general. Then, you need to have read enough about it (I think) that you want to read what is almost a technical manual about some of the core tenets. It’s a bit like reading a catechism, in which serious religious, metaphysical, and practical questions are answered in great and careful detail for the dedicated lay reader. I wish it had been a bit more focused on description and less on instruction. That is: I wanted to read analysis of and relationship between the eight practices, rather than a book intended to convince me of their importance. Still, this got close and I’m glad I read it.

What’s next?

I have no idea! Well, not much of an idea. Goodreads reminds me that I’m currently reading books about Eiffel, Rust, and WebAssembly. I received a few books for Christmas, and of course I already have a huge backlog of owned and unread books. There are just a few Egan novels I haven’t read yet. Lots of books remain on my “effectiveness” shelf. We’ll see where the year takes me.

One thing is seeming increasingly likely, though. I’ve read Gene Wolfe’s Book of the New Sun three (I think) times, now. These books get better as you re-read them and try to work out the many mysteries within them. Last time I read them, I thought, “When I read these again, it will be with a notebook for taking notes.” I think this is the year. I might also finally listen to ReReading Wolfe an epic-length podcast that goes through the books chapter-by-chapter, just for people who are re-reading the books, so spoilers a-plenty. I’ve been thinking about trying to find old hardback copies of the books to mark up, but it seems like most of them are quite expensive!

At any rate, maybe in a year I’ll write another blog post like this one. If I do, I hope it will be able to mention at least 36 books I’ve read in 2026.

In an attempt to avoid switch /x for a complex regular expression, I tried to replace qr/string/ with the following expression:

(map { qr/$_/ } ("a more" . "complex regex"))[0]

As the latter expression uses double quoted strings, I thought I would have to duplicate any backslash that should go into the qr operator. Because of that, I tried something like this:

(map { qr/$_/ } (
  "^Load key \"\\Q$host_CA\\E\": " 
  . 'incorrect passphrase supplied ' 
  . "to decrypt private key$CRLF"
))

However, Perl 5.26 complains with the following error message:

Unrecognized escape \Q passed through in regex; marked by <-- HERE in m/^Load key "\Q <-- HERE ...

It seems I don't have to duplicate the backslash, but I don't understand why. The following examples illustrate the behavior I am seeing:

DB<3> $x='f*o'

DB<4> x qr/\Q$x\E/
0  (?^u:f\\*o)
   -> qr/(?^u:f\*o)/

DB<5> x map { qr/$_/ } ("\\Q$x\\E/")
0  (?^u:\\Qf*o\\E/)
   -> qr/(?^u:\Qf*o\E\/)/

DB<6> x map { qr/$_/ } ("\Q$x\E/")
0  (?^u:f\\*o/)
   -> qr/(?^u:f\*o\/)/
As preparations are underway for the Perl Toolchain Summit 2026, this short episode is the last excerpt recorded during PTS 2025 (as a tangent during the CPAN Testers interview, published as episode 6). BooK starts by explaining the selection process for the Perl Toolchain Summit and some of the history, and then Doug, Ruth, Breno and Ferki reminisce about what makes the event so special.

(dlxxx) 6 great CPAN modules released last week

Niceperl
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.438 on 2025-12-25, with 18 votes
    • Previous CPAN version: 2.437_05 was 7 days before
    • Author: KUERBIS
  2. Convert::Pheno - A module to interconvert common data models for phenotypic data
    • Version: 0.29 on 2025-12-23, with 15 votes
    • Previous CPAN version: 0.28 was 8 months, 4 days before
    • Author: MRUEDA
  3. Devel::MAT - Perl Memory Analysis Tool
    • Version: 0.54 on 2025-12-26, with 30 votes
    • Previous CPAN version: 0.53 was 1 year, 9 months, 19 days before
    • Author: PEVANS
  4. Finance::Quote - Get stock and mutual fund quotes from various exchanges
    • Version: 1.68 on 2025-12-21, with 145 votes
    • Previous CPAN version: 1.68 was 3 days before
    • Author: BPSCHUCK
  5. HTTP::Tiny - A small, simple, correct HTTP/1.1 client
    • Version: 0.092 on 2025-12-27, with 115 votes
    • Previous CPAN version: 0.091 was 14 days before
    • Author: HAARG
  6. JSON::Schema::Modern - Validate data against a schema using a JSON Schema
    • Version: 0.631 on 2025-12-25, with 16 votes
    • Previous CPAN version: 0.630 was 10 days before
    • Author: ETHER

I am developing a Virtualmin plugin. But the problem is to have a link appear under the "Manage Virtual Server" category in the Virtualmin sidebar whenever the feature is enabled for a virtual server (domain).

Despite following the standard plugin structure, the menu item refuses to appear in the Virtualmin UI, although the module is accessible if I manually type the URL or find it in the Webmin "Tools" section (when not hidden).

Environment

  • OS: Ubuntu 22.04 / 24.04
  • Virtualmin version: Latest
  • Webmin version: Latest

File Structure

/usr/share/webmin/my-plugin-folder/

  • index.cgi
  • module.info
  • virtual_feature.pl
  • ...

Relevant Code

virtual_feature.pl

require 'my-plugin-lib.pl';

sub feature_name {
    return "plugin_name";
}

sub feature_label {
    return "Plugin Name";
}

sub feature_disables {
    return 1;
}

sub feature_check {
    return undef;
}

sub feature_setup {
    my ($d) = @_;
    return undef;
}

sub feature_links {
    my ($d) = @_;
    # This is intended to place the link under "Manage Virtual Server"
    return ({ 'mod' => $module_name,
              'desc' => "Plugin Name",
              'page' => "index.cgi?dom=" . $d->{'id'},
              'cat' => 'server' }); 
}

1;

module.info

desc=Plugin Name Tool
os_support=*-linux
version=1.6
category=server
depends=virtual-server
virtualmin=1
hidden=1

Expected Behavior

After enabling the feature globally in System Settings -> Features and Plugins, a link should appear in the left-hand sidebar under the "Manage Virtual Server" category.

Actual Behavior

The feature shows up in the "Enabled features" list and can be toggled/saved successfully. However, the link never appears in the sidebar. No errors are logged in /var/webmin/miniserv.error.

What I have tried

  1. Restarting Webmin (/etc/webmin/restart).
  2. Hardcoding the module folder name in the 'mod' field of feature_links.
  3. Changing the 'cat' field to 'services' or 'logs'.
  4. Refreshing the Webmin module cache.
  5. Verifying that the feature is indeed marked as enabled in the domain's configuration file in /etc/webmin/virtual-server/domains/.

Is there a specific registration step or a required function in virtual_feature.pl that I am missing for the sidebar injection to work correctly in recent versions of the Virtualmin Authentic Theme?

JSON::Schema::Validate

Perl Maven

At an online event through the Perl Maven group we tried to understand this module and even to contriute to it. For more details about the contributions check out the OSDC Perl page.

This example is based on the one in the documentation of the JSON::Schema::Validate and tweaked a bit. It will be useful again if we continue dealing with this module.

examples/json_schema_validate.pl

use JSON::Schema::Validate;
use JSON ();
use open qw( :std :encoding(UTF-8) );
my $schema = {
    '$schema' => 'https://json-schema.org/draft/2020-12/schema',
    '$id'     => 'https://example.org/s/root.json',
    type      => 'object',
    required  => [ 'name' ],
    properties => {
        name => { type => 'string', minLength => 5 },
        next => { '$dynamicRef' => '#Node' },
    },
    '$dynamicAnchor' => 'Node',
    additionalProperties => JSON::false,
};
my $js = JSON::Schema::Validate->new( $schema )
    ->compile
    ->content_checks
    ->ignore_unknown_required_vocab
    ->prune_unknown
    ->register_builtin_formats
    ->trace
    ->trace_limit(200) # 0 means unlimited
    ->unique_keys; # enable uniqueKeys

    #my $data = {
    #    name => 'head',
    #    next => {
    #        name => 'tail'
    #    }
    #};
    #my $data = {
    #    name => 23,
    #    next => {
    #        name => 'tail'
    #    }
    #};
    #my $data = {
    #    name => 'head',
    #};
my $data = {
    name => 'head big',
};


my $ok = $js->validate($data)
    or die( $js->error );
print "ok\n";