Koha Open Source Ambassadors Initiative and its benefits for Perl - Andrii Nugged - TPRC 2024

The Perl and Raku Conference YouTube channel

Published by The Perl and Raku Conference - Las Vegas, NV 2024 on Tuesday 16 July 2024 07:27

perlguts: Remove relic perlapi-like line

Perl commits on GitHub

Published by khwilliamson on Tuesday 16 July 2024 00:00

perlguts: Remove relic perlapi-like line

This line was added by me in 6ef63541071 by mistake. This was left over
from some arrested development.

embed.fnc: Clarify comment

Perl commits on GitHub

Published by khwilliamson on Monday 15 July 2024 23:53

embed.fnc: Clarify comment

Perl Weekly Challenge 278: Sort String

blogs.perl.org

Published by laurent_r on Monday 15 July 2024 22:33

These are some answers to the Week 278, Task 1, of the Perl Weekly Challenge organized by Mohammad S. Anwar.

Spoiler Alert: This weekly challenge deadline is due in a few days from now (on July 21, 2024, at 23:59). This blog post provides some solutions to this challenge. Please don’t read on if you intend to complete the challenge on your own.

Task 1: Sort String

You are given a shuffle string, $str.

Write a script to return the sorted string.

A string is shuffled by appending word position to each word.

Example 1

Input: $str = "and2 Raku3 cousins5 Perl1 are4"
Output: "Perl and Raku are cousins"

Example 2

Input: $str = "guest6 Python1 most4 the3 popular5 is2 language7"
Output: "Python is the most popular guest language"

Example 3

Input: $str = "Challenge3 The1 Weekly2"
Output: "The Weekly Challenge"

There are a number of ways this could go wrong with faulty input. We will not try to validate the input, and we will assume correct input.

Sort String in Raku

We first split the input string into space-separated words, using the words method. We then use a regex to capture separately the letters and the digits, and store the letters in the @positions array, at the index given by the digit part.

sub sort-string ($in) {
    my @positions;
    for $in.words -> $word {
        $word ~~ m/(\D+)(\d+)/;
        @positions[$/[1]] = ~$/[0];

    }
    return "@positions[1..@positions.end]";
}
my @tests = "and2 Raku3 cousins5 Perl1 are4", 
            "guest6 Python1 most4 the3 popular5 is2 language7",
            "Challenge3 The1 Weekly2";
for @tests -> $test {
    say $test;
    say sort-string $test;
    say "";
}

This program displays the following output:

$ raku ./sort-sting.raku
and2 Raku3 cousins5 Perl1 are4
Perl and Raku are cousins

guest6 Python1 most4 the3 popular5 is2 language7
Python is the most popular guest language

Challenge3 The1 Weekly2
The Weekly Challenge

Sort String in Perl

This is a port to Perl of the above Raku program. Here, the words are separated using the split built-in function. Then, we use regular expression captures to retrieve the alphabetical part and the numeric part, which are then stored into the @positions array.

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

sub sort_string {
    my @positions;
    my @words = split /\s+/, shift;
    for my $word (@words) {
        my ($letters, $digits) = ($word =~ m/(\D+)(\d+)/);
        $positions[$digits] = $letters;

    }
    return "@positions[1..$#positions]";
}
my @tests = ("and2 Raku3 cousins5 Perl1 are4", 
            "guest6 Python1 most4 the3 popular5 is2 language7",
            "Challenge3 The1 Weekly2");
for my $test (@tests) {
    say $test;
    say sort_string $test;
    say "";
}

This program displays the following output:

$ perl  ./sort-sting.pl
and2 Raku3 cousins5 Perl1 are4
Perl and Raku are cousins

guest6 Python1 most4 the3 popular5 is2 language7
Python is the most popular guest language

Challenge3 The1 Weekly2
The Weekly Challenge

Wrapping up

The next week Perl Weekly Challenge will start soon. If you want to participate in this challenge, please check https://perlweeklychallenge.org/ and make sure you answer the challenge before 23:59 BST (British summer time) on July 28, 2024. And, please, also spread the word about the Perl Weekly Challenge if you can.


Paul writes: ``` My time was almost entirely consumed during April and May by running a stage show, and then June by travelling the entire length of the country supporting a long-distance bicycle adventure; as such I didn't get much Perl work done and I've only just got around to writing out what few things I did get done.

Entirely related to a few last pre-release steps to get features nicely lined up for the 5.40 release:

Hours:

5 = Stablise experiments for perl 5.40 https://github.com/Perl/perl5/pull/22123

1 = Fix perlexperiment.pod; create v5.40 feature bundle https://github.com/Perl/perl5/pull/22141

1 = Bugfix for GH22278 (uninitialised fields during DESTROY) https://github.com/Perl/perl5/pull/22280

Total: 7 hours

I'm now back to the usual schedule, so I hope to have more to work on for July onwards... ```

The Perl and Raku Conference 2024 - Las Vegas

r/perl

Published by /u/oalders on Monday 15 July 2024 17:39

I am new to shell scripting and I ran into an issue with the following. I am trying to create a type of script which is able to replace multiple lines in a file with another set of multiple lines (with a different size)

I tried to create a text file with the multi-line string i would like to replace (before.txt), a file with a multiline string of the text I would like to see (after.txt) and the original file (original.yml.new). The files contain the following information/structure. (sidenote: As you can see, the files contain some 'weird' symbols like | ; . : / _)

before.txt:

      - range: XXX.YYY.ZZZZ  
        options: |
          deny dynamic bootp clients;
          allow unknown-clients;       
      - range: dynamic-bootp AAA.BBB.CCC.
        options: |
          allow dynamic bootp clients;
          option root-path "KKK.LLL.MMM:/000.000.000";
          filename "ABCDEF";
          allow unknown-clients;          
    - tag: s_net

After.txt:

      - range: XXX.YYY.ZZZZ  
        options: |
          deny dynamic bootp clients;
          allow unknown-clients;      
          deny members of "cid_xxx.yyy.zzz"; 
      - range: dynamic-bootp AAA.BBB.CCC.
        options: |
          allow dynamic bootp clients;
          option root-path "KKK.LLL.MMM:/000.000.000";
          filename "ABCDEF";
          allow unknown-clients; 
          deny members of "cid_xxx.yyy.zzz";         
    - tag: s_net

original.yml.new:

[Some random number of strings]
      - range: XXX.YYY.ZZZZ  
        options: |
          deny dynamic bootp clients;
          allow unknown-clients;       
      - range: dynamic-bootp AAA.BBB.CCC.
        options: |
          allow dynamic bootp clients;
          option root-path "KKK.LLL.MMM:/000.000.000";
          filename "ABCDEF";
          allow unknown-clients;          
    - tag: s_net
[Some random number of strings]

I've tried to follow the info provided in text and made this oneliner code:

perl -i -0 -p0e "s/$(cat before.txt)/$(cat after.txt)/se" original.yml.new

Output yields:

Number found where operator expected at -e line 1, near "123.456.789.000 123.654.127.172"
    (Missing operator before  123.654.127.172?)
syntax error at -e line 1, near "range:"
Execution of -e aborted due to compilation errors.

Hope I have provided sufficient information :)

When I render the following,

=over 12

=item foo bar

baz1 baz1

baz2 baz2

=item foo bar foo bar foo bar

baz1 baz1

baz2 baz2

=back

I get,

    foo bar     baz1 baz1

                baz2 baz2

    foo bar foo bar foo bar
                baz1 baz1

                baz2 baz2

Notice how on one of the lines baz1 baz1 is pulled to the top, on the other it isn't. Is this behavior specified anywhere. The command paragraph consuming the following line if it fits within the "Indent Level" is not documented in perldoc perlpod is there another source that specifies if this is right? This is also not flagged by podchecker.

cpan/podlators - Update to version v6.0.2 (with v6.0.1 and v6.0.0)

v6.0.0 - 2024-07-10

 - Drop support for Perl 5.10.  podlators now requires Perl 5.12 or later.

 - podlators now uses semantic versioning for the package and module
   versions, with a v prefix to work with Perl's packaging system.

 - Pod::Man now translates all "-" characters in the input into *roff "\-"
   escapes (normally rendered as an ASCII hyphen-minus, U+002D) rather
   than using fragile heuristics to decide which characters represent true
   hyphens and which represent ASCII hyphen-minus.  The previous
   heuristics misrendered command names such as apt-get, causing search
   and cut-and-paste issues.  This change may cause line-break issues with
   long hyphenated phrases.  In cases where the intent is a true hyphen,
   consider using UTF-8 as the POD character set (declared with =encoding)
   and using true Unicode hyphens instead of the ASCII "-" character.

 - Pod::Man now disables the special *roff interpretation of "`" and "'"
   characters as paired quotes everywhere, not just in verbatim text, thus
   forcing them to be interpreted as the regular ASCII characters.  This
   also disables the use of "``" and "''" for paired double-quotes.  The
   rationale is similar to that for hyphens: there is no way to tell from
   the POD source that the special interpretation as quotes is intended.
   To produce paired typographic quotes in the output, use UTF-8 and
   Unicode paired quote characters.

 - Man page references in L<> that are detected as such by Pod::Simple are
   now always formatted as man page references even if our normal
   heuristic would not detect them.  This fixes the formatting of
   constructions such as @@RXVT_NAME@@perl(3), which are used by packages
   that format a man page with POD and then substitute variables into it
   at build time.  Thanks to Marco Sirabella for the analysis and an
   initial patch.  (GitHub #21)

 - Add a workaround to Pod::Man to force persistent ragged-right
   justification under nroff with groff 1.23.0.  Thanks to Guillem Jover
   for the report and G. Branden Robinson for the analysis.  (GitHub #23)

 - Fix wrapping of text with S<> markup in all subclasses of Pod::Text.
   Thanks to Jim Avera for the report.  (GitHub #24)

 - Pod::Man now forces a blank line after a nested list contains only
   =item tags without bodies.  In previous versions, the blank line before
   the next item in the surrounding =over block was not included.  Thanks
   to Julien ÉLIE for the report.  (GitHub #26)

 - Import PerlIO before checking for layers so that PerlIO::F_UTF8 is
   available, which fixes double-encoding of output when a :utf8 layer is
   in place and PerlIO is not imported.  Thanks to youpong for the bug
   report, James Keenan for the elaboration, and Graham Knop for the fix.
   (GitHub #25)

 - pod2text --help now exits with status 0, not 1, matching normal UNIX
   command behavior and the behavior of pod2man.  (GitHub #19)

 - Fix tests when NO_COLOR is set in the environment.  (GitHub #20)

v6.0.1 - 2024-07-12

 - Remove autodie from the module build process.  When built as part of
   Perl core, podlators is built before autodie is available.  Thanks to
   James E Keenan for the report and a draft patch.  (GitHub #33)

v6.0.2 - 2024-07-14

 - Fix removal of scripts/pod2man and scripts/pod2text by make realclean,
   broken in the v6.0.0 release.  Thanks to James E Keenan for the report.

Remove CUSTOMIZED element for podlators

Perl commits on GitHub

Published by jkeenan on Monday 15 July 2024 10:37

Remove CUSTOMIZED element for podlators

To prepare for sync with cpan.

How can I change app_url of Perl Kelp App

Perl questions on StackOverflow

Published by Sangyong Gwak on Monday 15 July 2024 08:22

I want to change app_url.

I did it as follows:

package Post;
use Kelp::Base 'Kelp';

use utf8;

sub before_dispatch {
    # overriding this method disables access logs
}

sub build {
    my $self = shift;
    
    $self->config_hash->{app_url}='https://perl-kelp.sys5.co';

It seems to work. Is this a good way?

Perl Weekly #677 - Reports from TPRC 2024

dev.to #perl

Published by Gabor Szabo on Monday 15 July 2024 05:22

Originally published at Perl Weekly 677

Hi there!

In case you missed it earlier there plenty of videos from The Perl and Raku Conference in Las Vegas that you can watch.

There is also a thread on Reddit answering the question: Perl and why you use it.

First time I taught Perl was in the year 2000. It was one of the local training companies that hired me, gave me their teaching material, and sent me in the classroom. I remember standing in front of the class for some time that felt ages without any clue what to say. Then somehow I started to speak. Apparently the course went well enough as they asked me to teach again. Since then a lot has happened. I created my own training materials. I started to offer my courses directly to the clients, and I taught Perl to more than a 1,000 people. Both in Israel and in some other countries. It was really nice. It let me travel to Perl conferences and workshops around the world and meet nice people. Unfortunately there are hardly any Perl training courses these days and unless there are some major changes in the language I don't expect this to change.

I am mentioning this because this week is the first time I am teaching an in-person Rust course. Interestingly, to a bunch of Python programmers who are switching from Python to Rust. I am both nervous and excited. I am excited as I love learning and the explaining new technologies and there is a lot to learn in Rust. There is also more to teach in Rust as it is much harder to learn than Perl or Python.

Anyway

Enjoy your week!

--
Your editor: Gabor Szabo.

Event reports

The Perl and Raku Conference 2024 - Las Vegas

The report of Keith Carangelo.

Fear and loathing at YAPC

Despite being the worst attended YAPC in recent memory, 2024's show in Vegas had some of the best talks in a long while.

Virtual presentations for Perl developers

Continuous Integration (CI): GitHub Actions for Perl Projects (Free Virtual presentation on August 4)

This events was postponed to August 4. In this virtual event you will learn why and how to use GitHub Actions as a CI system for your Perl projects. The meeting is free of charge thanks to my supporters via Patreon and GitHub. Besides this event I am running many more, so make sure you check the Code Mavens meetup group and also register to it.

GitHub Pages for Perl developers (Free Virtual presentation on August 15)

In this virtual event you will learn how to use Markdown and GitHub Pages to create a simple web site and then we'll extend our use of GitHub Actions to generate the site using Perl. Register now!

Articles

The Quest for Performance Part IV : May the SIMD Force be with you

See discussion on reddit

A p5p discussion about adding :writer to perlclass

Using Coro and AnyEvent Interactively

I have not been able to figure out how to run an async thread in the background while using a REPL like reply. The moment I run the main loop, it takes over the input from the REPL. Here's what a typical failed REPL session might look like.

Migrating from MySQL to PostgreSQL

Perl and why you use it

Perl script to write into the Fediverse (and Nostr)

apparently NUL is mostly whitespace in Perl?

How to use perl v5.40's boolean builtins in Mojo::Pg queries

Grants

Maintaining Perl 5 Core (Dave Mitchell): June 2024

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

Welcome to a new week with a couple of fun tasks "Sort String" and "Reverse Word". 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 - 277

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

TWC277

CPAN modules can be very handy to get you elegant one liner. Thanks for sharing the knowledge with us.

Count the Common Ones and the Strong Pairs

Erlang is the surprise guest language this week. I love the simple narrative, it is so easy to follow. Keep sharing.

Strong Count

Another cool use case for Bag of Raku magics. The end result is one-liner. Great, keep it up.

Strength Uncombined

Bag for Perl can be found in CPAN module Set::Bag. CPAN is the rockstar. Highly recommended.

Perl Weekly Challenge: Week 277

The one liner in the end of the post is the gem of code. Great work, thanks for sharing.

Common Strength

Simple for loop showing the power and getting the job done. Simple yet powerful, keep it up.

Perl Weekly Challenge 277: Count Common

Another example of how to port Bag of Raku in Perl. Great work for spreading the knowledge.

Perl Weekly Challenge 277: Strong Pair

Raku's combinations method is so handy and make the code compact. In Perl, simple for loop is enough. Thanks for sharing.

Perl Weekly Challenge 277

Master of inhouse Perl one-liners sharing great example. You really don't want to miss it. Well done.

They call me the count, because I love to count pairs! Ah, ah, ah!

Another cool use of CPAN module, simple and easy interface to get the job done. Thanks for sharing.

Commons and pairs

Cute little solutions in Perl. So simple yet very easy to follow. Keep it up great work.

The Weekly Challenge - 277

Full on demo of CPAN modules. Happy to see the popularity among team members. Well done and keep it up.

The Weekly Challenge #277

No gimmicks, pure Perl solution using just core functions. The end result is still very powerful. Thanks for sharing.

A Strong Count

PostScript is getting regular space these days in the weekly post. I enjoy reading the code and learning too. Thanks for your contributions.

Strong counting

Today, I learnt how to declare type for list of list in Python. Thanks for sharing knowledge every week.

Weekly collections

NICEPERL's lists

Great CPAN modules released last week;
MetaCPAN weekly report;
StackOverflow Perl report.

Events

Continuous Integration (CI): GitHub Actions for Perl Projects

August 4, 2024, in Zoom

Toronto Perl Mongers monthly meeting

July 25, 2024, Virtual event

London Perl and Raku Workshop

October 26, 2024, in London, UK

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.

TWC 277: Strength Uncombined

blogs.perl.org

Published by Bruce Gray on Monday 15 July 2024 01:12

In which thousands become millions, as we achieve a near-linear solution.

TWC Task #1 - Count Common

Task:

Given two arrays of strings, return the count of words that appears in both arrays exactly once.

Observations:

  • The task specifies two input arrays, but is easier to express once we allow for unlimited input arrays.

  • The input arrays cannot just be flattened/combined and counted, or we will lose the distinction between count==2 meaning "one in each sentence" vs "two in one sentence". However, there is no example highlighting this incorrect approach. I have added the test: ( 1, <Perl is Perl>, <Java is not> ).

Raku

Map each array of strings into a Set of words and a list of words that occur more than once, subtracting the list from the Set to create a new Set of only words occurring once in the array. Then, take the intersection of (all) those Sets via reduce(spelled [∩]), and return the size of that intersection by +.

sub task1 ( @LoLists --> UInt ) {
    return +[∩] map { .Set (-) .repeated }, @LoLists;
}

After doing the Perl solution below, I realized that while .Set (-) .repeated is concise inside the map, a change to .Bag.grep(*.value == 1).Set would make the task clearer to a maintenance programmer. I left it unchanged, to mention it here.

Perl

The algorithm is the same as in Raku (after the mentioned clearer change), but since the Perl module for Bags lacks some methods that Raku builds-in, I tried augmenting Set::Bag instead of writing the extra logic into the task1 sub. I am pleased with how this turned out.

use v5.40;
use Set::Bag;

package Set::Bag { # Extending the class with methods I wish were already included.
    use List::Util qw<pairgrep>;
    sub new_from_list ($self, $list_aref) {
        my $bag = Set::Bag->new();
        $bag->insert($_ => 1) for @{$list_aref};
        return $bag;
    }
    sub singles ($self) {
        return Set::Bag->new( pairgrep { $b == 1 } $self->grab );
    }
    sub count ($self) {
        my @e = $self->elements();
        return 0 + @e;
    }
}

use List::Util qw<reduce>;
sub task1 ( @LoLists ) {
    my $intersections_bag =
        reduce { $a & $b }
        map { Set::Bag->new_from_list($_)->singles }
        @LoLists;

    return $intersections_bag->count;
}

TWC Task #2 - Strong Pair

Task:

Given an array of integers, return the count of all strong pairs in the given array.
(x,y) is called a strong pair if it satisfies: 0 < |x - y| < min(x, y).

Observations:

Example 2 says input (5, 7, 1, 7) has output 1, which implies that the two (5,7) pairs (because the 7 occurs twice) must count only once. This further implies that we must either de-duplicate the input array, or accumulate a list of all the strong pairs and de-duplicate that list before summarizing in into the count of strong pairs. Since de-duplicate the input array is simpler, I will do that, via List::Util::uniq in Perl, and either .unique or .squish-after-sorting in Raku.

More observations are embedded between solutions, for narrative flow.

Perl

Translation of the slowest and fastest Raku solutions, with no notable changes. More than half the total runtime is just task2a grinding through all the combinations of the final EXTRA test: 1..4096.

Raku

Straight translation of the task.

sub task2_combo_unique ( @ns --> UInt ) {

    sub is_strong_pair ( (\x,\y) --> Bool )
        { 0 < abs(x - y) < min(x,y) }

    return +grep &is_strong_pair, combinations(@ns.unique, 2);
}

Now, let's do some logic and algebra, to transform 0 < abs(x - y) < min(x,y) into something more informative and performative.

0 < abs(x - y) < min(x,y)
0 < abs(x - y) and abs(x - y) < min(x,y)

Absolute values cannot be negative, so the < is really !=:

0 != abs(x - y) and abs(x - y) < min(x,y)

The only way abs(x - y) can equal 0 is if x and y are the same number. I already committed to de-duplicating the input, so x==y cannot happen. Therefore 0 != abs(x - y) is always true, and the whole clause can be removed. That leaves:

abs(x - y) < min(x,y)

Now, I could have made a solution with only that simplification, but removing one !=0 comparison doesn't seem high-value, and we are on the verge of more math realization. Both abs(x-y) and min are determined by ordering, and the pairings we want to count are unordered (i.e. combinations, so 5,7 is the same pair as 7,5), which is easiest to generate for computers by forcing an order. Also, Raku has a faster way to de-duplicate a list when it is in sorted order. All that adds up to a likelihood that sorting the list will allow approaches that gain efficiency the exceed the cost of sorting.

So, before this point, we can assume the list had no duplicates, because we used .unique. Solutions below this point will all use .sort(+*).squish, so we can assume "no duplicates, and in ascending numeric order".

Given that we now know the ordering, the last Strong Pair definition we had reduced to:

abs(x - y) < min(x,y)

we can replace min(x,y) with just x:

abs(x - y) < x

Also, since abs(x - y) is the same as abs(y - x), we can swap them:

abs(y - x) < x

The ordering implies y > x, so y - x cannot be negative, and abs can be removed:

y - x < x

This simplification allows us to remove min, abs, and 0< from the grep code. This gives use a 2x performance improvement, even with the added cost of the sort (which is partial paid for by .squish being cheaper than .unique).

sub task2_combo_sort ( @ns --> UInt ) {
    return +grep ->(\x,\y){ (y - x) < x },
            combinations( @ns.sort(+*).squish, 2 );
}

Both versions of task2_combo_* are O(N²).

We can do even better though!

A last bit of algebra; if we take the prior simplification:

y - x < x

and add x to both sides, we get:

y < 2x

and since we know x < y, that tells us that x < y < 2x. In Raku terms:

$y ~~ $x ^..^ ($x * 2)

We will use that soon.

Once we are working with sorted unique numbers, the .combinations(2) approach blocks three optimizations.
Given 3,4,5,6,7,8,9,10,11, and aliasing to $x as we iterate:

  1. Even when we can take no hints from any prior loop, there can be an early endpoint to checking $y. x=3 will pair with 4, then 5, then fail to pair with 6, and at that point we can stop checking; we know every number after will fail. .combinations cannot do this early exit; it must generate and test all five pairs: (3,7) through (3,11).
  2. The scans for valid $y can start earlier. $x=4 will pair with 5,6,7, but 5 did not need to be checked; because 5 is to the left of the stopping point of the prior loop, we already know it is inside the 2x range! We could assume 5 without checking, then check 6,7. Using the same optimization in the next loop where $x=5, we can assume the pairings with 6&7 are valid, and start checking at 8.
  3. Past a "halfway" point, the $x iterations can be replaced by a closed equation. When $x=6, 2*$x=12 is more than the last element (11). So, all numbers to right are "in range" of 2x, and always will be from this point forward. So, no need to inspect the array values at all any more; the number of pairs that will succeed is all of pairs remaining, since none can fail. We can directly calculate using the near-zero-cost O(1) triangle calculation.

LATE NOTE: Jörg Sommrey (jo-37) blogged on the logic of the first two of these optimizations, in proper Math/CompSci notation. If you have an academic background, that writeup might be more to your liking.

To make room for the first two optimizations, we must abandon both the uncontrolled .combinations method and the use of a inner $y loop. Instead, we will have an outer $x loop, and a $y pointer that can remember its location across $x loops.

O(N) algorithm: (Well, it is O(N lnN) on paper, but with the numeric sort running in down in NQP, I am not seeing the impact of the sort, at the under-10-million scale I am testing.)

sub task2_linear_after_sort ( @ns --> UInt ) {
    my @ns_ss = @ns.sort(+*).squish;

    my ( $y, $r ) = 0 xx *;
    for @ns_ss.kv -> $x, $xv {
        my $x2 = $xv * 2;

        $y++ while ($y+1) <= @ns_ss.end and @ns_ss[$y+1] < $x2;

        $r += $y - $x;
    }

    return $r;
}

To enable the third optimization, all that we need is my $highest = @ns_ss.tail outside the loop, and then to watch for 2x to exceed that highest, then add in all the pairs we would have counted past that point. e.g. if it happens 5-away from the end, the count of pairs would be 4+3+2+1, or [+]1..4, or Triangle(4).

sub task2_linear_after_sort_early_return ( @ns --> UInt ) {
    my @ns_ss = @ns.sort(+*).squish;

    my $highest = @ns_ss.tail;

    my ( $y, $r ) = 0 xx *;
    for @ns_ss.kv -> $x, $xv {
        my $x2 = $xv * 2;

        if $x2 > $highest {
            $r += Triangle(+@ns_ss - $x);
            last;
        }

        $y++ while ($y+1) <= @ns_ss.end and @ns_ss[$y+1] < $x2;

        $r += $y - $x;
    }

    return $r;
}

The performance differences are as severe as one would expect with O(N²) vs anything-close-to-O(N); in the time that the slowest solution can solve a 1_000 element input array, the fastest can solve 1_000_000 elements.


The road to freedom
can't be seen
by downcast eyes
-- "you're an ace, kid" video, by Karen "DEMONDICE" Calanni

NewLib porting++

Perl on Medium

Published by Seo Minsang on Monday 15 July 2024 00:25

resolve error for automake 1.11

Per Context Catalyst Component - John Napiorkowski - TPRC 2024 - Lightning Tak

The Perl and Raku Conference YouTube channel

Published by The Perl and Raku Conference - Las Vegas, NV 2024 on Sunday 14 July 2024 23:46

C

The Weekly Challenge

Published on Sunday 14 July 2024 23:24

As you know, The Weekly Challenge, primarily focus on Perl and Raku. During the Week #018, we received solutions to The Weekly Challenge - 018 by Orestis Zekai in Python. It was pleasant surprise to receive solutions in something other than Perl and Raku. Ever since regular team members also started contributing in other languages like Ada, APL, Awk, BASIC, Bash, Bc, Befunge-93, Bourne Shell, BQN, Brainfuck, C3, C, CESIL, Chef, COBOL, Coconut, C Shell, C++, Clojure, Crystal, D, Dart, Dc, Elixir, Elm, Emacs Lisp, Erlang, Excel VBA, F#, Factor, Fennel, Fish, Forth, Fortran, Gembase, GNAT, Go, GP, Groovy, Haskell, Haxe, HTML, Hy, Idris, IO, J, Janet, Java, JavaScript, Julia, Korn Shell, Kotlin, Lisp, Logo, Lua, M4, Maxima, Miranda, Modula 3, MMIX, Mumps, Myrddin, Nelua, Nim, Nix, Node.

Uiua

The Weekly Challenge

Published on Sunday 14 July 2024 23:24

As you know, The Weekly Challenge, primarily focus on Perl and Raku. During the Week #018, we received solutions to The Weekly Challenge - 018 by Orestis Zekai in Python. It was pleasant surprise to receive solutions in something other than Perl and Raku. Ever since regular team members also started contributing in other languages like Ada, APL, Awk, BASIC, Bash, Bc, Befunge-93, Bourne Shell, BQN, Brainfuck, C3, C, CESIL, Chef, COBOL, Coconut, C Shell, C++, Clojure, Crystal, D, Dart, Dc, Elixir, Elm, Emacs Lisp, Erlang, Excel VBA, F#, Factor, Fennel, Fish, Forth, Fortran, Gembase, GNAT, Go, GP, Groovy, Haskell, Haxe, HTML, Hy, Idris, IO, J, Janet, Java, JavaScript, Julia, Korn Shell, Kotlin, Lisp, Logo, Lua, M4, Maxima, Miranda, Modula 3, MMIX, Mumps, Myrddin, Nelua, Nim, Nix, Node.

BLOG: The Weekly Challenge #058

The Weekly Challenge

Published on Sunday 14 July 2024 23:24

This week, I struggled with both the task, to be honest. Dealing with alpha part of the version was really pain in the neck. Every time, I struggle with any task, I follow the college days course of action i.e. pick a pend and paper. I start dribbling the thought process, it really helps in getting the idea out on the paper. Once the rough draft is ready, it is time to face the unit test trial. I make sure every solution of mine must go through the unit test trials. It flesh out edge cases most time, if I could come up with enough test cases.

Julia

The Weekly Challenge

Published on Sunday 14 July 2024 23:24

As you know, The Weekly Challenge, primarily focus on Perl and Raku. During the Week #018, we received solutions to The Weekly Challenge - 018 by Orestis Zekai in Python. It was pleasant surprise to receive solutions in something other than Perl and Raku. Ever since regular team members also started contributing in other languages like Ada, APL, Awk, BASIC, Bash, Bc, Befunge-93, Bourne Shell, BQN, Brainfuck, C3, C, CESIL, Chef, COBOL, Coconut, C Shell, C++, Clojure, Crystal, D, Dart, Dc, Elixir, Elm, Emacs Lisp, Erlang, Excel VBA, F#, Factor, Fennel, Fish, Forth, Fortran, Gembase, GNAT, Go, GP, Groovy, Haskell, Haxe, HTML, Hy, Idris, IO, J, Janet, Java, JavaScript, Julia, Korn Shell, Kotlin, Lisp, Logo, Lua, M4, Maxima, Miranda, Modula 3, MMIX, Mumps, Myrddin, Nelua, Nim, Nix, Node.

Colin Crain › Perl Weekly Review #177

The Weekly Challenge

Published on Sunday 14 July 2024 23:24

( …continues from previous week. )
PathTools: Keep $VERSION consistent in all *.pm files

Corrects oversight in aa5929628d0; spotted by Aaron Dill in GH #22346.

Installing CPAN modules ON MacOS

r/perl

Published by /u/MrCosgrove2 on Sunday 14 July 2024 14:06

I have a Mac M1 chip laptop.

While I have managed to install a couple of modules, most fail to install.

I tried perlbrew, but that was a struggle to even get it to install perl itself, but when it was installed it wasn't working the way I needed it to.

Just wondering if I am missing something with CPAN or if this is an issue because it's an M1 chip?

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

How to use perl v5.40's boolean builtins in Mojo::Pg queries

blogs.perl.org

Published by karjala on Sunday 14 July 2024 01:04

Perl v5.40 introduced native true and false keywords. Unfortunately not all CPAN modules are ready to use them. One of those not yet ready is Mojo::Pg.

Normally you'd want to pass booleans to your queries as just 1's and 0's. However, since Mojo::JSON's true & false stringify to 1 and 0, my 5.38-using codebase is full of Mojo::Pg queries with Mojo::JSON's true and false as arguments.

This is a problem if I want to upgrade the perl interpreter of that project to Perl v5.40, because if I write "use v5.40;" in the file that contains those boolean keywords, Perl's builtin booleans will be used instead, which don't stringify to 1 and 0, but to 1 and the empty string, which can't be used by DBD::Pg in boolean fields and makes DBD::Pg throw an exception.

The solution I found was to subclass Mojo::Pg::Database, and wrap the query method, so that if Perl's builtin booleans are found, they are replaced in the query with native Pg booleans.

The source of the module and a lot more information can be found in my blogpost, here.

Perl KVM - Chad Granum - TPRC 2024 - Lightning Talk

The Perl and Raku Conference YouTube channel

Published by The Perl and Raku Conference - Las Vegas, NV 2024 on Sunday 14 July 2024 00:43

(div) 4 great CPAN modules released last week

Niceperl

Published by Unknown on Saturday 13 July 2024 20:41

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

  1. Dumbbench - More reliable benchmarking with the least amount of thinking
    • Version: 0.504 on 2024-07-09, with 17 votes
    • Previous CPAN version: 0.503 was 2 years, 2 months, 18 days before
    • Author: BDFOY
  2. IO::Socket::SSL - Nearly transparent SSL encapsulation for IO::Socket::INET.
    • Version: 2.087 on 2024-07-08, with 49 votes
    • Previous CPAN version: 2.086 was 5 days before
    • Author: SULLR
  3. PerlPowerTools - BSD utilities written in pure Perl
    • Version: 1.046 on 2024-07-11, with 39 votes
    • Previous CPAN version: 1.045 was 2 months, 11 days before
    • Author: BRIANDFOY
  4. Pod::Man - Convert POD data to various other formats
    • Version: v6.0.1 on 2024-07-13, with 14 votes
    • Previous CPAN version: 5.01 was 1 year, 6 months, 19 days before
    • Author: RRA

(dlxxxviii) metacpan weekly report

Niceperl

Published by Unknown on Saturday 13 July 2024 20:39

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

This week there isn't any remarkable distribution

Build date: 2024/07/13 18:38:42 GMT


Clicked for first time:


Increasing its reputation:

(dcxiv) stackoverflow perl report

Niceperl

Published by Unknown on Saturday 13 July 2024 20:37

ntfy fr tckt alrts - Lee Johnson - TPRC 2024 - Lightning Talk

The Perl and Raku Conference YouTube channel

Published by The Perl and Raku Conference - Las Vegas, NV 2024 on Saturday 13 July 2024 14:04

The Quest for Performance Part IV

r/perl

Published by /u/ReplacementSlight413 on Saturday 13 July 2024 02:39

The final installment in the series:

"The-Quest-For-Performance" from my blog Killing It with #perl

Discussing #python #numpy #numba, #rstats #openMP enhancements of Perl code and #simd

Bottom line: I will not be migrating to Python anytime soon.

Food for thought: The Perl interpreter (and many of the modules) are deep down massive C programs. Perhaps one can squeeze real performance kicks by looking into alternative compilers, compiler flags and pragmas ?

https://chrisarg.github.io/Killing-It-with-PERL/2024/07/09/The-Quest-For-Performance-Part-IV-May-the-SIMD-Force-Be-With-You.html

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

Outreachy Updates - Bruce Gray for Makoto Nozaki - TPRC 2024 - Lightning Talk

The Perl and Raku Conference YouTube channel

Published by The Perl and Raku Conference - Las Vegas, NV 2024 on Friday 12 July 2024 21:22

Unicode adds new properties to the Unicode database and these are added to later versions of Perl. I'd like to be able to est if a property is allowed on my current version of Perl.

I have tried

perl -E 'say eval {qr/\p{wibble}/}; say q(OK)'

But the eval doesn't trap the missing property, I suspect because it's being looked up at compile time, and the script dies before it reaches the say q(OK)

Is there somehow that I can test if a property exists before using it in a regex?

MIME::QuotedPrint not encoding - what am I doing wrong?

Perl questions on StackOverflow

Published by Steve Waring on Friday 12 July 2024 14:55

With this code:

#!/usr/bin/perl
use warnings FATAL => 'all';
use strict;
use MIME::QuotedPrint;

my $encoded = "=4E=6F=74=65=73=0A=4E=6F=74=65=73=20=6C=69=6E=65=20=32";
print decode_qp($encoded);

my $decoded = "Imported today";
$encoded = encode_qp($decoded);
print "\n$encoded\n";

The first print statement gives exactly what I was expecting, but the second gives Imported today= instead of =49=6D etc.

What am I doing wrong?

I still like printing code listings

rjbs forgot what he was saying

Published by Ricardo Signes on Friday 12 July 2024 12:00

I used to program on paper, then type it in later. Not all the time, but sometimes. Sometimes I’d write pseudocode. Sometimes I wrote just the code I would type in later. Sometimes just flow charts and subroutine signatures. These days, I only really do the last version, because I always have a computer nearby now. I’m not stuck in a boring lecture, for example, with only a legal pad.

Back then, and later, I’d also review code on paper. This was before I was doing formal “code review” for work. Sometimes I just wanted to look at my own code, out of the context of my computer, and think about it. Sometimes I wanted to look at somebody else’s code. Either way, putting it on paper was really useful. I could read it away from the rest of the distractions of my computer, and I could draw circles and arrows in a bunch of different colors.

The way I did it, then, was to use Vim’s :hardcopy command. Like the rest of Vim, it has slightly strange but actually very good documentation. I worked on Windows in the early 2000s, and I could enter :ha and get a printout. Sometimes, though, I’d use the a2ps program instead. That was a bit more work to use, but it produced better listings (as I recall), especially because it would print two pages of code on one piece of paper, while remaining quite legible.

Over time, I printed code less often. This was partly, but not entirely, because I was coding less. Lately, I’ve been coding a bit more. On top of that, I do a lot of it sitting not twenty feet from Mark Dominus, who seems to print out nearly every hunk of code he reviews. This has brought back memories of how much I got out of printing code. It also led to him asking me a question or two about a2ps that left me a little surprised and embarrassed that I had forgotten how to use it well.

Over the last twenty four hours, I’ve tried to get back up to speed, and to find (and simplify) a method for printing code listings on demand. This blog post is a bit of a recounting of that work, and what I found.

PostScript

I wanted to start with a2ps but I have to write a prelude about PostScript.

The “a” in a2ps stands for “any”. The idea is that you feed it basically any kind of source code (or plain text) and it will build a PostScript file for printing. PostScript is a programming language created by Adobe and used (mostly but not entirely) to drive printers. It’s a bit of a weird language, but it’s postfix and stack-based, so I have a soft spot in my heart for it. You can see three books on PostScript on shelf three in my post about my technical bookshelf. Ten years ago, showing the kid different kinds of programming, we wrote this program:

/text {
  /Times-Roman findfont exch scalefont setfont
} def

newpath 24 text 200 400 moveto
        (You're standing on my neck!) show

newpath 284 284 72 0 360 arc stroke
newpath 265 300 12 0 360 arc fill
newpath 303 300 12 0 360 arc fill
newpath 250 225 moveto 275 225 lineto
        275 200 lineto 250 200 lineto
        250 225 lineto stroke
newpath 275 225 moveto 300 225 lineto
        300 200 lineto 275 200 lineto
        275 225 lineto stroke

newpath 300 225 moveto 325 225 lineto
        325 200 lineto 300 200 lineto
        300 225 lineto stroke

It draws a skull with the caption “You’re standing on my neck!”. Try it!

But how? Well, in theory you can send it directly to your printer with lp, but on current macOS (unlike older versions) you will get this error: Unsupported document-format “application/postscript”.

I’m not sure exactly where the problem lies. My suspicion is that it’s in the CUPS service that serves as the mediator between the user and the printer on macOS. Probably I could get around this by using mDNS and IPP, and honestly I am tempted to go learn more. But there was a simpler solution: ps2pdf converts a PostScript program to a PDF file. It’s shipped with Ghostscript and is easy to get from Homebrew.

PDF is actually based on PostScript, but I don’t know the details. PostScript has also been used for rendering graphical displays, using a system called Display PostScript (DPS), which was developed by both Adobe and NeXT, and later became the basis for the MacOS X display system. So, why doesn’t macOS support PostScript well anymore? Honestly, I don’t know.

Anyway: lots of the things I tried using for printing output PostScript, which is meant to be easy to send on to the printer. With ps2pdf installed, printing these files isn’t so hard. It’s just a drag that they can’t be send right to the lp command.

a2ps

Right, back to a2ps! Given a piece of source code, it will spit out a PostScript program representing a nice code listing. Unfortunately, running it out of the box produced something pretty awful, and I had to fumble around a good bit before I got what I wanted. I didn’t save a copy, so if you want to see it, you can try to reproduce it on your own. The problems included being off center, running off the page margins, using a mix of different typefaces in one source listing, using awful colors, and probably other stuff. So, I had to consult the manual. Unfortunately, I started doing that by running man a2ps, immediately hitting the problem that has infuriated geeks for decades: I got a pretty mediocre man page with a footnote saying the real docs were in Texinfo. And info isn’t installed.

Eventually I found myself reading the a2ps manual as a PDF on the web. With that (and with some help from Mark), I found that much of what I needed would come down to putting this in ~/.a2ps/a2psrc:

Options: --medium=letter
Options: --line-numbers 1
Options: --prologue color

This set my paper size, turned on line numbering on every line, and said that I wanted highlighting to be expressed as color, not just font weight.

There were two problems that I could not get over:

  1. Typeface mixing! Everything was in fixed text except for literal strings, which were (to my horror) represented in a proportional font.
  2. Awful colors. For example, subroutine names were printed in black on a bright yellow background. Probably some people think this is fine. I did not. (The a2ps manual admits: “It is pretty known that satisfying the various human tastes is an NEXPTIME-hard problem.”)

So, how to fix it? By hacking on a PostScript file!

a2ps combines (roughly) two things to build the final PostScript program: the prologue, and the program. (There’s also the header (“hdr”), but that’s included directly by the prologue. Let’s not split hairs.)

The program is a series of PostScript instructions that will print out your listing. The prologue is a set of function definitions that the program will used. The a2ps binary (written in C) reads your source document, tokenizes it for syntax highlighting, and then emits a program. For example, here’s a hunk of output for the Perl code that I’ll be using in all the samples in this post.

0 T () S
(sub) K
( ) p
(richsection) L
( \(@elements\) {) p n
(185) # (  Slack::BlockKit::Block::RichText::Section->new\({) N
0 T (    elements => _rtextify\(@elements\),) N
0 T (  }\);) N
0 T (}) N
0 T () N
(190) # () S

The parentheses are string delimiters, and because PostScript is a postfix language, when you see (richsection) L it’s calling the function L with the string “richsection” on the stack. True, there may be other things on the stack, but I happen to know that L is a one-argument function. It looks like this:

/L {
  0 0 0 FG
  1 1 0 true BG
  false UL
  false BX
  fCourier-Bold bfs scalefont setfont
  Show
} bind def

This prints the string on the stack to the current position on the page in black on bright yellow. Yuck. This function comes from the “color” prologue, which is installed in share/a2ps/ps. There’s no way to change parameters to it, so the recommended practice is to copy it into ~/.a2ps and edit that. This would be more horrifying if there were new version of a2ps coming out with notable changes, but there aren’t, so it’s … fine.

I hacked up a copy of color.pro and changed the prologue option in my configuration file to rjbs.pro. I renewed my PostScript programmer credentials! While doing this, I also fixed the typefaces, replacing Times-Roman with Courier in the definition of str, the string literal display function.

This got me some pretty decent output, shown here, and linked to a PDF:

a page of code from a2ps

By the way, all the samples in this post will be from formatting this copy of Slack::BlockKit::Sugar.

This was fine, but I had two smaller problems:

  1. The syntax highlighting is a bit anemic (but not so bad).
  2. The line spacing is a little tight for me.

Fixing the first one means editing the “style sheet” for Perl. This isn’t like CSS at all. It doesn’t define the style, it defines how to mark up tokens as being one thing or another. The functions in the prologue will do the styling. I looked at what might be worth putting here as a sample, but I think if you want to see what they look like, you should check out the perl.ssh file itself. It’s fine, but it’s also obvious that making it better would be an ordeal. I bailed.

Fixing line spacing felt like it should be easy, though. Surely there’d be an option for that, right? Sadly, no. I decided to use my PostScript expertise to work. Here’s the N function, which renders a line and moves to the next position:

/N {
  Show
  /y0 y0 bfs sub store
  x0 y0 moveto
} bind def

bfs is the “body font size”. We’re moving a little down the page by reducing the y position of the cursor by the font size. What if we did this?

/y0 y0 bfs 1.1 mul sub store

That should add a 10% line spacing increase, right? Well, yes, but the problem is this: remember how the a2ps binary is responsible for spitting out the PostScript program? That’s where it computes how many lines per page. By mucking with the vertical spacing, we start running off the end of the page. We need to change the number of lines that a2ps puts on the page. No problem, we’d just tweak this code:

job->status->linesperpage =
  (int) ((printing_h / job->fontsize) - BOTTOM_MARGIN_RATIO);

…at which point I realized I had to install automake. I did, and I went a few steps further, and finally gave up. It was too annoying for a Saturday.

What if instead I changed the default style? I won’t bore you with the PostScript, but I made a new function, vbfs, defined as 0.9 of bfs. I updated all the rendering functions to use that value for size, but the full value was still used for line spacing. This worked! But changing the font size mean that I was ending up with horizontal dead space. I was scaling everything down, when all I wanted to scale up was the vertical space. It was unsatisfactory, and I decided to settle for the tight line spacing.

…for about five minutes. And then I decided to try the other GNU program for turning source code into PostScript.

enscript

GNU Enscript bills itself as “a free replacement for Adobe’s enscript program”. I don’t know what that was, but I can tell you that enscript is basically “a2ps, except different”. It serves the same function. I fed it the same hunk of code, but not before reading the manual and finding --baselineskip, which is exactly what I wanted: a way to control line spacing. I used this invocation:

enscript lib/Slack/BlockKit/Sugar.pm \
  --columns=2       \
  --baselineskip=2  \
  --landscape       \
  --color           \
  --highlight       \
  --line-numbers    \
  --output Sugar.ps

It looked pretty good at first, when looking at the first page of output (not pictured here). On the other hand, here’s page three:

a page of code from enscript

The line spacing is nice (and maybe nicer when cranked up), and the colors aren’t offensive. But they’re all wrong. Part of the issue is that this source is using =func as if it was a real Pod directive, which it isn’t. On the other hand, it’s real enough that Perl will ignore the enclosed documentation. Syntax highlighting should start at =func and end at =cut. The syntax definition for Perl in enscript is very strict, and so this is wrong. And that means that the documentation’s syntax highlighting ends up all wrong all over the place. It’s unusable.

Syntax highlighting in enscript is different than a2ps’s style sheets. Instead, it’s programmed with a little “state” language. You can read the Perl state program, but I’m not sure I recommend it. It’s relatively inscrutable, or at least it is written in terms of some other functionality that doesn’t seem well documented. Fixing the Pod thing seemed trivial, but all I could imagine was an endless stream of further annoyance. Maybe this isn’t fair, but it’s where I ended up.

At this point, settling on a2ps might have been a good idea, but instead I moved on to Vim.

Vim :hardcopy

Way up at the top of this post, I mentioned that I had used Vim in the past. So, why not now? Well, reasons. The first one is that I didn’t remember how, and I knew that “it didn’t work anymore”. But I was in for way more than a penny by now, so I went further down the rabbit hole.

It turned out that “it didn’t work anymore” was trivial. I was getting this error:

E365: Failed to print PostScript file

Right. Because lp doesn’t handle PostScript anymore. I could just write the PostScript file to a file, then apply ps2pdf. I did so, and it was bad. The good news was that getting from bad to okay wasn’t so hard. I had to set some printoptions in Vim.

set printoptions=paper:letter,number:y,left:5pc

This sets my paper size (which I’d already had in my .vimrc actually!), turns on line numbering, and reduces the left margin to 5%. The default left margin was 10%, which was just way too much. It’s nice to have space to write, but I usually do that in the whitespace on the right side of the code. To print to a file in Vim, you can execute :hardcopy > filename.ps. With these settins, I got this output:

a page of code from Vim

The main problem here is that it’s one-up. Only one page of code per sheet of paper. It’s easy to read, but it takes twice as much paper. It’s a waste, and also leads to more desk clutter than necessary. My desk is enough of a mess as it is.

Fortunately, there’s a solution for this! The slightly obscure mpage command reads a PostScript document in, then spits out another one that’s multiple pages per sheet. It hasn’t quite fallen off the web, but it’s not extremely well published. Here’s a link to its man page hosted at a fairly random-seeming location at CMU. Fortunately, it’s in Homebrew. I could take the PDF above and run this:

mpage -2 -bLetter -S Sugar.ps > Sugar2.ps && ps2pdf Sugar2.ps

The -S option there is fairly critical. It says “allow non-square scaling”. In theory this might introduce some distortion, but I can’t notice it, and it gets a better use of space on the page. I also go back to my printoptions in Vim and set all the margins to 0pc. Since mpage will be adding a margin when it produces the two-up pages, I don’t need any margin on the pages it’s combining. I get four more lines per page, plus more space on the right of each listing.

Here’s what we get:

a page of code from Vim, sent through mpage

I wasn’t sure how to get a better set of colors. I’m pretty sure it’s possible, but I’ll have to think about it and play around. There is a very large benefit here, though. The syntax highlighting that I get in the PDF will be based on the same syntax highlighting that I’m used to seeing every day in Vim. I know nothing is critically wrong, and if there was, I’d be very motivated to fix it, because I’d be seeing it every day in my editor!

The real problem, for fixing the colors, is that I use a dark-background color scheme in Vim. Printing tries to emulate your color scheme, but has to correct for the fact that it’s going to print on white paper. The real answer is to have an alternate color scheme ready for printing.

Still, I’m pretty happy with this. All that remained was to make it really easy. So, I wrote a stupid little Perl program that finds a PostScript file on disk, runs it through mpage, then ps2pdf, then puts it on the Desktop and opens it in Preview. Then I updated my Vim configuration to make :hardcopy send print jobs to that instead of lp. It looks like this:

set printexpr=ByzantinePrintFile()
function ByzantinePrintFile()
  call system("/Users/rjbs/bin/libexec/vim-print-helper "
    \.. v:fname_in
    \.. " "
    \.. shellescape(expand('%:t'))
  \)
  call delete("v:fname_in")
  return v:shell_error
endfunc

Vim script is still weird.

This is where I’ll stop, feeling content and full of PostScript. I think for many people, all this PostScript nonsense would leave a bad aftertaste. For them, there’s another option…

Vim 2html.vim

Vim ships with a helper file called 2html.vim, which exports the current buffer as HTML, using the settings and colors currently in use. You can enter this in your Vim command line:

runtime! syntax/2html.vim

…and you’ll get a new Vim buffer full of HTML. The parity with the Vim display is impressive.

HTML output and Vim side by side

The problem is that so far, I’ve found going from HTML to a two-up PDF is too much of a pain. Possibly there’s some weird route from HTML to PostScript to piping through mpage but I think I’ll leave that adventure for another day or another dreamer. Me, I’ve got printing to do.

A p5p discussion about adding :writer to perlclass

r/perl

Published by /u/davorg on Friday 12 July 2024 11:26

Using Coro and AnyEvent Interactively

blogs.perl.org

Published by gg on Thursday 11 July 2024 09:30

Problem

I have not been able to figure out how to run an async thread in the background while using a REPL like reply. The moment I run the main loop, it takes over the input from the REPL. Here's what a typical failed REPL session might look like.

❯ rlwrap reply
use AnyEvent
use Coro
use Coro::AnyEvent
my ($i, $loop)
$res[0] = [
undef,
undef
]

$i = 0
$res[1] = 0

$loop = async { while ($i < 10) { say $i++; sleep 1 } }
$res[2] = bless( {}, 'Coro' )

AE::cv->recv
0
1
2
3
4
5
6
7
8
9
^C

I don't know how to get back to the REPL, so I hit ^C but that exits the REPL.

Solution

A workaround I discovered is vividsnow/perl-live which is a combination of perl + elisp that provides an interactive Perl environment that is running an event loop. However, instead of a REPL, you get an emacs buffer in cperl-mode from where you can send lines of perl to a running perl process.

It's not quite what I was looking for, but I can work with this. It does solve the problem of letting me interact with async threads in a running perl process.

Demo

perl live coding video

Maintaining Perl 5 Core (Dave Mitchell): June 2024

Perl Foundation News

Published by alh on Thursday 11 July 2024 08:43


Dave writes:

This is my monthly report on work done during June 2024 covered by my TPF perl core maintenance grant.

I spent most of last month continuing to work on understanding XS and improving its documentation, as a precursor to adding reference-counted stack (PERL_RC_STACK) abilities to XS.

This work is a bit frustrating, as I still haven't got anything publicly to show for it. Privately however, I do have about 4000 lines of notes on ways to improve the documentation and the XS parser itself.

I have also been going through the Extutils::ParseXS' module's code line by line trying to understand it, and have (so far) added about 1000 new lines of code comments to ParseXS.pm, which is nearly ready to be pushed. This has involved a lot of code archaeology, since much of the code is obscure. I have even discovered XS keywords which have been implemented but aren't documented (such as "ATTRS:" and "NOT_IMPLEMENTED_YET").

I have also dug out the xsubpp script from the 1994 perl5.000 release and from time to time run it against some sample XS constructs. Amazingly, it still runs under a modern perl (although I didn't check whether the C code it outputs is still compilable).

SUMMARY: * 1:38 process p5p mailbox * 53:30 rework XS documentation

Total: * 55:08 (HH:MM)

Migrating from MySQL to PostgreSQL

dev.to #perl

Published by Lawrence Cooke on Thursday 11 July 2024 05:00

Migrating a database from MySQL to Postgres is a challenging process.

While MySQL and Postgres do a similar job, there are some fundamental differences between them and those differences can create issues that need addressing for the migration to be successful.

Where to start?

Pg Loader is a tool that can be used to move your data to PostgreSQL, however, it's not perfect, but can work well in some cases. It's worth looking at to see if it's the direction you want to go.

Another approach to take is to create custom scripts.

Custom scripts offer greater flexibility and scope to address issues specific to your dataset.

For this article, custom scripts were built to handle the migration process.

Exporting the data

How the data is exported is critical to a smooth migration. Using mysqldump in its default setup will lead to a more difficult process.

Use the --compatible=ansi option to export the data in a format PostgreSQL requires.

To make the migration easier to handle, split up the schema and data dumps so they can be processed separately. The processing requirements for each file are very different and creating a script for each will make it more manageable.

Schema differences

Data Types

There are differences in what data types are available in MySQL and PostgreSQL, this means when processing your schema you are going to need to decide what field data types work best for your data.

Category MySQL PostgreSQL
Numeric INT, TINYINT, SMALLINT, MEDIUMINT, BIGINT, FLOAT, DOUBLE, DECIMAL INTEGER, SMALLINT, BIGINT, NUMERIC, REAL, DOUBLE PRECISION, SERIAL, SMALLSERIAL, BIGSERIAL
String CHAR, VARCHAR, TINYTEXT, TEXT, MEDIUMTEXT, LONGTEXT CHAR, VARCHAR, TEXT
Date and Time DATE, TIME, DATETIME, TIMESTAMP, YEAR DATE, TIME, TIMESTAMP, INTERVAL, TIMESTAMPTZ
Binary BINARY, VARBINARY, TINYBLOB, BLOB, MEDIUMBLOB, LONGBLOB BYTEA
Boolean BOOLEAN (TINYINT(1)) BOOLEAN
Enum and Set ENUM, SET ENUM (no SET equivalent)
JSON JSON JSON, JSONB
Geometric GEOMETRY, POINT, LINESTRING, POLYGON POINT, LINE, LSEG, BOX, PATH, POLYGON, CIRCLE
Network Address No built-in types CIDR, INET, MACADDR
UUID No built-in type (can use CHAR(36)) UUID
Array No built-in support Supports arrays of any data type
XML No built-in type XML
Range Types No built-in support int4range, int8range, numrange, tsrange, tstzrange, daterange
Composite Types No built-in support User-defined composite types

Tinyint field type

Tinyint doesn't exist in PostgreSQL. You have the choice of smallint or boolean to replace it with. Choose the data type most like the current dataset.

 $line =~ s/\btinyint(?:\(\d+\))?\b/smallint/gi;

Enum Field type

Enum fields are a little more complex, while enums exist in PostgreSQL, they require creating custom types.

To avoid duplicating custom types, it is better to plan out what enum types are required and create the minimum number of custom types needed for your schema. Custom types are not table specific, one custom type can be used on multiple tables.

CREATE TYPE color_enum AS ENUM ('blue', 'green');

...
"shirt_color" color_enum NOT NULL DEFAULT 'blue',
"pant_color" color_enum NOT NULL DEFAULT 'green',
...

The creation of the types would need to be done before the SQL is imported. The script could then be adjusted to use the custom types that have been created.

If there are multiple fields using enum('blue','green'), these should all be using the same enum custom type. Creating custom types for each individual field would not be good database design.

if ( $line =~ /"([^"]+)"\s+enum\(([^)]+)\)/ ) {
    my $column_name = $1;
    my $enum_values = $2;
    if ( $enum_values !~ /''/ ) {
        $enum_values .= ",''";
    }

    my @items = $enum_values =~ /'([^']*)'/g;

    my $sorted_enum_values = join( ',', sort @items );

    my $enum_type_name;
    if ( exists $enum_types{$sorted_enum_values} ) {
        $enum_type_name = $enum_types{$sorted_enum_values};
    }
    else {
        $enum_type_name = create_enum_type_name($sorted_enum_values);
        $enum_types{$sorted_enum_values} = $enum_type_name;

        # Add CREATE TYPE statement to post-processing
        push @enum_lines,
        "CREATE TYPE $enum_type_name AS ENUM ($enum_values);\n";
    }

    # Replace the line with the new ENUM type
    $line =~ s/enum\([^)]+\)/$enum_type_name/;
}

Indexes

There are differences in how indexes are created. There are two variations of indexes, Indexes with character limitations and indexes without character limitations. Both of these needed to be handled and removed from the SQL and put into a separate SQL file to be run after the import is complete (run_after.sql).

if ($line =~ /^\s*KEY\s+/i) {
    if ($line =~ /KEY\s+"([^"]+)"\s+\("([^"]+)"\)/) {
        my $index_name = $1;
        my $column_name = $2;
        push @post_process_lines, "CREATE INDEX idx_${current_table}_$index_name ON \"$current_table\" (\"$column_name\");\n";
    } elsif ($line =~ /KEY\s+"([^"]+)"\s+\("([^"]+)"\((\d+)\)\)/i) {
        my $index_name = $1;
        my $column_name = $2;
        my $prefix_length = $3;
        push @post_process_lines, "CREATE INDEX idx_${current_table}_$index_name ON \"$current_table\" (LEFT(\"$column_name\", $prefix_length));\n";
    }
    next;
}

Full text indexes work quite differently in PostgreSQL. To create full text index the index must convert the data into a vector.

The vector can then be indexed. There are two index types to choose from when indexing vectors. GIN and GiST. Both have pros and cons. Generally GIN is preferred over GiST. While GIN is slower building the index, it's faster for lookups.

if ( $line =~ /^\s*FULLTEXT\s+KEY\s+"([^"]+)"\s+\("([^"]+)"\)/i ) {
    my $index_name  = $1;
    my $column_name = $2;
    push @post_process_lines,
    "CREATE INDEX idx_fts_${current_table}_$index_name ON \"$current_table\" USING GIN (to_tsvector('english', \"$column_name\"));\n";
    next;
}

Auto increment

PostgreSQL doesn't use the AUTOINCREMENT keyword, instead it uses GENERATED ALWAYS AS IDENTITY.

There is a catch with using GENERATED ALWAYS AS IDENTITY while importing data. GENERATED ALWAYS AS IDENTITY is not designed for importing IDs, When inserting a row into a table, the ID field cannot be specified. The ID value will be auto generated. Trying to insert your own IDs into the row will produce an error.

To work around this issue, the ID field can be set as SERIAL type instead of int GENERATED ALWAYS AS IDENTITY. SERIAL is much more flexible for imports, but it is not recommended to leave the field as SERIAL.

An alternative to using this method would be to add OVERRIDING SYSTEM VALUE into the insert query.

INSERT INTO table (id, name)
OVERRIDING SYSTEM VALUE
VALUES (100, 'A Name');

If you use SERIAL, some queries will need to be written into run_after.sql to change the SERIAL to GENERATED ALWAYS AS IDENTITY and reset the internal counter after the schema is created and the data has been inserted.

if ( $line =~ /^\s*"(\w+)"\s+(int|bigint)\s+NOT\s+NULL\s+AUTO_INCREMENT\s*,/i ) {
    my $column_name = $1;
    $line =~ s/^\s*"$column_name"\s+(int|bigint)\s+NOT\s+NULL\s+AUTO_INCREMENT\s*,/"$column_name" SERIAL,/;

    push @post_process_lines, "ALTER TABLE \"$current_table\" ALTER COLUMN \"$column_name\" DROP DEFAULT;\n";

    push @post_process_lines, "DROP SEQUENCE ${current_table}_${column_name}_seq;\n";

    push @post_process_lines, "ALTER TABLE \"$current_table\" ALTER COLUMN \"$column_name\" ADD GENERATED ALWAYS AS IDENTITY;\n";

    push @post_process_lines, "SELECT setval('${current_table}_${column_name}_seq', (SELECT COALESCE(MAX(\"$column_name\"), 1) FROM \"$current_table\"));\n\n";

}

Schema results

Original schema after exporting from MySQL

DROP TABLE IF EXISTS "address_book";
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE "address_book" (
  "id" int NOT NULL AUTO_INCREMENT,
  "user_id" varchar(50) NOT NULL,
  "common_name" varchar(50) NOT NULL,
  "display_name" varchar(50) NOT NULL,
  PRIMARY KEY ("id"),
  KEY "user_id" ("user_id")
);

Processed main SQL file

DROP TABLE IF EXISTS "address_book";
CREATE TABLE "address_book" (
  "id" SERIAL,
  "user_id" varchar(85) NOT NULL,
  "common_name" varchar(85) NOT NULL,
  "display_name" varchar(85) NOT NULL,
  PRIMARY KEY ("id")
);

Run_after.sql

ALTER TABLE "address_book" ALTER COLUMN "id" DROP DEFAULT;
DROP SEQUENCE address_book_id_seq;
ALTER TABLE "address_book" ALTER COLUMN "id" ADD GENERATED ALWAYS AS IDENTITY;
SELECT setval('address_book_id_seq', (SELECT COALESCE(MAX("id"), 1) FROM "address_book"));
CREATE INDEX idx_address_book_user_id ON "address_book" ("user_id");

Its worth noting the index naming convention used in the migration. The index name includes both the table name and the field name. Index names have to be unique, not only within the table the index was added to, but the entire database, adding the table name and the column name reduces the chances of duplicates in your script.

Data processing

The biggest hurdle in migrating your database is getting the data into a format PostgreSQL accepts. There are some differences in how PostgreSQL stores data that requires extra attention.

Character sets

The dataset used for this article predated utf8mb4 and uses the old default of Latin1, the charset is not compatible with PostgreSQL default charset UTF8, it should be noted that PostgreSQL UTF8 also differs from MySQL's UTF8mb4.

The issue with migrating from Latin1 to UTF8 is how the data is stored. In Latin1 each character is a single byte, while in UTF8 the characters can be multibyte, up to 4 bytes.

An example of this is the word café

in Latin1 the data is stored as 4 bytes and in UTF8 as 5 bytes. During migration of character sets, the byte value is taken into account and can lead to truncated data in UTF8. PostgreSQL will error on this truncation.

To avoid truncation, add padding to affected Varchar fields.

It's worth noting that this same truncation issue could occur if you were changing character sets within MySQL.

Character Escaping

It's not uncommon to see backslash escaped single quotes stored in a database.

However, PostgreSQL doesn't support this by default. Instead, the ANSI SQL standard method of using double single quotes is used.

If the varchar field contains It\'s it would need to be changed to it''s

 $line =~ s/\\'/\'\'/g;

Table Locking

In SQL dumps there are table locking calls before each insert.

LOCK TABLES "address_book" WRITE;

Generally it is unnecessary to manually lock a table in PostgreSQL.

PostgreSQL handles transactions by using Multi-Version Concurrency Control (MVCC). When a row is updated, it creates a new version. Once the old version is no longer in use, it will be removed. This means that table locking is often not needed. PostgreSQL will use locks along side MVCC to improve concurrency. Manually setting locks can negatively affect concurrency.

For this reason, removing the manual locks from the SQL dump and letting PostgreSQL handle the locks as needed is the better choice.

Importing data

The next step in the migration process is running the SQL files generated by the script. If the previous steps were done correctly this part should be a smooth action. What actually happens is the import picks up problems that went unseen in the prior steps, and requires going back and adjusting the scripts and trying again.

To run the SQL files sign into the Postgres database using Psql and run the import function

\i /path/to/converted_schema.sql

The two main errors to watch out for:

ERROR: value too long for type character varying(50)

This can be fixed by increasing varchar field character length as mentioned earlier.

ERROR: invalid command \n

This error can be caused by stray escaped single quotes, or other incompatible data values. To fix these, regex may need to be added to the data processing script to target the specific problem area.

Some of these errors require a harder look at the insert statements to find where the issues are. This can be challenging in a large SQL file. To help with this, write out the INSERT statements that were erroring to a separate, much smaller SQL file, which can more easily be studied to find the issues.

my %lines_to_debug = map { $_ => 1 } (1148, 1195); 
 ...
if (exists $lines_to_debug{$current_line_number}) {
    print $debug_data "$line";  
}

Chunking Data

Regardless of what scripting language you choose to use for your migration, chunking data is going to be important on large SQL files.

For this script, the data was chunked into 1Mb chunks, which helped kept the script efficient. You should pick a chunk size that makes sense for your dataset.

my $bytes_read = read( $original_data, $chunk, $chunk_size );

Verifying Data

There are a few methods of verifying the data

Row Count

Doing a row count is an easy way to ensure at least all the rows were inserted. Count the rows in the old database and compare that to the rows in the new database.

SELECT count(*) FROM address_book

Checksum

Running a checksum across the columns may help, but bear in mind that some fields, especially varchar fields, could have been changed to ANSI standard format. So while this will work on some fields, it won't be accurate on all fields.

For MySQL

SELECT MD5(GROUP_CONCAT(COALESCE(user_id, '') ORDER BY id)) FROM address_book

For PostgreSQL

SELECT MD5(STRING_AGG(COALESCE(user_id, ''), '' ORDER BY id)) FROM address_book

Manual Data Check

You are going to want to verify the data through a manual process also. Run some queries that make sense, queries that would be likely to pick up issues with the import.

Final thoughts

Migrating databases is a large undertaking, but with careful planning and a good understanding of both your dataset and the differences between the two database systems, it can be completed successfully.

There is more to migrating to a new database than just the import, but a solid dataset migration will put you in a good place for the rest of the transition.

Scripts created for this migration can be found on Git Hub.

Perl Weekly Challenge 277: Strong Pair

blogs.perl.org

Published by laurent_r on Thursday 11 July 2024 02:03

These are some answers to the Week 277, Task 2, of the Perl Weekly Challenge organized by Mohammad S. Anwar.

Spoiler Alert: This weekly challenge deadline is due in a few days from now (on July 14, 2024, known in France as Bastille Day, at 23:59). This blog post provides some solutions to this challenge. Please don’t read on if you intend to complete the challenge on your own.

Task 2: Strong Pair

You are given an array of integers, @ints.

Write a script to return the count of all strong pairs in the given array.

A pair of integers x and y is called strong pair if it satisfies: 0 < |x - y| < min(x, y).

Example 1

Input: @ints = (1, 2, 3, 4, 5)
Ouput: 4

Strong Pairs: (2, 3), (3, 4), (3, 5), (4, 5)

Example 2

Input: @ints = (5, 7, 1, 7)
Ouput: 1

Strong Pairs: (5, 7)

We have a slight problem with example 2: since the integer 7 appears twice in the input array, we will find twice the strong pair (5, 7) and the output will be 2, not 1. To solve this issue and obtain the result specified in the example, we will remove duplicates from the input array before we start building the pairs.

Strong Pair in Raku

First, we use the unique method to remove duplicates from the input array, then we use the combinations method to generate all possible pairs. We increment the $count counter for each pair matching the strong pair criteria, and finally return the counter.

sub strong-pairs (@in) {
    my` $count = 0;
    for @in.unique.combinations: 2 -> @pair {
        $count++ if 0 < (@pair[0] - @pair[1]).abs < @pair.min;
    }
    return $count;
}

my @tests = (1, 2, 3, 4, 5), (5, 7, 1, 7);
for @tests -> @test {
    printf "%-10s => ", "@test[]";
    say strong-pairs @test;
}

This program displays the following output:

$ raku ./strong-pairs.raku
1 2 3 4 5  => 4
5 7 1 7    => 1

Strong Pair in Perl

This is essentially a port to Perl of the above Raku program. In Perl, the canonical way to remove duplicates is to coerce the input list into a hash and then retrieve the keys of the hash. Then we use two nested for loops to generate all the possible pairs. Next, we increment the $count counter for each pair matching the strong pair criteria, and finally return the counter.

sub strong_pairs {
    my %input = map { $_ => 1 } @_; # remove duplicates
    my @in = keys %input;
    my $count = 0;
    for my $i (0..$#in) {
        for my $j ($i+1..$#in) {
            my $min = $in[$i] < $in[$j] ? $i : $j;
            $count++ if 0 < abs($in[$i] - $in[$j]) and
                abs($in[$i] - $in[$j]) < $in[$min];
        }
    }
    return $count;
}

my @tests = ([1, 2, 3, 4, 5], [5, 7, 1, 7]);
for my $test (@tests) {
    printf "%-10s => ", "@$test";
    say strong_pairs @$test;
}

This program displays the following output:

$ perl ./strong-pairs.pl
1 2 3 4 5  => 4
5 7 1 7    => 1

Wrapping up

The next week Perl Weekly Challenge will start soon. If you want to participate in this challenge, please check https://perlweeklychallenge.org/ and make sure you answer the challenge before 23:59 BST (British summer time) on July 21, 2024. And, please, also spread the word about the Perl Weekly Challenge if you can.

Perl and why you use it

r/perl

Published by /u/brisray on Tuesday 09 July 2024 19:46

I would be interested to know why you chose Perl and how long you have been using it and what for.

I have just returned to Perl after many years away, think decades rather than a couple of years. Consider me a noob as I've long forgotten anything I knew about the language.

I run a small home webserver, Apache on Windows 10 with Strawberry Perl, and recently started some projects starting with moving away with things like Google Analytics and going back to some old log analyzers such as AWStats, which is still being maintained, and W3Perl, which is not. Even more recently I have started using Ringlink.

Perl is still being developed, Strawberry, Active State, CPAN etc. but lost out to PHP and Python. Just like COBOL, I can easily imagine thousands of systems depend on Perl.

Wow, some interesting stories. My own history is learning Locomotive Basic on an Amstrad 1640 PC in the mid-80s. Later on I was working in a print shop working on databases on EBCDIC data tapes in Foxpro for DOS and using a language called PReS to produce print ready documents from them.

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

apparently NUL is mostly whitespace in Perl?

rjbs forgot what he was saying

Published by Ricardo Signes on Tuesday 09 July 2024 12:00

This post will be short but baffling.

In the following snippet, the ^@ sequences indicate literal NUL bytes in the source document.

use v5.36.0;
my $i = ^@ 1;
sub foo () {
 say q^@Hell0, w0rld.^@;
 $i^@++;
}

foo(^@);

say ^@$i;

This program will run and print:

Hell0, w0rld.
2

The NUL bytes are all ignored… except for the two that act as the string delimiters for the q-operator. As near as I can tell without reading any of the source for the perl tokenizer (or related code), NUL is treated like whitespace. I am gobsmacked. I know all kinds of weird stuff about Perl, but this one surprised me.

It came up when I tried to run a bunch of small programs through perltidy, and it refused to process just one file, because it was “binary”. There was a NUL after a subroutine’s opening brace. I removed it out, but not because it was a syntax error. Just because it was not in good taste to leave it there.

Perl Weekly #676 - Perl and OpenAI

dev.to #perl

Published by Gabor Szabo on Monday 08 July 2024 08:08

Originally published at Perl Weekly 676

hi there,

I am not qualified to give my opinion on OpenAI. I have noticed Curtis has an opinion and widely respected too. If you haven't read then I would highly recommend you please do, e.g. Will You Loose Your Job to AI?, Claude Sonnet 3.5 beats ChatGPT 4.0 and Building an iPhone App with ChatGPT.

How about Perl dealing with the OpenAI? We have another post, An OpenAI Chatbot in Perl, where you will find the detailed discussion on how you can use the core OOP with OpenAI. Talking about Corinna, we are aware the progress is slow and steady. Having said, there is still plenty of work needed to be done. There is a dicussion How you can help get Corinna in the core faster? on reddit. Feel free to share your views and if possible offer your help to speed up the work.

With the recent release of Perl v5.40, you can find out the details of core ehancements in Perl v5.40.0 Shows That It Is Too Resilient To Die and What's New in Perl v5.40?.

Dave Cross released a new CPAN module App::MergeCal and shared his story behind it in the post: Combining calendars.

Enjoy rest of the newsletter and please look after yourself.

--
Your editor: Mohammad Sajid Anwar.

Articles

An OpenAI Chatbot in Perl

Find out how to use the latest core OOP syntax to create OpenAI Chatbot.

Combining calendars

Get to know the story behind the CPAN module: App::MergeCal.

Perl v5.40.0 Shows That It Is Too Resilient To Die

If you missed the latest release Perl v5.40 then you must checkout this to find out more about the core enhancements in the latest release.

Announcements

New Standards of Conduct published

TPRF has created a new Standard of Conduct to help combat bullying, harassment and abuse in our communities.

The corner of Gabor

A couple of entries sneaked in by Gabor.

Continuous Integration (CI): GitHub Actions for Perl Projects (Free Virtual presentation on August 4)

This events was postponed to August 4. In this virtual event you will learn why and how to use GitHub Actions as a CI system for your Perl projects. The meeting is free of charge thanks to my supporters via Patreon and GitHub. Besides this event I am running many more, so make sure you check the Code Mavens meetup group and also register to it.

GitHub Pages for Perl developers (Free Virtual presentation on August 15)

In this virtual event you will learn how to use Markdown and GitHub Pages to create a simple web site and then we'll extend our use of GitHub Actions to generate the site using Perl. Register now!

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

Welcome to a new week with a couple of fun tasks "Count Common" and "Strong Pair". 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 - 276

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

TWC276

Compact yet powerful solutions in Perl shared in the post. Well done.

Completed and Maximum Frequency Days

Check out the comparison of Prolog, C and Perl. The analysis is worth reading.

Complete Maximum

Power of Raku made the difficult task easy and at times allow to create elegant one-liner. Thanks for contributing.

Hourly Frequencies

PDL once again showing the cool features. The end result is not be missed. Keep it up great work.

Perl Weekly Challenge 276: Complete Day

Building combinations function of Raku in Perl can be so easy and simple. Thanks for sharing knowledge with us.

Perl Weekly Challenge 276: Maximum Frequency

Method chaining of Raku makes the code compact and elegant. Raku Rocks !!!

filtering arrays

Raku one-liner is showing method chaining and giving us effective solution. Thanks for your contributions.

Perl Weekly Challenge 276

Unique hack used in this week's Perl solution. Well done.

Complete Maximum Day Frequency

Smart use of CPAN module makes the code short and easy to follow. Great work, keep it up.

Round days and frequent numbers

I noticed the use of v5.26 and few other bits. I am sure it would work with the latest release too (v5.40). Well done.

The Weekly Challenge - 276

As always, we see the use of CPAN modules again. All heavy lifting done by the modules, rest is just a thin layer on top. Keep it up great work.

The Weekly Challenge #276

Clever use of CPAN modules is very handy. Happy to see the wide use of the modules. Keep sharing the knowledge.

Frequency Day is Complete

Lua is the pick of the language this week. I really enjoy the varieties each week. Highly recommended.

Maximum Frequency and now my Day is Complete

Welcome back to blogging and thanks for introduction to Python. It is always pleasure to have your post. Thank you.

Complete frequency

For me, it is the source of Python magics. Thanks for introducting Counters function. Thanks for your contributions.

Rakudo

2024.27 Concurrency Learnings

Weekly collections

NICEPERL's lists

Great CPAN modules released last week.

Events

Boston.pm monthly meeting

July 9, 2024, Virtual event

Purdue Perl Mongers

July 10, 2024, Virtual event

Continuous Integration (CI): GitHub Actions for Perl Projects

August 4, 2024, in Zoom

Toronto Perl Mongers monthly meeting

July 25, 2024, Virtual event

London Perl and Raku Workshop

October 26, 2024, in London, UK

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.

Combining calendars

Perl Hacks

Published by Dave Cross on Sunday 07 July 2024 10:35

One of the most popular posts I’ve written in recent months was the one where I talked about all the pointless personal projects I have. The consensus in the many comments I received was that anything you find useful isn’t pointless. And I can’t really argue with that.

But it’s nice when one of your projects is used by other people. And that happened to me recently.

The initial commit in mergecal is from 2016, but I strongly suspect it existed as code that wasn’t in source code control for several years before that. The idea behind it is simple enough. I wanted to be able to share my calendar with someone, but I didn’t have a single iCal file that I could share. For various complicated and yet dull reasons, my calendar is split across a number of separate iCal files. Initially, I remember thinking there must be an online service that will take a list of iCal calendars and produce a single, combined one. But a few hours on Google didn’t find anything so I did what any hacker would do and wrote my own.

It really wasn’t difficult. As usual, it was just a case of plumbing together a few CPAN modules. In this case, Text::vFile::asData did most of the heavy lifting – with JSON used to parse a configuration file. It can’t have taken more than an hour to write. And, as the commit history shows, very few subsequent changes were required. I just set it up with the correct configuration and a cronjob that rebuilt the combined calendar once a day and published it on my web site.

And then I forgot about it for years. The best kind of software.

Then, in January of this year, I got a pull request against the code. This astonished me. MY SOFTWARE HAD A USER. And in the PR, the user said “It boggles my mind that there is still no simpler free solution, even after all those years”.

So maybe this would be useful to a few more people. Perhaps I should market it better (where “better” means “at all”).

As a first step towards that, I’ve rewritten it and released it to CPAN as App::MergeCal. Maybe I should think about putting it online as some kind of web service.

Anyway, it makes me incredibly happy to know my software is used by even one person. Which reminds me – please take the time to say “thank you” to anyone whose software you find useful. It’s a small thing, but you’ll make someone very happy.

The post Combining calendars first appeared on Perl Hacks.

(diii) 8 great CPAN modules released last week

Niceperl

Published by Unknown on Saturday 06 July 2024 23:16

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::perlimports - Make implicit imports explicit
    • Version: 0.000055 on 2024-07-04, with 18 votes
    • Previous CPAN version: 0.000054 was 5 days before
    • Author: OALDERS
  2. DBD::mysql - A MySQL driver for the Perl5 Database Interface (DBI)
    • Version: 5.007 on 2024-07-01, with 56 votes
    • Previous CPAN version: 5.006 was 27 days before
    • Author: DVEEDEN
  3. Firefox::Marionette - Automate the Firefox browser with the Marionette protocol
    • Version: 1.59 on 2024-06-30, with 16 votes
    • Previous CPAN version: 0.77 was 4 years, 11 months, 23 days before
    • Author: DDICK
  4. IO::Socket::SSL - Nearly transparent SSL encapsulation for IO::Socket::INET.
    • Version: 2.086 on 2024-07-03, with 49 votes
    • Previous CPAN version: 2.085 was 5 months, 12 days before
    • Author: SULLR
  5. Kelp - A web framework light, yet rich in nutrients.
    • Version: 2.17 on 2024-07-06, with 44 votes
    • Previous CPAN version: 2.12 was 10 days before
    • Author: BRTASTIC
  6. Module::CoreList - what modules shipped with versions of perl
    • Version: 5.20240702 on 2024-07-02, with 43 votes
    • Previous CPAN version: 5.20240609 was 23 days before
    • Author: BINGOS
  7. Net::AMQP::RabbitMQ - interact with RabbitMQ over AMQP using librabbitmq
    • Version: 2.40012 on 2024-07-04, with 15 votes
    • Previous CPAN version: 2.40011 was 11 days before
    • Author: MSTEMLE
  8. Syntax::Keyword::Match - a match/case syntax for perl
    • Version: 0.15 on 2024-07-04, with 13 votes
    • Previous CPAN version: 0.14 was 2 months, 4 days before
    • Author: PEVANS

Marrying Perl to Assembly

dev.to #perl

Published by chrisarg on Thursday 04 July 2024 18:34

This is probably one of the things that should never be allowed to exist, but why not use Perl and its capabilities to inline foreign code, to FAFO with assembly without a build system? Everything in a single file! In the process one may find ways to use Perl to enhance NASM and vice versa. But for now, I make no such claims : I am just using the perlAssembly git repo to illustrate how one can use Perl to drive (and learn to code!) assembly programs from a single file.
(Source code may be found in the perlAssembly repo )

x86-64 examples

Adding Two Integers

Simple integer addition in Perl - this is the Hello World version of the perlAssembly repo
But if we can add two numbers, why not add many, many more?

The sum of an array of integers

Explore multiple equivalent ways to add large arrays of short integers (e.g. between -100 to 100) in Perl. The Perl and the C source files contain the code for:

  • ASM_blank : tests the speed of calling ASM from Perl (no computations are done)
  • ASM : passes the integers as bytes and then uses conversion operations and scalar floating point addition
  • ASM_doubles : passes the array as a packed string of doubles and do scalar double floating addition in assembly
  • ASM_doubles_AVX: passes the array as a packed string of doubles and do packed floating point addition in assembly
  • ForLoop : standard for loop in Perl
  • ListUtil: sum function from list utilities
  • PDL : uses summation in PDL

Scenarios w_alloc : allocate memory for each iteration to test the speed of pack, those marked
as wo_alloc, use a pre-computed data structure to pass the array to the underlying code.
Benchmarks of the first scenario give the true cost of offloading summation to of a Perl array to a given
function when the source data are in Perl. Timing the second scenario benchmarks speed of the
underlying implementation.

This example illustrates

  • an important (but not the only one!) strategy to create a data structure that is suitable for Assembly to work with, i.e. a standard array of the appropriate type, in which one element is laid adjacent to the previous one in memory
  • the emulation of declaring a pointer as constant in the interface of a C function. In the AVX code, we don't FAFO with the pointer (RSI in the calling convention) to the array directly, but first load its address to another register that we manipulate at will.

Results

Here are the timings!

mean median stddev
ASM_blank 2.3e-06 2.0e-06 1.1e-06
ASM_doubles_AVX_w_alloc 3.6e-03 3.5e-03 4.2e-04
ASM_doubles_AVX_wo_alloc 3.0e-04 2.9e-04 2.7e-05
ASM_doubles_w_alloc 4.3e-03 4.1e-03 4.5e-04
ASM_doubles_wo_alloc 8.9e-04 8.7e-04 3.0e-05
ASM_w_alloc 4.3e-03 4.2e-03 4.5e-04
ASM_wo_alloc 9.2e-04 9.1e-04 4.1e-05
ForLoop 1.9e-02 1.9e-02 2.6e-04
ListUtil 4.5e-03 4.5e-03 1.4e-04
PDL_w_alloc 2.1e-02 2.1e-02 6.7e-04
PDL_wo_alloc 9.2e-04 9.0e-04 3.9e-05

Let's say we wanted to do this toy experiment in pure C (using Inline::C of course!)
This code obtains the integers as a packed "string" of doubles and forms the sum in C

double sum_array_C(char *array_in, size_t length) {
    double sum = 0.0;
    double * array = (double *) array_in;
    for (size_t i = 0; i < length; i++) {
        sum += array[i];
    }
    return sum;
}

Here are the timing results:

mean median stddev
C_doubles_w_alloc 4.1e-03 4.1e-03 2.3e-04
C_doubles_wo_alloc 9.0e-04 8.7e-04 4.6e-05

What if we used SIMD directives and parallel loop constructs in OpenMP? All three combinations were tested, i.e. SIMD directives
alone (the C equivalent of the AVX code), OpenMP parallel loop threads and SIMD+OpenMP.
Here are the timings!

mean median stddev
C_OMP_w_alloc 4.0e-03 3.7e-03 1.4e-03
C_OMP_wo_alloc 3.1e-04 2.3e-04 9.5e-04
C_SIMD_OMP_w_alloc 4.0e-03 3.8e-03 8.6e-04
C_SIMD_OMP_wo_alloc 3.1e-04 2.5e-04 8.5e-04
C_SIMD_w_alloc 4.1e-03 4.0e-03 2.4e-04
C_SIMD_wo_alloc 5.0e-04 5.0e-04 8.9e-05

Discussion of the sum of an array of integers example

  • For calculations such as this, the price that must be paid is all in memory currency: it takes time to generate these large arrays, and for code with low arithmetic intensity this time dominates the numeric calculation time.
  • Look how insanely effective sum in List::Util is : even though it has to walk the Perl array whose elements (the doubles, not the AV*) are not stored in a contiguous area in memory, it is no more than 3x slower than the equivalent C code C_doubles_wo_alloc.
  • Look how optimized PDL is compared to the C code in the scenario without memory allocation.
  • Manual SIMD coded in assembly is 40% faster than the equivalent SIMD code in OpenMP (but it is much more painful to write)
  • The threaded OpenMP version achieved equivalent performance to the single thread AVX assembly programs, with no obvious improvement from combining SIMD+parallel loop for pragmas in OpenMP.
  • For the example considered here, it thus makes ZERO senso to offload a calculation as simple as a summation because ListUtil is already within 15% of the assembly solution (at a latter iteration we will also test AVX2 and AVX512 packed addition to see if we can improve the results).
  • If however, one was managing the array, not as a Perl array, but as an area in memory through a Perl object, then one COULD consider offloading. It may be fun to consider an example in which one adds the output of a function that has an efficient PDL and assembly implementation to see how the calculus changes (in the to-do list for now).

Disclaimer

The code here is NOT meant to be portable. I code in Linux and in x86-64, so if you are looking into Window's ABI or ARM, you will be disappointed. But as my knowledge of ARM assembly grows, I intend to rewrite some examples in Arm assembly!

How can we get and set the OpenMP environment from Perl?

dev.to #perl

Published by chrisarg on Thursday 04 July 2024 18:15

Those who attended the TPRC2024 conference last week, had the opportunity to listen to Brett Estrade talking about intermediate uses of OpenMP in Perl.
(If you had not had the chance to go, well here is his excellent talk).

While OpenMP is (probably) the most popular and pain-free way to add parallelization to one's C/C++/Fortran code, it can also be of great value
when programming in dynamic languages such as Perl (indeed I used OpenMP to add parallelization to
some bioinformatics codes as I am discussing in this preprint). OpenMP's runtime environment provides a way to control many aspects of
parallelization from the command-line. The OpenMP Perl application programmer can use Brett's excellent OpenMP::Environment
module to set many of these environmental variables. However, these changes must make it to the C(C++/Fortran) side to affect the OpenMP code ; in the absence of an explicit
readout of the environment from the C code, one's parallel Perl/C code will only use the environment as it existed when the Perl application was fired, not the environment as
modified by the Perl application.

This blog post will show a simple OpenMP Perl/C program that is responsive to changes of the environment (scheduling of threads, number of threads) from within the Perl part
of the application. It makes use of the Alien::OpenMP and OpenMP::Environment to set up
the compilation flags and the environment respectively. The code itself is very simple:

  1. It sets up the OpenMP environment from within Perl
  2. It jumps to C universe to set and print these variables and return their values back to Perl for printing and verification
  3. It runs a simple parallel loop to show that the numbers of threads were run correctly.

So here is the Perl part:


use v5.38;
use Alien::OpenMP;
use OpenMP::Environment;
use Inline (
    C    => 'DATA',
    with => qw/Alien::OpenMP/,
);

my $env = OpenMP::Environment->new();
$env->omp_num_threads(5);

say $env->omp_schedule("static,1");
my $num_of_OMP_threads = get_thread_num();
printf "Number of threads = %d from within Perl\n",$num_of_OMP_threads;
my $schedule_in_C = get_schedule_in_C();
say "Schedule from Perl: $schedule_in_C";

test_omp();
__DATA__
__C__

And here is the C part (which would ordinarly follow the __C__ token (but we parsed it out to highlight the C syntax).


#include <omp.h>
#include <stdlib.h>
#include <string.h>

void set_openmp_schedule_from_env() {
    char *schedule_env = getenv("OMP_SCHEDULE");
    if (schedule_env != NULL) {
        char *kind_str = strtok(schedule_env, ",");
        char *chunk_size_str = strtok(NULL, ",");

        omp_sched_t kind;
        if (strcmp(kind_str, "static") == 0) {
            kind = omp_sched_static;
        } else if (strcmp(kind_str, "dynamic") == 0) {
            kind = omp_sched_dynamic;
        } else if (strcmp(kind_str, "guided") == 0) {
            kind = omp_sched_guided;
        } else {
            kind = omp_sched_auto;
        }
        int chunk_size = atoi(chunk_size_str);
        omp_set_schedule(kind, chunk_size);
    }
}

char * get_schedule_in_C() {
    int chunk_size;
    omp_sched_t kind;

    set_openmp_schedule_from_env();
    omp_get_schedule(&kind, &chunk_size);
    printf("Schedule in C: %x\n",kind);
    printf("Schedule from env %s\n",getenv("OMP_SCHEDULE"));
    return getenv("OMP_SCHEDULE");

}

int get_thread_num() {
    int num_threads = atoi(getenv("OMP_NUM_THREADS"));
    omp_set_num_threads(num_threads);
    printf("Number of threads = %d from within C\n",num_threads);
    return num_threads;
}

int test_omp() {
    int n = 0;
    #pragma omp parallel for schedule(runtime)
    for (int i = 0; i < omp_get_num_threads(); i++) {
        int chunk_size;
        omp_sched_t kind;
        omp_get_schedule(&kind, &chunk_size);
        printf("Schedule in C: %x as seen from thread %d\n",kind,omp_get_thread_num());
    }
    return n;
}

The Perl and C parts use functions from OpenMP::Environment and omp.h to get/set the environment. The names are rather self explanatory, so will save everyone space and not repeat them.
The general idea is that one sets those variables in Perl and then heads over to C, to get the variable names and set them again in C. To make a parallel loop responsive to
these changes, one would also like to set the schedule to runtime, rather than the default value, using the appropriate clause as in:


    #pragma omp parallel for schedule(runtime)

The output of the code is :

static,1
Number of threads = 5 from within C
Number of threads = 5 from within Perl
Schedule in C: 1
Schedule from env static
Schedule from Perl: static
Schedule in C: 1 as seen from thread 0
Schedule in C: 1 as seen from thread 3
Schedule in C: 1 as seen from thread 1
Schedule in C: 1 as seen from thread 4

confirming that we used 5 threads and static scheduling. Note that the numerical code used internally by the OpenMP runtime for static scheduling is 1, but in any case we also read the value as text in C from the environment and sent it back to Perl, as we did, if we have to be 100% sure that we got what asked for.

Since one of the main reasons to use Perl with OpenMP is to benchmark different runtime combinations for speed, I use the clause schedule(runtime) in all my Perl/OpenMP codes!
Hopefully these snippets can be of use to those experimenting with OpenMP applications in Perl!

New Standards of Conduct published

Perl Foundation News

Published by D Ruth Holloway on Thursday 04 July 2024 12:20

The Board of the The Perl and Raku Foundation has created a new Standard of Conduct to help combat bullying, harassment, and abuse in our communities. It is designed to help protect anyone (paid or volunteer, in-person attendee or remote worker) who is doing the work of the Foundation in promoting and advancing the Perl and Raku programming languages. I did a talk on the new Standards at TPRC in Las Vegas last week, and you can watch the video on YouTube to learn more about our rationale, scope, and implementation details.

The current official version of the document is visible on GitHub, at https://github.com/tpf/soc/blob/main/Standards_of_Conduct.md. The new Standards will take effect on August 1, and the time between now and then is a public-comment period. There are still minor amendments under way with the Board, and the document will be updated near the end of July with those amendments. If you have constructive feedback on these new Standards, we'd love to hear them! You can reach me via email.

The inaugural Response Team has been created, with these members of our communities stepping up to serve:

  • Ruth Holloway, Board Member, Team Lead
  • Peter Krawczyk, Board Member
  • Abigail
  • T. Alex Beamish
  • Jason Crome
  • Sarah Gray
  • Matthew Stuckwisch

Reports of violations of these new standards after August 1 should be sent via email to soc@perlfoundation.org, as that email address is the only supported reporting mechanism in the new Standards.

List of new CPAN distributions – Jun 2024

Perlancar

Published by perlancar on Monday 01 July 2024 00:07

dist author abstract date
Alien-RtAudio JBARRETT Install RtAudio 2024-06-23T15:44:22
Alien-SunVox JBARRETT Install The SunVox Library – Alexander Zolotov's SunVox modular synthesizer and sequencer 2024-06-20T09:22:51
Alien-libextism EXTISM find or build and install libextism with development dependencies 2024-06-06T03:28:08
Aozora2Epub YOSHIMASA Convert Aozora Bunko XHTML to EPUB 2024-06-14T10:10:23
App-ArticleWrap SCHROEDER word wrap news articles or mail files 2024-06-28T11:16:03
App-BPOMUtils-NutritionLabelRef PERLANCAR Get one or more values from BPOM nutrition label reference (ALG, acuan label gizi) 2024-06-05T00:06:03
App-CommonPrefixUtils PERLANCAR Utilities related to common prefix 2024-06-01T00:05:57
App-CommonSuffixUtils PERLANCAR Utilities related to common suffix 2024-06-02T00:06:21
App-KemenkesUtils-RDA PERLANCAR Get one or more values from Indonesian Ministry of Health's RDA (AKG, angka kecukupan gizi, from Kemenkes) 2024-06-12T00:06:32
App-NKC2MARC SKIM Tool to fetch record from National library of the Czech Republic to MARC file. 2024-06-26T07:14:52
App-Timestamper-Log-Process SHLOMIF various filters and queries for App::Timestamper logs. 2024-06-09T04:42:04
App-runscript SVW Module that implements the runscript utility 2024-06-25T08:11:16
Audio-SunVox-FFI JBARRETT Bindings for the SunVox library – a modular synthesizer and sequencer 2024-06-22T11:40:41
Bio-SeqAlignment-Applications-SequencingSimulators-RNASeq-Polyester CHRISARG Skeleton package that does nothing but reserve the namespace. 2024-06-09T13:20:02
Bio-SeqAlignment-Components-Libraries-edlib CHRISARG basic edlib library 2024-06-13T03:23:35
Bio-SeqAlignment-Components-SeqMapping CHRISARG Imports all modules relevant to sequence mapping 2024-06-10T04:15:38
Bio-SeqAlignment-Components-Sundry CHRISARG Miscellaneous components for building awesome sequencing apps. 2024-06-09T16:30:30
Bio-SeqAlignment-Examples-EnhancingEdlib CHRISARG Parallelizing Edlib with MCE, OpenMP using Inline and FFI::Platypus 2024-06-13T01:02:44
Bio-SeqAlignment-Examples-TailingPolyester CHRISARG "Beefing" up the RNA sequencing simulator polyester with polyA tails 2024-06-12T12:26:38
Bot-Telegram VASYAN A micro^W nano framework for creating telegram bots based on WWW::Telegram::BotAPI 2024-06-17T11:13:27
CXC-DB-DDL-Field-Pg DJERIUS DBD::Pg specific Field class 2024-06-27T14:28:18
DWIM-Block DCONWAY Use AI::Chat without having to write the infrastructure code 2024-06-26T22:36:44
Data-Checks PEVANS XS functions to assist in value constraint checking 2024-06-19T13:26:59
Data-ISO8583 CADE 2024-06-08T22:52:33
Data-Tranco GBROWN An interface to the Tranco domain list. 2024-06-03T13:35:31
DateTime-Schedule TYRRMINAL Determine scheduled days in range based on inclusions/exclusions 2024-06-11T20:45:23
Devel-StatProfiler MBARBON low-overhead sampling code profiler 2024-06-24T21:51:40
ExtUtils-Typemaps-Misc LEONT A collection of miscelaneous typemap templates 2024-06-20T19:43:50
Extism EXTISM Extism Perl SDK 2024-06-06T04:07:08
Filter-Syntactic DCONWAY Source filters based on syntax, instead of luck 2024-06-26T22:39:31
Graphics-ColorNamesCMYK-All PERLANCAR CMYK colors from all Graphics::ColorNamesCMYK::* 2024-06-03T00:06:12
HATX HOEKIT A fluent interface for Hash and Array Transformations 2024-06-28T13:43:31
Kelp-Module-Beam-Wire BRTASTIC Beam::Wire dependency injection container for Kelp 2024-06-02T14:32:03
Kelp-Module-YAML BRTASTIC YAML encoder / decoder for Kelp 2024-06-24T19:18:49
Math-Recaman SIMONW Calculate numbers in Recamán's sequence 2024-06-25T17:25:03
Multi-Dispatch DCONWAY Multiple dispatch for Perl subs and methods 2024-06-26T22:42:28
RT-Extension-SMSWebhook-Twilio BPS RT-Extension-SMSWebhook-Twilio Extension 2024-06-13T22:40:55
Raylib-FFI PERIGRIN Perl FFI bindings for raylib 2024-06-27T05:58:30
SMS-Send-CZ-Smsmanager RADIUSCZ SMS::Send driver for SMS Manager – Czech Republic 2024-06-10T20:58:38
SPVM-R KIMOTO Porting R language Features 2024-06-26T05:10:09
Sah-PSchemaBundle PERLANCAR Convention for Sah-PSchemaBundle-* distribution 2024-06-06T00:06:05
Sah-PSchemaBundle-Array PERLANCAR Parameterized schemas related to array type 2024-06-07T00:06:17
Sah-PSchemaBundle-Perl PERLANCAR Parameterized schemas related to Perl 2024-06-08T00:06:02
Sah-PSchemaBundle-Re PERLANCAR Various regular-expression (parameterized) schemas 2024-06-09T00:05:56
Sah-SchemaBundle-CPAN PERLANCAR Sah schemas related to CPAN 2024-06-15T00:07:21
Sah-SchemaBundle-Chrome PERLANCAR Various Sah schemas related to Google Chrome 2024-06-12T00:06:44
Sah-SchemaBundle-Code PERLANCAR Various schemas related to 'code' type and coderefs 2024-06-10T04:51:45
Sah-SchemaBundle-Collection PERLANCAR Various Sah collection (array/hash) schemas 2024-06-16T00:05:16
Sah-SchemaBundle-Color PERLANCAR Sah schemas related to color codes/names 2024-06-12T00:06:55
Sah-SchemaBundle-ColorScheme PERLANCAR Sah schemas related to color schemes 2024-06-23T15:45:50
Sah-SchemaBundle-ColorTheme PERLANCAR Sah schemas related to ColorTheme 2024-06-30T00:05:31
Sah-SchemaBundle-Nutrient PERLANCAR Sah schemas related to nutrients 2024-06-04T02:10:55
SpeL-Wizard WDAEMS engine to build audio files from the spel files generated by SpeL and maintain their up-to-dateness 2024-06-10T08:18:20
SpeL-Wizard-20240610-TRIAL WDAEMS engine to build audio files from the spel files generated by SpeL and maintain their up-to-dateness 2024-06-10T08:02:44
String-Random-Regexp-regxstring BLIAKO Generate random strings from a regular expression 2024-06-28T23:27:57
Switch-Back DCONWAY given/when for a post-given/when Perl 2024-06-26T22:42:39
Switch-Right DCONWAY Switch and smartmatch done right this time 2024-06-26T22:45:36
Sys-GetRandom-PP MAUKE pure Perl interface to getrandom(2) 2024-06-15T05:21:14
Tags-HTML-Footer SKIM Tags helper for HTML footer. 2024-06-03T15:29:04
Tags-HTML-Message-Board SKIM Tags helper for message board. 2024-06-03T16:01:31
XDR-Gen EHUELS Generate (de)serializers for XDR definitions 2024-06-08T15:05:53

Stats

Number of new CPAN distributions this period: 61

Number of authors releasing new CPAN distributions this period: 29

Authors by number of new CPAN distributions this period:

No Author Distributions
1 PERLANCAR 17
2 CHRISARG 6
3 DCONWAY 5
4 SKIM 3
5 JBARRETT 3
6 EXTISM 2
7 WDAEMS 2
8 BRTASTIC 2
9 LEONT 1
10 GBROWN 1
11 EHUELS 1
12 DJERIUS 1
13 YOSHIMASA 1
14 CADE 1
15 BPS 1
16 BLIAKO 1
17 SVW 1
18 KIMOTO 1
19 VASYAN 1
20 PEVANS 1
21 TYRRMINAL 1
22 SCHROEDER 1
23 HOEKIT 1
24 SIMONW 1
25 SHLOMIF 1
26 MAUKE 1
27 RADIUSCZ 1
28 PERIGRIN 1
29 MBARBON 1

trying to cope with Slack’s BlockKit

rjbs forgot what he was saying

Published by Ricardo Signes on Sunday 30 June 2024 12:00

The other day, a concatenation of circumstances led me to thinking about the lousy state of sending formatted text to Slack. We have a bot called Synergy at work, and the bot posts lots of content. Mostly it’s plain text, but sometimes we have it send text with bold or links. This is for a couple reasons. Our bot supports channels other than Slack (like SMS and Discord and the console), so we can’t express everything in Slack-oriented terms. But even doing so would be hard, because of the APIs involved.

Slack’s APIs are dreadful, and not in the usual ways. At first glance, they look fairly modern and straightforward. Maybe they seem a bit over-engineered, but Slack is a large-scale system, and some of that is to be expected. But when you really start using them, they’re surprisingly painful. Common patterns turn out to have weird exceptions. Things don’t compose because of seemingly-arbitrary restrictions. The documentation seems auto-generated, with all that entails: missing context, lack of an overview of any given abstraction, no helpful hints. Auto-generated documentation is, at least, usually accurate and comprehensive in the methods and types provided, because it comes from the source code. Unhappily, the Slack documentation is frequently inaccurate.

sending text isn’t good enough

So, as I said, the state of the Slack APIs and developer ecosystem is such that I’ve avoided trying to get more out of it. Then again, the kind of formatting we can use easily in Synergy’s messages is not great. It usually uses roughly this:

await $slack->api_call('chat.postMessage', {
  text    => $text,
  channel => $channel,
  as_user => jtrue(),
});

Nice and simple! So, how does this get us rich text? Well, the $text content just gets formatted with Markdown! No, sorry, wait… with mrkdwn. The Slack “mrkdwn” format is like Markdown, but worse. It differs in how bold, italic, and link work, at least. Maybe other things, too. You can disable this, but then you just get plain text, which has its own problems.

This is an actual, practical problem. When we display search results from our work tracker, Linear, imagine we find an issue called “problems with Secure::Key::HSM”. This will get displayed as “problems with Secure:🔑:HSM” because mrkdwn is always on the lookout for emoji colon codes.

mrkdwn is intended for human writers, just like Markdown is intended for human writers. (That said, I don’t actually know whether a human can avoid that problem above.) If you want your software to write rich text output, you should use a less ambiguous, tricky format. For example, HTML. In Slack, the format provided is BlockKit and especially its “rich text” blocks. BlockKit is a (mediocre) object model for describing content that Slack can display in many different contexts (called “surfaces”), like: modal dialogs, messages, canvases, and more. Instead of supplying a hunk of mrkdwn, you can supply an array of “blocks”, and Slack will display them. Blocks are not ambiguous. Take the problematic Linear issue from the last paragraph. The form we want would be expressed in BlockKit like this:

[ {
  "type": "section",
  "text": { "type": "plain_text", "text": "problems with Secure::Key::HSM" }
} ]

Great! (The bad form is actually exactly the same, but replace plain_text with mrkdwn.)

sending rich text is a big pain

But let’s say that in the message above, you wanted to call them “serious problems”, with the italics. You can’t use plain text, because you want italics. You can’t use mrkdwn, because you’d get that emoji. You need a rich text block. Like so:

[
  {
    "type": "rich_text",
    "elements": [
      {
        "type": "rich_text_section",
        "elements": [
          {
            "type": "text",
            "text": "serious",
            "style": { "italics": true }
          },
          {
            "type": "text",
            "text": " problems with Secure::Key::HSM"
          }
        ]
      }
    ]
  }
]

Kinda great, but tedious. Unambiguous, but awful to write.

Also, there’s a bug. I put “italics” when I should’ve put “italic”. No problem, because you can easily expect an error like this:

Unknown property "italics" at /0/elements/0/elements/style

Not great, but gets the job done, right? Well, the problem is that while you can easily expect that, you won’t get it. What you get is this:

invalid_blocks

No matter how serious or trivial the error, and no matter where it is, that’s what you get. That is the entire body of the response to sending any invalid message. Then you try to go re-read the documentation about how it should work, and you pour over each and every element in the structure and the corresponding documentation. Worse, that documentation, as I said, is bad. I found at least a handful of errors (now reported). The combination of (bad docs) and (bad error messages) and (wordy structure) made it easy to sigh and go on using using (sigh) mrkdwn.

making it hard to screw up

Well, now I didn’t want to do that anymore, so I wrote a bunch of classes, representing each of the kinds of blocks. (More on “kinds of blocks” below.)

Here’s a piece of rich text I generated for testing:

Here is a safe link: click me

  • it will be fun
  • it will be cool 🙂
  • it will be enough

This is easy to type, and simple, and I wanted it to be easy to program.

Here’s the code for that four line Slack rich text:

my $blocks = Slack::BlockKit::BlockCollection->new({
  blocks => [
    Slack::BlockKit::Block::RichText->new({
      elements => [
        Slack::BlockKit::Block::RichText::Section->new({
          elements => [
            Slack::BlockKit::Block::RichText::Text->new({
              text => "Here is a ",
            }),
            Slack::BlockKit::Block::RichText::Text->new({
              text  => "safe",
              style => { italic => 1 },
            }),
            Slack::BlockKit::Block::RichText::Text->new({
              text => " link: ",
            }),
            Slack::BlockKit::Block::RichText::Link->new({
              text  => "click me",
              unsafe => 1,
              url   => "https://fastmail.com/",
              style => { bold => 1 },
            }),
          ],
        }),
        Slack::BlockKit::Block::RichText::List->new({
          style => 'bullet',
          elements => [
            Slack::BlockKit::Block::RichText::Section->new({
              elements => [
                Slack::BlockKit::Block::RichText::Text->new({
                  text => "it will be fun",
                }),
              ]
            }),
            Slack::BlockKit::Block::RichText::Section->new({
              elements => [
                Slack::BlockKit::Block::RichText::Text->new({
                  text => "it will be cool",
                }),
                Slack::BlockKit::Block::RichText::Emoji->new({
                  name => 'smile',
                }),
              ]
            }),
            Slack::BlockKit::Block::RichText::Section->new({
              elements => [
                Slack::BlockKit::Block::RichText::Text->new({
                  text => "it will be enough",
                }),
              ],
            }),
          ],
        }),
      ],
    })
  ]
});

Okay, the good news is that if I screw up on any property or type, this code will give me an error message that tells me a lot more about what happened, and it happens before we try to send the reply. The error message isn’t great, but it will be something roughly like “Slack::BlockKit::Block::RichText::Text object found where ExpansiveBlockArray expected in Section constructor”. Maybe a little worse. But it’s descriptive, it has a stack trace, and it happens client-side.

The bad news is that it took 57 lines of Perl, mostly fluff, to generate four lines of text. This made me sour, so I needed some sugar:

use Slack::BlockKit::Sugar -all => { -prefix => 'bk_' };
bk_blocks(
  bk_richblock(
    bk_richsection(
      "Here is a ", bk_italic("safe"), " link: ",
      bk_link("https://fastmail.com/", "click me", { style => { bold => 1 } }),
    ),
    bk_ulist(
      "it will be fun",
      bk_richsection("it will be cool", bk_emoji('smile')),
      "it will be enough",
    ),
  )
);

This is 13 lines. Maybe it could be shorter, but not much. All the same type checking applies. Also, each function in there has a reusable return value, so you could do things like:

# provide either an ordered List of 2+ Sections or just one Section
my @reasons = gather_reasons();
return bk_blocks(@reasons > 1 ? bk_olist(@reasons) : @reasons);

how does it work?

It’s practically not worth explaining how it works. It is almost the definition of “a simple matter of programming”. You can read the source for Slack::BlockKit on GitHub. It’s a bunch of Moose classes with type constraints and a few post-construction validation routines. I think it’s a pretty decent example of how Moose can be useful. Moose made it easy to make the whole thing work by letting me decompose the problem into a few distinct parts: a role for elements with “style”, a set of types (like for “which kinds of elements can be children of this block”), and BUILD submethods for validating one-off quirks that can’t be expressed in type constraints.

The thing worth nothing, maybe, is how it doesn’t work. It isn’t auto-generated code. It’d be pretty nice if Slack was publishing some data description that could automatically generate an API, maybe with some sugar. I don’t normally enjoy that sort of thing, but it’d probably be better than doing this by hand and then digging for exceptions, right? Anyway, they don’t do that, so I wrote this by hand. It felt silly, but it was only a few hours of work, much of it done while on a road trip.

some of the problems I encountered

I feel a bit childish calling out the problems with the BlockKit API (or its documentation), but I’m going to do it anyway.

First, I’ll say that my biggest problem is the lack of a clear object model. The term “block” and “object” and “element” are used without much clear distinction. It might be safe to say “anything with a block_id propety is a block”. Beyond that, I wouldn’t bet much. Many Block types have an elements property. Some say they contain “objects” and some say “elements”. A rich_text_list thing might be an object, or maybe an element? Or maybe an element is a kind of object? There’s also a kind of object called a “composition object”, which just seems to be another name for “types we will reuse”. I can’t tell if a composition object is substantially different from an “element”. They have their own page in the docs, anyway.

This isn’t a huge deal, but a hierarchy of types makes it easier to build a system that has to represent… well, a hierarchy of types!

non-isolated type definition

Next, the types that do exist are not clearly separated. The most jarring example of this might be:

  1. some of the rich text blocks can contain, in their elements, “link” objects
  2. “link” objects have a set of styles, chosen from { bold, code, italic, strike }
  3. …but the “link” objects contained in a “preformatted” rich text block can only have bold or italic styles

So, the type definition for a link object isn’t a complete definition, it’s contingent on the context. To verify the object, you have to put the verification into the parent: when constructed, a RichText::Preformatted object must scan its children for Link objects and raise an error based on their styling. (The alternative would be to have a distinct PrefomattedLink type, which sounds worse.)

But actually the alternative is to do nothing. This restriction isn’t enforced, and in fact using the strike style works! (I can’t say whether the code style works, since by definition a link in a preformatted section will be in code style.)

missing or bogus properties

The text object (not to be confused with the text composition object) exists almost entirely to pass along its text and style properties for rending. But the text property isn’t documented. It appears in nearly every example, though, so you can figure that one out.

Quite a few blocks are documented as having pixel-count properties, like the border property on the list block. When used at all, these trigger an invalid_blocks error. Possibly their validity is related to the surface onto which they’re rendered, but I can’t find any documentation of this.

Other properties have incorrect type definitions. The preformatted block says its elements can contain channel, emoji, user, and usergroup objects. Trying to use any of those, though, will get an error. Only link and text objects actually work.

what’s next?

I filed an pull request against Slack::Notify, which Rob N★ quickly applied and shipped (thanks!), which makes this code easy to use. So, the iron is hot and I want to strike it. I’ll probably put this in place to replace a couple gross bits in Synergy.

But also, I should write some tests first.

But also, and much less likely, it’d be great to have some form of Markdown Esperanto, where I could write Markdown (or the like) in my code, and then have it formatted into the right output based on the output channel. Given a Markdown DOM, it would be fairly simple to spit out BlockKit rich text. I think. That would be cool, but I’m pretty sure I won’t ever do it. We’ll see, though.

(dii) 7 great CPAN modules released last week

Niceperl

Published by Unknown on Sunday 30 June 2024 09:00

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::perlimports - Make implicit imports explicit
    • Version: 0.000054 on 2024-06-29, with 18 votes
    • Previous CPAN version: 0.000053 was 5 months, 16 days before
    • Author: OALDERS
  2. CPAN::Audit - Audit CPAN distributions for known vulnerabilities
    • Version: 20240626.001 on 2024-06-26, with 14 votes
    • Previous CPAN version: 20240615.002 was 11 days before
    • Author: BDFOY
  3. GD - Perl interface to the libgd graphics library
    • Version: 2.83 on 2024-06-23, with 28 votes
    • Previous CPAN version: 2.82 was 27 days before
    • Author: RURBAN
  4. Graph - graph data structures and algorithms
    • Version: 0.9729 on 2024-06-28, with 27 votes
    • Previous CPAN version: 0.9727 was 1 year, 3 days before
    • Author: ETJ
  5. Kelp - A web framework light, yet rich in nutrients.
    • Version: 2.12 on 2024-06-26, with 44 votes
    • Previous CPAN version: 2.00 was 16 days before
    • Author: BRTASTIC
  6. Net::AMQP::RabbitMQ - interact with RabbitMQ over AMQP using librabbitmq
    • Version: 2.40011 on 2024-06-23, with 15 votes
    • Previous CPAN version: 2.40010 was 2 years, 12 days before
    • Author: MSTEMLE
  7. PPR - Pattern-based Perl Recognizer
    • Version: 0.001009 on 2024-06-26, with 22 votes
    • Previous CPAN version: 0.001008 was 1 year, 2 months, 15 days before
    • Author: DCONWAY

What's New in Perl v5.40?

perl.com

Published on Friday 28 June 2024 09:00

This article was originally published at The Weekly Challenge.


Perl, the most versatile and powerful programming language, continues to evolve. With the addition of Corinna to core Perl, I look forward to every release for new features. On 9th June 2024, we had the latest public release of Perl v5.40. There have been significant enhancements in this release. You can check out the main attraction yourself.

In this post, I would like to share my personal favourites.

1. The new __CLASS__ keyword
2. The :reader attribute for field variables
3. A space is permitted in the -M command-line option
4. The new ^^ logical xor operator
5. The try/catch feature is no longer experimental
6. for iterating over multiple values at a time is no longer experimental

1. The new __CLASS__ keyword


Do you remember our good old friend, __PACKAGE__? Well, it is a special token that returns the name of the package in which it occurs. Most commonly, you will find this __PACKAGE__->meta->make_immutable in a Moose class.

Similar to __PACKAGE__, we now have a special token __CLASS__ for the new core OO. In most cases, it would behave same as __PACKAGE__. Having said that, it shines when you are dealing with subclass.


use v5.40;
use experimental 'class';

class Example1 {
    field $x = __CLASS__->default_x;
    field $y = __CLASS__->default_y;

    sub default_x { 10 }
    sub default_y { 20 }
    method sum { return $x + $y }
}

class Example2 :isa(Example1) {

    sub default_x { 1 }
    sub default_y { 2 }
}

say Example1->new->sum;  # 30
say Example2->new->sum;  # 3

2. The :reader attribute for field variables


With the introduction of new OO in Perl v5.38, this is how one can create a class.


use v5.38;
use experimental 'class';

class Employee {
    field $name :param;
    field $age  :param;

    method name    { return $name }
    method get_age { return $age  }
}

my $emp = Employee->new(name => "Joe", age => 40);
say $emp->name;      # Joe
say $emp->get_age;   # 40


If you noticed, the method name() and get_age() is just a generic getter method.

Luckily in the latest release, the same can be achieved like below with the use of :reader without having to explicitly define the getter methods.

I must admit, it looks a lot cleaner definition of class comparatively.


use v5.40;
use experimental 'class';

class Employee {
    field $name :param :reader;
    field $age  :param :reader(get_age);
}

my $emp = Employee->new(name => "Joe", age => 40);
say $emp->name;      # Joe
say $emp->get_age;   # 40


There are two variants, one that would give you regular getter and the second where you can provide your own method name.

You may be wondering, how about setter?

Well I am hoping in the next release we might get that too.


3. A space is permitted in the -M command-line option


Prior to Perl v5.40, this is how you would use -M switch.


$ p538 -MList::Util=sum -E 'say sum(1, 2, 3, 4)'
10


However if you forced a space in an earlier Perl, you would get error Missing argument to -M like below:


$ p538 -M List::Util=sum -E 'say sum(1, 2, 3, 4)'
Missing argument to -M


With the release of Perl v5.40, you no longer get error.


$ p540 -M List::Util=sum -E 'say sum(1, 2, 3, 4)'
10

4. The new ^^ logical xor operator


Prior to Perl v5.40, we had 3 low-precedence logical operators and, or and xor. Also we had 2 medium-precedence logical operators && and ||.

In the earlier release of Perl, this is how one would use low-precedence xor operator.


use v5.38;

my $x = 1;
my $y = 0;

($x xor $y) and say 'Either $x or $y is true but not both.';


With the addition of the new medium-precedence xor operator ^^, the same can be achieved like below:


use v5.40;

my $x = 1;
my $y = 0;

$x ^^ $y and say 'Either $x or $y is true but not both.';

5. The try/catch feature is no longer experimental


We all know try/catch was added to the core Perl v5.34 as experimental.


use v5.34;
use experimental 'try';

try {
    1/0;
} catch ($e) {
    say "try/catch exception: $e";
}


It stayed experimental even in Perl v5.36.


use v5.36;
use experimental 'try';

try {
    1/0;
} catch ($e) {
    say "try/catch exception: $e";
}


However it is no longer experimental in Perl v5.40. Hurrah!!!


use v5.40;

try {
    1/0;
} catch ($e) {
    say "try/catch exception: $e";
}

6. for iterating over multiple values at a time is no longer experimental


Do you remember iterating over multiple values at a time was an experimental feature added to the core Perl v5.36?


use v5.36;
use experimental 'for_list';

for my ($p, $q) (1,2,3,4) {
    say $p, $q;
}


It is no longer experimental in Perl v5.40.


use v5.40;

for my ($p, $q) (1,2,3,4) {
    say $p, $q;
}

Just to show realtime result, please see below:


$ p540 -E 'for my ($p, $q) (@ARGV) { say $p, $q; }' 1 2 3 4
12
34

$ p540 -E 'for my ($p, $q) (@ARGV) { say $p, $q; }' 1 2 3 4 5
12
34
5

$ p540 -E 'for my ($p, $q) (@ARGV) { say $p, $q; }' 1 2 3 4 5 6
12
34
56

I have only scratched the surface so far. Maybe in the next post I will try to explore further enhancements.

TPRC 2024 Feedback Form

Perl Foundation News

Published by Amber Krawczyk on Thursday 27 June 2024 17:46

Please help us by filling out our brief TPRC feedback form at https://forms.gle/DcUDX6JzWT72yXTY7 Couldn't make it this year? We still want your feedback!

What's new on CPAN - May 2024

perl.com

Published on Thursday 27 June 2024 08:00

Welcome to “What’s new on CPAN”, a curated look at last month’s new CPAN uploads for your reading and programming pleasure. Enjoy!

APIs & Apps

Config & Devops

Data

Development & Version Control

Language & International

Science & Mathematics

Web

Other

Outreachy 2024 - Success working on the Open Food Facts project

Perl Foundation News

Published by Stéphane Gigandet on Tuesday 25 June 2024 11:00

The Perl Foundation is taking part again this year in the Outreachy program which encourages the participation of underrepresented groups in open source. As Makoto Nozaki described in the previous post, we had many applicants this year, most of whom were new to Perl but very interested in learning the language. Out of many very motivated and enthusiastic candidates, we selected Success Ologunsua who will be working on the Open Food Facts project.

Success’s introduction in her own words:

> "Hello everyone, my name is Success Ologunsua. I'm a microbiologist turned software engineer based in Lagos, Nigeria. I mostly write server-side code because I enjoy being involved in how things run behind the scenes. > I am passionate about contributing to open-source projects and I'm currently contributing to a project in the OpenFoodFacts community. I joined this project because it addresses important social and health issues, such as weight management and diet monitoring, which resonate deeply with me. Also, I was drawn to the inclusivity of all languages in the project and the challenge of learning Perl, a language I find intriguing. > My tech stack includes Node.js, Nest.js, JavaScript, TypeScript, MongoDB, PostgreSQL, HTML, CSS, and most recently, Perl 😍. > Besides solving problems with various tools and technologies, I enjoy writing articles that explain technical topics. You can find some of my work at: https://medium.com/@TheSussex > In my free time, I enjoy watching crime thriller series, swimming, and people-watching."*

This is the fifth year that The Perl Foundation is supporting the Open Food Facts project through the Outreachy program. Open Food Facts is a wikipedia for food products. Volunteers from all around the world gather data about food products (ingredients, allergens, nutrition facts, labels, packaging etc.) in a free, open and collaborative database that now contains more than 3 million products!

This year, Success will focus on the producers platform of Open Food Facts, continuing on the work of previous Outreachy interns Yukti Sharma and Monalika Patnaik. The platform enables big and small food manufacturers to share data and photos for their products on Open Food Facts, and to get free advice to improve the quality of their products (by comparing their products to similar products on the market, and by finding opportunities to get better nutritional scores by reducing sugars, saturated fats and salt).

Success’s mentors will be Alex Garel and Stéphane Gigandet.

Please join us in welcoming Monalika to the Perl’s community, and if you want to say “Hi!” to Monalika, you can join one of the weekly development calls for the Perl backend of Open Food Facts! (every Monday at 4pm CEST) or send a message at any time in the #productopener channel of the Open Food Facts Slack!

Bowing to the inevitable

Perl Hacks

Published by Dave Cross on Sunday 23 June 2024 11:37

Data Munging with Perl was published in February 2001. That was over 23 years ago. It’s even 10 years since Manning took the book out of print and the rights to the content reverted to me. Over that time, I’ve been to a lot of Perl conferences and met a lot of people who have bought and read the book. Many of them have been kind enough to say nice things about how useful they have found it. And many of those readers have followed up by asking if there would ever be a second edition.

My answer has always been the same. It’s a lot of effort to publish a book. The Perl book market (over the last ten years, at least) is pretty much dead. So I really didn’t think the amount of time I would need to invest in updating the book would be worth it for the number of sales I would get.

But times change.

You may have heard of Perl School. It’s a small publishing brand that I’ve been using to publish Perl ebooks for a few years. You may have even read the interview that brian d foy did with me for perl.com a few years ago about Perl School and the future of Perl publishing. In it, I talk a lot about how much easier (and, therefore, cheaper) it is to publish books when you’re just publishing ebook versions. I end the interview by inviting anyone to come to me with proposals for Perl School books, but brian is one of only two people who have ever taken me up on that invitation.

In fact, I haven’t really written enough Perl School books myself. There are only two – Perl Taster and The Best of Perl Hacks.

A month or so ago, brian was passing through London and we caught up over dinner. Of course, Perl books was one of the things we discussed and brian asked if I was ever going to write a second edition of Data Munging with Perl. I was about to launch into my standard denial when he reminded me that I had already extracted the text from the book into a series of Markdown files which would be an excellent place to start from. He also pointed out that most of the text was still relevant – it was just the Perl that would need to be updated.

I thought about that conversation over the next week or so and I’ve come to the conclusion that he was right. It’s actually not going to be that difficult to get a new edition out.

I think he was a little wrong though. I think there are a few more areas that need some work to bring the book up to date.

  • Perl itself has changed a lot since 2001. Version 5.6.0 was released while I was using the book – so I was mostly targeting 5.005 (that was the point at which the Perl version scheme was changed). I was using “-w” and bareword filehandles. It would be great to have a version that contains “use warnings” and uses lexical filehandles. There are dozens of other new Perl features that have been introduced in the last twenty years.
  • There are many new and better CPAN modules. I feel slightly embarrassed that the current edition contains examples that use Date::Manip and Date::Calc. I’d love to replace those with DateTime and Time::Piece. Similarly, I’d like to expand the section on DBI, so it also covers DBIx::Class. There’s a lot of room for improvement in this area.
  • And then there’s the way that the world of computing has changed. The current edition talks about HTTP “becoming ubiquitous” – which was an accurate prediction, but rather dates the book. There are discussions on things like FTP and NFS – stuff I haven’t used for years. And there are new things that the book doesn’t cover at all – file formats like YAML and JSON, for example.

The more I thought about it, the more I realised that I’d really like to see this book. I think the current version is still useful and contains good advice. But I don’t want to share it with many people because I worry that they would pick up an out-of-date idea of what constitutes best practices in Perl programming.

So that has now become my plan. Over the next couple of months, I’ll be digging through the existing book and changing it into something that I’m still proud to see people reading. I don’t want to predict when it will be ready, but I’d hope to have it released in the autumn.

I’d be interested to hear what you think about this plan. Have you read the book? Are there parts of it that you would like to see updated? What new syntax should I use? What new CPAN modules are essential?

Let me know what you think.

The post Bowing to the inevitable first appeared on Perl Hacks.

belated review of stuff I bought during lockdown

rjbs forgot what he was saying

Published by Ricardo Signes on Saturday 22 June 2024 12:00

A couple weeks ago, I had to test a printer, and the first text file I found to test-print was this, quazza-purchases.txt:

Mar 27    $ 90      Philips Hue lights
Mar 30    $200      dock (Fastmail paid)

Apr  2    $232      Dual monitor arm

May  7    $ 64      ottoman
May  8    $ 48      bookends
May 11    $ 13      banjo hanger
May 27    $ 16      headphone hanger
May 29    $225      Wall art

Jun  8    $335      Whiteboard
Jun 15    $ 17      magnet-making stuff!
Jun 19    $ 12      Whiteboard erasing cloths

Jul  4    $500      side table
Jul 12    $ 12      furniture feet

Sep  8    $ 36      Label maker

It’s a list of things I bought to improve my work-from-home experience. I don’t know why I kept it, but now that I have it, I can provide a few years of perspective on how those went. Nobody is asking for this, but I’m providing it anyway. If you want more photos than those found in this post, you’re in luck. It turns out that I posted a little Flickr album of some of this decorating. It is just as boring an album as you might expect!

Our last day of work in the office was March 13th, so March 27th was just two weeks into lockdown. That means the Hue lights were pretty early. I didn’t just get these for fun (although I did have fun with them). I got them because I already spent a lot of time on Zoom talking to Australia, and now I was going to spend even more talking to my American coworkers. You can see what a difference it made to my Zoom face in another post about these.

I think these were a decent buy. I was happier with my Zoom calls, and it gave me some code to write for fun, and now I have a few other Hue lights in my house. I put weird colors up at the holidays, or set lights to dim sometimes. Most of the value, though, is in Zoom calls.

Hue lights: ★★★★☆

Around the same time, I ordered that new dock and the monitor arm. These were … fine. The dock is an okay dock, but it was meant to let me have two displays while in clamshell mode on my laptop, and that didn’t work very well. Sometimes it worked. Sometimes it didn’t. Sometimes it worked but all my USB v2 peripherals stopped working. It stank, so I hooked it up to a Raspberry Pi which I never used. Now it’s just an expensive one-display dock.

That means the extra monitor arm also didn’t deliver the value I expected. Eventually, I decided to connect an Apple TV to it, which is sometimes useful. I can put a second desktop on it, or I can just put a movie on it while doing weekend fun work. The down side is that for some reason I’ve never gotten the display’s built-in audio-out to work properly, so I have to use a Bluetooth speaker. That means that weirdly, once in a while, some neighbor is able to pair to it and play noise into my office. Awful.

Dock and monitor arm: ★★★☆☆

May was a month of organizing and making my space nice to sit in day after day. Some of this was decluttering: I got a bunch of books better organized, I got my headphones slung under my desk, and I got my banjo off the floor and onto the wall. I guess this was okay. The bookends let me put all my books in the correct orientation, instead of sideways books holding up vertical books. The banjo hanger made all the people on my Zoom calls think I played banjo. (Usually for only one or two calls, after which they’d say, “Hey, do you play the banjo?” and then I’d say, “No.”) The headphone hanger still gets use, but I don’t love it. The cables dangle in my trash can. I don’t know what I’d like better, but something.

Bookends, hangers: ★★★☆☆

I also bought an ottoman. Just about as soon as I received it, I thought it was going to be the best thing I bought during lockdown. A couple years later, I still think so, at least relative to its price. I started using it for reading. I’d turn my chair away from my desk, put up my feet so I couldn’t turn back to my computer, and just enjoy sitting. I am still doing that, even though I have some other chairs. I keep my cheap but comfy IKEA blanket in it, too. I’ve been thinking about getting an ottoman for work. And maybe one for my balcony. They’re just a good idea.

Ottoman

Ottoman: ★★★★★

And then there’s the art. At the time, my home office was basically a walk-in closet. It wasn’t connected to a bedroom, but it was small and bland, with off-white walls and a window that looked out onto an ugly stucco wall. It felt like putting a little something attractive up on the walls would be a good idea. I went to Society6 and got two canvas prints by local Philly artist Andrew Chalfen. If you look at that page, you can find the Tiled City pieces. One of mine looks like those. The other is much less busy, mostly made up of hexagons. Years later, I still like them and I’m not tired of looking at them.

Hanging art: ★★★★☆

In June came the whiteboard. I really like whiteboarding. I don’t do it every day, but when I realize that I need to use a whiteboard for a problem, it’s a good sign that I’ll save a huge amount of effort by just doing so. At the Fastmail office in Philadelphia, we have really nice whiteboards, and I didn’t want to get a lousy melamine one for home. I splurged and contacted our office furniture vendor. In the end, the $350 was worth it. I’m still using it years later, and it’s still saving me time. Also, sometimes the kid comes in and draws something on it.

When they came to deliver it, they came in a full semi trailer down my one-lane street in Philly. Then the driver needed my help to unload. It was bizarre, but I ended up with a nice whiteboard. It’s “ceramic steel”, whatever that means. It’s magnetic and erases really nicely. The erasing cloths were maybe not a great idea. Paper towels work better, I think.

Steelcase truck

(Note that the truck has a rainbow Steelcase logo. It was delivered in June.)

I also bought “magnet-making stuff”. This was actually some small neodymium magnets and some two-part epoxy. I made some whiteboard magnets by sticking the magnets to some polyhedral dice with epoxy. This was fun, I’d do it again. (It smelled very bad, and I was told that if I ever do it again, I have to do it outside. Okay!)

dice magnets

Whiteboard: ★★★★☆

That whiteboard’s effectiveness was probably hampered by another purchase, which was otherwise pretty good: my sideboard. It’s a nice wood and metal console — Article’s Taiga oak console. It holds a bunch of my cables (in boxes), stationery, some electronics I want to keep easy to find, and sometimes the books I’m reading. It matches my aesthetic and it’s quite convenient. The problem is that both then and now, I have it right under my whiteboard. It’s about a foot deep, so it means I have to stand just a little bit away from the whiteboard, so it’s just a little bit less ergonomic.

In some future dwelling, it may all come together better, but here it’s been slightly imperfect.

Wooden console: ★★★☆☆

Also on the list: feet to go under furniture so it wouldn’t slip. Fine. Beneath discussion, I think. And the label maker… I mean, everybody loves a label maker, right? But what is there to say? I labeled a lot of things, then I put it away, and now I use it a couple times a year. I should’ve bought it earlier in life, but even then, there isn’t so much to say.

But… one more thing!

Earlier, I mentioned that my office had a window onto an ugly wall. Well, I have a photo:

my "view"

Awful. Just awful. Eventually that wall was resurfaced, so it went from dingy, disgusting stucco to merely ugly, typical stucco. It too me far, far too long to do something about this view. I hung some heavy yellow drapes. I’d always had blinds, so their effect on the view was marginal. On the other hand, they gave the bland room a big pop of color that was definitely worth the fifty bucks I spent on the drapes and rod combined.

The whole endeavor did have one lasting bit of value: it made it clear to me that I should spend a little time and money making my home more comfortable even when there is not a global pandemic throwing my day to day life into unheaval. Just this month, I bought a new table and chair for my balcony. Lesson learned.