Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical


by pryrt (Abbot)
on Mar 18, 2016 at 23:38 UTC ( #1158292=user: print w/replies, xml ) Need Help??

Hobbyist Perl s‎crip‎ts since the mid '90's, when I picked it up to start doing some simple cgi and random .sig picker for my college-supplied email and personal homepage.

Since my searches for Perl questions usually had the best answer here, I decided I'd finally make an account, and see if I could occasionally answer something rather than just having all my questions answered. :-)

Took over Games::Literati a few years back, because it'd had a long-time scoring bug, and I wanted to add some features (like Words With Friends). That got me interested in publicly contributing to CPAN: while I don't think anyone but me has ever used one of my modules, they do exist. :-)

Developing Data::IEEE754::Tools because I'm interested in the underlying encoding of floating-point numbers, and because Integers sometimes turn into Reals after substraction started an Earworm, fed by Determining the minimum representable increment/decrement possible?, that then wouldn't go away.

Developing Math::PRBS because sometimes, a PRBS is useful to have, and I was surprised to find that I couldn't see it in Math::NumSeq (under any name that I could think of); even if it does include it, one of its prerequisite libraries doesn't compile on Win32 systems. So, I made one (that didn't rely on the prerequisite libraries, so not part of the Math::NumSeq family).

I listed some of my programming history (and potential future) in response to the January 2019 Poll. People reading this far through my bio might be interested to see that history, too.

Since Re^2: Canonization Without Representation showed I was interested: #709 in 556d (1y + 6mo + 7d). The next day, I learned that the SIOB list reorders as XP changes. Now I'm curious whether there's a public interface that will allow showing how someone moves through the SIOB list over time (as the more-active monks start overtaking others). :-)

cavac created a monster; I just tabled my rune:

Posts by pryrt
RFC: A guide to installing modules for Win32 (2022 Edition) in Meditations
9 direct replies — Read more / Contribute
by pryrt
on Jul 25, 2022 at 16:05

    Pursuant to Re^3: Can't locate Convert/ , here is a suggested version for "A guide to installing modules for Win32 (2022 Edition)"

    After any suggested updates (I don't pretend to be an expert, so feel free to correct and nitpick), would this go better as a reply to holli's original A guide to installing modules for Win32, or as a new top-level post in the Tutorials section?

    I included the case-sensitivity section because that was an issue in the recent thread Can't locate Convert/, even though I'm not sure how general-use that note really is, or whether it really belongs in this tutorial.

    Updates: Here is a history of the edits made as a result of suggestions.

    1. Fix cpan arguments (per brian_d_foy's reply)
    2. Add perl Makefile.PL to the "standard recipe" (per syphilis's reply)
    3. Switch to a table, to avoid & (avoiding single & per many recommendations)
    4. Fix formatting syntax (per Discipulus's reply)
    5. Add a note about alternative build recipes (to cover Build.PL and possibly others)
    6. Add a note about incompatible modules
    7. s/skill/system/ in the last paragraph (per hippo's comment

    A guide to installing modules for Win32 (2022 Edition)

    Nearly two decades later, holli's excellent A guide to installing modules for Win32 could use some updated information.

    ActiveState phased out using PPM in 2021 (), so starting with ActivePerl 5.28, PPM is no longer included.

    And since 2008 (), there's been an alternative distribution, Strawberry Perl, which comes with it's own gcc/g++ compiler and build environment. Modern Strawberry Perl versions not require using PPM for installation either (though it still ships with a PPM client, if you can find PPM repositories to use it with), so the original Win32 Guide's PPM instructions are not as useful as they once were.

    ActiveState's ActivePerl

    The modern method of "installing" modules on ActivePerl, as announced in The ActiveState Platform and Perl 5.32, is to make a binary build with the State Tool, where you tell it all the modules you need, and it will provide a binary build with all of those modules (and their dependencies) already installed.

    Strawberry Perl

    One of the benefits of Strawberry Perl is that they include a working gcc/g++ compiler and build environment, complete with a variant of make (dmake for older versions, gmake for newer versions; see perl -V:make to find out which your copy of Strawberry Perl uses) that means you can easily build and install modules similarly to how it's done on Linux and other OS:

    The default client comes with Strawberry Perl, so installing Some::Module as easy as cpan Some::Module. Strawberry Perl also comes pre-installed with cpanm, an alternative CPAN client that handles dependencies, allowing installation with cpanm Some::Module. You can install cpanplus or other of the advanced CPAN clients on Strawberry Perl as well.

    Finally, if you are a traditionalist and want to manually build using the traditional recipe, you can look at the output of perl -V:make and then pick the appropriate variant of the recipe:

    perl Makefile.PL make make test make install
    perl Makefile.PL dmake dmake test dmake install
    perl Makefile.PL gmake gmake test gmake install

    Some modules may specify their own recipe for building and installing. If so, then try following their directions; the Strawberry build environment is pretty good. But if they specify a different recipe, it doesn't work, and the CPAN-client options don't work, you should file a bug report with the author, because any distributed module should be installable using cpan, cpanm, cpanplus and the like.

    For any of these installation techniques: If you have an installed copy of Strawberry Perl, your path should point to the Perl and C binaries already; if you have a portable copy of Strawberry Perl, you may need to run portableshell.bat to get the environment set up correctly.

    Other Alternatives

    If you have built your own Perl, or for Windows Subsystem for Linux, or cygwin, or other Windows tools that provide bash or bash-like environments, you should still be able to follow the instructions in the original A Guide to Installing Modules for installing, or use cpanm or cpanplus or other clients not mentioned in the original guide.

    Win32 Caveat: Module Case Sensitivity

    File names on Windows are not case-sensitive, so some Windows users are used to typing PATHS IN ALL CAPS. Do not type module names in all caps, even when using a CPAN client from the Windows command line (cmd.exe or powershell), as Perl and the CPAN tools will not treat SOME::MODULE and Some::Module the same, even if they resolve to the same ...\Some\ file.

    Windows Incompatibility

    Please note that some modules have been created in such a way that they are incompatible with the Windows operating system. This guide cannot help you install and use a module that is not compatible with your OS. (You can check the CPAN Testers reports linked from the page for each module: if it doesn't show any passing results on the mswin32 platform, you may have difficulty installing the module.)

Making a reloadable module, allowing "live" edits in Cool Uses for Perl
3 direct replies — Read more / Contribute
by pryrt
on Apr 09, 2022 at 18:44
    I was recently watching this youtube video on a simple PID controller implemented in Python (it was in a watchlist of math-related videos, though his PID was more math-adjacent than math-focused). But instead of focusing on the controller algorithm, I was intrigued by his demo environment, where he was able to update his python code live, and have the demo program automatically incorporate the changes immediately, without reloading the demo program.

    I followed his link to the repo for his demo, where he explains his module and how that portion works.

    "That should be doable in Perl," said I. "And I might even be able to do it." And indeed, after some effort, I could.

    He basically used a class variable to store the state of the module-under-development ("mod"), then used a loop in his demo program that every loop would check the timestamp on the mod's file, and if it was newer, he would store the state, then reload the mod and return a new instance of the mod object initialized to the stored state.

    In my example, which I will replicate in the spoiler, I did something similar, but I just stored the state in the instance of my reloadable object, and had the loop read the state from there and pass it as an option when creating the instance from the reloaded package. (My implementation isn't clean enough for CPAN or anything like that, but as toy, I thought it was a pretty cool usage of Perl, and is good enough for a proof-of-concept.)

    The funny thing is, a few days after I implemented it, as I was finishing up debug of something or other, where I was reloading my program quite frequently, I realized just as I was finishing up, "that would have been a perfect time to use Reloadoadable. DOH!".

    If this has piqued your interest, I would love to see, and learn from, how some of the other monks would implement this. You don't have to use the sine calculator as your example; I just thought it was a simple enough example for the proof of concept. If you wanted to do all the graphics to replicate his PID ship controller instead, by all means... ;-)

Announcing WWW::KeePassHttp in Cool Uses for Perl
No replies — Read more | Post response
by pryrt
on Nov 17, 2021 at 09:53

    Some years ago, I saw and bookmarked the discussion at Best way to store passwords, for making use of KeePass for accessing passwords in a perl script. I recently had a script where I was hardcoding a password to access one machine at $work which wouldn't allow me to set up ssh-key-based login, and decided to try to make it work with WWW::KeePassRest. I had it mostly working when I happened to glance again at the plugin page and noticed its license required a SmartFTP Ultimate or Enterprise license, which I didn't have. Since $work would frown on using unlicensed software, and I'm not making $work pay for a license just to access my free password manager's passwords for my own convenience, I deleted that KeePassRest plugin. Looking through the KeePass plugins list, I found a few that looked promising for me having the skills to communicate with, and I got my script at $work correctly interfacing with KeePassHttp.

    I then took the same concepts, and re-wrote it at home with all the trappings of a public module and unit testing, and as of last night, released it to CPAN as WWW::KeePassHttp v0.01


    WWW::KeePassHttp - Interface with KeePass PasswordSafe through the KeePassHttp plugin


    use WWW::KeePassHttp; my $kph = WWW::KeePassHttp->new(Key => $key); $kph->associate() unless $kph->test_associate(); my $entries = $kph->get_logins($search_string); print "$_ => $entries->[0]{$_}\n" for qw/Name Login Password/;


    Interface with KeePass PasswordSafe through the KeePassHttp plugin. Allows reading entries based on URL or TITLE. Allows creating a new entry as well.


    You need to have KeePass (or compatible) on your system, with the KeePassHttp plugin installed.

    Yes, I know that the returned entries should be objects rather than plain-old-hashes. That was the first issue I created as I was getting ready to release last night. I needed a sense of accomplishment, so decided to do a v0.01 release. Right now, the entry-object is my primary task before considering this module good enough for a "v1.0" release. But if anyone else has suggestions, let me know. Also, I don't have any of the linux ports for KeePass, so I don't know if the KeePassHttp plugin works on the linux port... but if it does, and if any of you could test with a live linux+KeePass+KeePassHttp system, that would be great.

    I also had the fun when developing my test coverage of this being my first foray into mocking another module during testing: KeePassHttp uses HTTP requests for communicating with the plugin, but I didn't want to require that CI and smoketesting machines have KeePass+KeePassHttp installed and working before I could get test coverage. I really like Test::MockObject's ability to queue up a list of return values, so that I can easily define my list of HTTP::Tiny->get() replies without having to have an HTTP server available to give me the answers that I want to test.

XML round-trip with comments and prolog in Seekers of Perl Wisdom
3 direct replies — Read more / Contribute
by pryrt
on Jul 28, 2021 at 11:40

    I want to automate changing some settings in an app which uses XML config files, but I am not an XML expert and don't have real experience with any of the XML modules (other than knowing from reading here that I need to avoid XML::Simple). I like starting from "known good" code as examples, and playing around until I understand it better. I found some of haukex's examples with XML::Rules, especially Re^6: XML compare with a key and Re: How do I get a list in a perl hash generated from an XML?, which got me to the point that I could get the XML parsed into an initial data structure which seems reasonable to me.

    But my next goal was to round-trip the config file: to see if I could get an output file that's compatible with the input, so it's still usable as a config file for the app. So far, I've got a short example of:

    #!perl use 5.012; # strict, // use warnings; use Data::Dump; use XML::Rules; my $xml_doc = <<EOXML; <?xml version="1.0" encoding="UTF-8" ?> <!-- important instructions to manual editors --> <root> <group name="blah"> <!-- important instructions for group "blah" --> <tag/> </group> <group name="second"> <!-- important instructions for group "second" --> <differentTag/> </group> </root> EOXML my $parser = XML::Rules->new( stripspaces => 3|4, rules => [ _default => 'raw', ], ); #dd my $data = $parser->parse($xml_doc); print my $out = $parser->ToXML($data, 0, " ", "") . "\n"; __DATA__ <root> <group name="blah"> <tag/> </group> <group name="second"> <differentTag/> </group> </root>

    ... But there are two things I haven't figured out how to do, as evidenced by the differences between the input text and the output text.

    • How do I keep the <?xml ...?> prolog? That is, if the original XML tells me it's encoding="UTF-8" or encoding="Windows-1252", I want to be able to preserve that in my XML output. I searched XML::Rules for <?xml or prolog and couldn't find anything. So is it possible to have XML::Rules include that during its parsing?
    • Is it possible to maintain comments, and their relationship to the existing tags? I searched for comment or <!--, but again couldn't find anything. This is important, because as the dummy data shows, the comments are important instructions to the user who is manually editing the config file, and I don't want to lose that information as I round-trip through my perl-based config-file editor.

    So, is XML::Rules the right choice for this? (And if so, how do I accomplish it?) If not, which module is better equipped for my goals? (And could you provide a similar example, showing how to round-trip through the data structure and still have prolog and comments?)

    Thank you.

    edit: fixed missing sentence separator and missing paragraph indicators; fix title

Anonymous Edit in Perl Monks Discussion
1 direct reply — Read more / Contribute
by pryrt
on Feb 23, 2021 at 14:49
    Re: Challenge: Ricochet Robots was an anonymous post that was recently edited (emptied) with no janitation history. But Anonymous Monk cannot edit his own posts. After some back and forth in the CB, the best guess is that the post ran afoul of anti-spam AM-posts-with-links auto-cleaning. Which is fine... but it would be nice to be sure.

    More importantly than this specific instance: should there be some sort of indication on such posts, whether in the janitation history or in the body of the emptied post, to indicate that it was auto-cleaned for potential spam? This would give people a chance to weigh in with a consideration-to-edit/restore: "no, I saw the content and followed the link before it was purged: it was a link to a A* algorithm implementation of this problem in another language, which doesn't seem like spam given the conversation". (It's obviously been fixed in this case, but I'm using my reaction to this case to explain the general idea)

Anonymous Identifier in Perl Monks Discussion
6 direct replies — Read more / Contribute
by pryrt
on Feb 23, 2021 at 14:32
    Recently, the anonymous account is mostly one infamous user, one detractor who seems to think that every anonymous post (other than his) are by that infamous, and an increasingly-rare useful post.

    I understand the desire for an anonymous account -- it lowers the barrier of entry for one-off questions, and it probably helps with GPDR.

    But often, especially in the last year or so, it seems to me to be more trouble than it is worth. It allows infamous monks to hide behind a cloak that sometimes (but not always) masks who they are and how dangerous their "advice" is. But it also allows angry monks to carry out vendettas against the infamous monks any time there's a non-zero probability that an anonymous post might be from that infamous monk. And, on those rare occasions when the AM isn't one of those two, it makes it hard to follow questions, "no, I'm not that AM, I am a different one, the one from id://...."

    Most forums I've visited don't allow any anonymous posts. Do the negatives here outweigh the positives? And if TPTB don't want to disable AM, could we at least add a non-identifying identifier to AM posts?

    Something I've thought of before, I finally suggested in CB after today's anonymous-edit, and am now reiterating here: I would suggest a one-way hash on the IP address -- so it wouldn't tell us who or where the person is, but it would say "this is likely the same AM as from that other post". For the useful AM conversation, it would help other readers follow which AM said what; and for the infamous and his detractor(s), it would make it easier to confirm or deny whether it is likely the same monk or not. Both seem like "wins" to me. I understand that IP addresses can change or be behind big corporate blocks, so it's not a foolproof identifier in either direction (same IP might feasibly be used by good AM and bad AM, or a single AM's IP might change between posts) ... but it might help some. As long as the particular hash is not also applied to logged-in posts, I wouldn't think it would run afoul of GPDR (but, IANAL, so take it for what it's not worth).

    Anyway, just an idea I've had, and since there was some support in CB, I finally decided to suggest it officially.

Announcing Perl-based automation of Notepad++ in Cool Uses for Perl
2 direct replies — Read more / Contribute
by pryrt
on Feb 22, 2020 at 14:35

    Here is my Perl module for automating Notepad++ (the Windows-based text editor). edit: as new versions are released, I will update the VERSION HISTORY, and post a reply so something ends up in Newest Nodes / Recently Active Threads


    Win32::Mechanize::NotepadPlusPlus - Automate the Windows application Notepad++


    use Win32::Mechanize::NotepadPlusPlus ':main'; my $npp = notepad(); # main application


    Automate the Windows application Notepad++. This is inspired by the Notepad++ plugin PythonScript, but I decided to automate the application from the outside, rather than from inside a Notepad++ plugin. But this module uses similar naming conventions and interface to the PythonScript plugin.


    This is the first public release of the module. In general, it works. As with all first releases, there is room for improvement; I welcome feedback.

    The first known limitation is that none of the hooks for Scintilla or Notepad++ callbacks have been enabled. That may come sometime in the future.

    All the testing and development was done with a US-English installation of Notepad++, and all the file encodings have been ANSI or UTF-8. I know that I need to include better tests for encoding, and any help you can provide with that is appreciated.

    Notepad++ is a Windows application, so that's the intended platform for this module. However, I know Notepad++ can be made to run in Wine and similar environments in Linux, so it may be possible to make this module drive Notepad++ in such an environment. Feedback on this process is welcome.


    To install this module, use your favorite CPAN client.

    For a manual install, type the following:

    perl Makefile.PL make make test make install

    (You may need to use "dmake" or "gmake" instead of "make", depending on your setup.)


    Peter C. Jones

    Please report any bugs or feature requests thru the repository's interface at, or by emailing <bug-Win32-Mechanize-NotepadPlusPlus AT> or thru the web interface at


    Copyright (C) 2019,2020 Peter C. Jones


    This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License. See for more information.


    2020 Mar 21: v0.002 released to CPAN

    • Reorganize the hash variables for easier and clearer use going forward (#13)
    • editor->getLine() on an empty line will now correctly return an empty string, not "\0" (fixed #14)
    • update API for getNumberOpenFiles to correctly use the constants (#17)
    • add notepad->getNppVar() for accessing the "user variables", like FULL_CURRENT_PATH and CURRENT_WORD (#19)
    • improve documentation internal links (#20)
    • make the editor->hwnd() a public method (instead of using editor()->{_hwnd})
    • make the notepad->hwnd() a public method (instead of using notepad()->{_hwnd})
    • add helper editor->getEOLString(): convert EOL Mode integer to a string
    • editor->getFileEndPosition(): gives the end position of the whole document
    • improve test coverage: add encoding names and getLanguageName coverage to npp-buffer.t
    • examples/ folder: adding more example usages
    • improve Editor documentation on ->findText and some other methods, and clean up set/get pairs, so they share the same information
    • improve Notepad documentation, especially fixing the link for menuCmdID source file

    2020 Apr 6: v0.003 released to CPAN

    The user-centric changes that were made:

    • some of the Scintilla v4.2.0 messages that were implemented in Notepad++ v7.8 were missing, so add them (#29: thanks VinsWorldcom for pointing this out!)
    • runPluginsCommand() = fixed command cache feature and improved test (#30)
    • added version notes, to say which messages and "enums" (hashes/keys) require NPP v7.8 (because these are the Scintilla v4.2.0 updates)
Outputting JSON with sorted names/keys in Seekers of Perl Wisdom
5 direct replies — Read more / Contribute
by pryrt
on Jan 25, 2020 at 19:15

    I'm trying to create a simple JSON file. I wanted to try to get the names/keys output in a specific (non-alphanumeric) order (to make it easier on the human users of the JSON -- I know it's irrelevant to any automated parsers). Using the JSON module, I can get unsorted or alphanumerically sorted. Manually rolling it, I can get in whatever order I specify. Is there an option I'm not seeing in the JSON docs for altering the sort-order? or another module that has user-supplied sort order?

    (It's not overly important; this is mostly as a learning opportunity; my manual_ordered_json could have finished this one-off job for me already, but I was hoping to expand my toolbase knowledge.)


[SOLVED] Win32::GuiTest::SendMessage/AllocateVirtualMemory and TCHAR** in Seekers of Perl Wisdom
1 direct reply — Read more / Contribute
by pryrt
on Sep 23, 2019 at 11:56


    As I started talking about a couple months ago in the Notepad++ Community forum, and mentioned recently in another post there, I'm working on a library that will allow an external perl instance (ie, not via a plugin) to use Win32::GuiTest::SendMessage to control Notepad++.

    For communicating with Notepad++ itself, I've got most message-types (sending messages, getting back return-values and lParam [out] values, including sending or receiving a single string). I believe there's only one more type of wrapper I need: the interface to allow wParam to be a TCHAR** (in or out; since it's a **, if I can get one working, I should be able to get both), which is required for NPPM_GETOPENFILENAMES and related (1), and for NPPM_GETSESSIONFILES and NPPM_SAVESESSIONS (2)

    (1: okay, techincally, I have a workaround for GETOPENFILES: I manually loop through the open buffers, and do single-filename-reads instead.)

    (2: For NPPM_SAVESESSIONS, it actually requires wrapping it in a struct; but I think if I can make the TCHAR** work, then wrapping a struct around that should be doable. At least, once I have the technique, I'll have a technique, and I have this as a guide for how to do a struct.)

    If I were in a plugin directly, and thus had access to the parent process memory space, in a C-like language, I could just define the wParam as a TCHAR**, and it would just work -- there are plenty of instances on github of plugins doing that, and I could have just translated those into the Perl equivalent. Unfortunately, because I'm in an external process, I have to use VirtualAllocEx and friends (as mentioned). As I said above, I was able to figure out enough of VirtualAllocEx (and its the Win32::GuiTest wrapper of AllocateVirtualBuffer) to get it to pass a single TCHAR* string back and forth. But I haven't been able to implement the TCHAR** the way I understand -- all I can read back is a string full of NULL \0 bytes.

    My example code, which shows working Perl for a normal string, and my NULL-only result with TCHAR**:

    Unfortunately, I'm out of ideas, so I'm asking in both the Notepad++ Community and in perlmonks. If there's someone that can show an external C example using VirtualAllocEx or an external Perl script using Win32::GuiTest::AllocateVirtualBuffer, and successfully talk with Notepad++'s NPP_GETOPENFILENAMES message, I'd appreciate it.

    (I know @ekopalypse in the Notepad++ community has shown some facility in hopping back and forth between languages... and vr in perlmonks has the only recent post on perlmonks involving AllocateVirtualBuffer... but I'm definitely not limiting my request for help to just those two.)


    edit: fixed link once I had the post actually made in the Community. Sorry for the two minutes when I didn't have a URL yet. I tried a stealth edit, but you guys started reading too fast. :-)

stat on in-memory filehandle warns inconsistently across perl versions in Seekers of Perl Wisdom
1 direct reply — Read more / Contribute
by pryrt
on Mar 07, 2019 at 11:14

    I was surprised by my test results on Travis-CI, where my module failed on 5.16, 5.18, and 5.20, but not on the versions above or below those.

    Doing some digging, it's because of the way that stat works on an in-memory filehandle: on most versions, it gives a warning in the unopened subcategory of the io warnings category, so I set up my module to trap on that warning, and die with a more meaningful message to the end-user, which should help them avoid the problem. But when it ran on multiple versions on Travis-CI, I found that 5.16-5.20 apparently do not give that (or any) warning, but still result in the empty list for the in-memory filehandle.

    The issue can be simply replicated with the one-liner SSCCE (shown in both windows/berrybrew and linux/perlbrew) in the spoiler below.

    I found a workaround (see second spoiler below), but I was curious, so I skimmed the perldelta for 5.16 and 5.22, but couldn't find a mention of the unopened-filehandle warning changing in either of those versions. So I guess the wisdom I am seeking: does anyone have insight as to why the warning disappeared in 5.16, but came back in 5.22? Was it intentional (and if so, why try removing it, and why re-instate it)? Or was it an accidental bug (if so, why wasn't it mentioned, or did I just not notice)?

    *workaround =

    And thank you: while working on the earlier issues -- figuring out that in-memory filehandle's don't stat right, but give the misleading "unopened filehandle" warning, even though Scalar::Util::openhandle() shows it as open; and trying to get the __WARN__ handler correct -- I thought I was going to need to SoPW, but developing a SSCCE showed me the problem. So thanks for the Rubber duck that you didn't even know you provided, too. :-)

Log In?

What's my password?
Create A New User
Domain Nodelet?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (3)
As of 2022-08-14 22:06 GMT
Find Nodes?
    Voting Booth?

    No recent polls found