Home > front end >  Do all my perl module .pm files need a `$VERSION` definition?
Do all my perl module .pm files need a `$VERSION` definition?

Time:11-01

I just added a new file to the PDL::IO::Touchstone distribution noticed CPAN's indexer says version is undef since $VERSION is missing:

     module : PDL::IO::MDIF
     version: undef
     in file: PDL-IO-Touchstone-1.009/lib/PDL/IO/MDIF.pm
     status : indexed

So ::MDIF does not have $VERSION but really it is the same as the distribution version as noted in Makefile.PL:

my %WriteMakefileArgs = (
   VERSION_FROM     => 'lib/PDL/IO/Touchstone.pm',
   ...
);

Questions:

  • So does this module within the distribution need a version?
  • If so, should the new module's $VERSION be maintained separately from $VERSION provided by VERSION_FROM in Makefile.PL?
    • I could do $VERSION = $PDL::IO::Touchstone::VERSION but not sure if CPAN will figure that out. Will it?

I looked around and found lots of discussion of versioning practices, but nothing about versions of modules within the same Perl distribution package. Please share what the best practice here should be, I'm new to Perl modules and this is the first 2-file distribution that I've pushed out.

I'm sure I'll update the primary file when releasing a new dist, but not sure if I'll remember to bump the version of other modules in the dist when they change. It would be nice if there is a low-maintenance option here.

CodePudding user response:

I like to give all of my modules versions. It's not a requirement, but consider the user experience while trying to upgrade when they don't know anything, or very little, about how CPAN works. ikegami already gave the tl;dr for this.

When you want to update a module from CPAN, the tool looks at that module's $VERSION (well VERSION sub). If that module doesn't have a version, that's undef. When CPAN.pm (or other tools maybe) looks to see if there is a more recent version, it does not find one it thinks is more recent because the latest version is also undef.

A concrete example is Mojo::UserAgent. Mojolicious only versions the main module. The other modules do not have versions. I typically do a lot of web client stuff, so my work product doesn't care about the web server side of Mojo. People using some of my stuff might not even know there is a different part of Mojo aside from the client stuff (they might even know Perl).

If I run cpan Mojo::UserAgent, it compares my currently installed version (undef) to the latest on CPAN (undef). This means that CPAN.pm guesses that I do not have something earlier than the latest available.

$ cpan -D Mojo::UserAgent
Mojo::UserAgent
-------------------------------------------------------------------------
    (no description)
    S/SR/SRI/Mojolicious-9.28.tar.gz
    /usr/local/perls/perl-5.36.0/lib/site_perl/5.36.0/Mojo/UserAgent.pm
    Installed: undef
    CPAN:      undef  up to date
    Sebastian Riedel (SRI)
    [email protected]

Now, I have this special knowledge that this distro does this. But someone merely using something I wrote with Mojo::UserAgent probably doesn't. If they need Mojolicious 8 to get particular CSS selectors then, how do they know that?

Normally, you can specify a minimum version of a module:

use File::Glob 8.0;

I can't require a minimum version of Mojo::UserAgent:

use Mojo::Usergent 8.0;

I get a weird error (there are other import issues and design decisions going along with this):

Can't locate 8.pm in @INC (@INC contains: ...)

This isn't a big deal because Mojolicious is mostly self-contained, so I can specify its minimum version:

use Mojolicious 8.0;

But, I have to know how all of this works, how that distro works, and how Perl works to do that. For the casual user of my stuff who just wants to get work down, including modifying what I've done, they have to discover some lore to know this. They have to know how CPAN.pm or PAUSE decides what the latest version is, and so on.

Furthermore, this is a problem for modules in a distribution that don't change and have no logical reason for a version bump. Well, they do because they have an implicit dependency on the main module that does have a version, but we're not in the habit of declaring that version. Consider, for example, some module that works with an API that has changed, but the meat of the change is in another module it uses. The module you use directly has not changed its literal text, but it can't work as is because the world is different. But, since the literal text in that file hasn't changed so we typically don't bump the version.

Maybe we should declare that main module dependency, but that's a lot of work. It adds some seemingly gratuitous churn to files, which is annoying in repo history. Ah hell, now that I've thought of that, I need to fix this in some distros. Some-not all. I don't know. Something to think about. ikegami gave the simple solution to this by just stealing the main module's version (thanks to tobyink for the note that the CPAN indexer extracts a single line and evals it):

package MyModule;
$VERSION = do { use PDL::IO::Touchstone; $PDL::IO::Touchstone::VERSION };

Of course, I can document all of this in the distro, script, or whatever. But we know that I can say it and they can read it and still not appreciate the importance. And, by this time we're a far way away from "just working".

CodePudding user response:

CPAN only requires a version for the distribution, and you have provided that using VERSION_FROM.

There are a variety of practices.

  • Only the "main module" has a version.
  • Each file has its own version.
  • Each file shares the distro's version.

CPAN evals the line that sets $VERSION, so the following should work if it's all on one line:

use PDL::IO::Touchstone; $VERSION = $PDL::IO::Touchstone::VERSION;
  • Related