4

I'm looking for a way for a module (or script) to be able to load a specific version of a module (mainly looking at in-house modules, if the solution doesn't work with CPAN modules that's ok).

I'd prefer for this to be largely a packaging exercise (like the way npm/nodejs works). My code defines the versions of the module it wants, then when the use happens the correct module version is loaded.

If it can't be done at the packaging level, is there a sane way to handle this in code? I really don't want to litter the module (or the module's USE-er) with

if($api_ver eq '1.1'){    }
elsif($ap_ver eq '2.0') {  }

More generally, I'm trying to come up with a sane way to track versioned APIs at the module level.

I looked at only per this post How can I 'use' specific version of a perl CPAN module? but the unit test report is fairly bad, and the module hasn't been touched in 6 years as far as I can tell (still on my list to play with though)

Edit: Essentially I'm asking if different modules in my application can use different versions of the same module. Something like:

Module A
   load version 1.0.1 of Module Foo

Module B
   load version 2.1.0 of Module Foo

Module A & B are part of a larger piece of software and Module Foo is also locally written (as I said, I'm less concerned about CPAN versions) I'd like to be able to make API breaking changes to Module Foo without having to uplift every module that uses it. Yes, eventually version 1 of module Foo may end up deprecated, and code would have to be uplifted at that time.

Community
  • 1
  • 1
skarface
  • 910
  • 6
  • 19
  • 2
    Take a look at [Module::Load::Conditional](http://search.cpan.org/~bingos/Module-Load-Conditional-0.64/lib/Module/Load/Conditional.pm). – Ron Bergin Jun 03 '15 at 14:19
  • 1
    "I'd prefer for this to be largely a packaging exercise" I'm not quite sure what you mean by this, but ExtUtils::MakeMaker and Module::Build both allow you to specify the minimum required version of dependencies; the check happens at install time. In your code, you can do `use Module VERSION;` to specify the minimum required version of `Module`. – ThisSuitIsBlackNot Jun 03 '15 at 14:31
  • use Module VERSION doesn't allow me to specify a particular version of a library, it just fails to load if a minimum version isn't available. I want to have module A require version 1.2.0 of module B and module C require version 2.1.1 of module B. i.e. different things using different versions of a module (yes the different versions need to be installed and available) – skarface Jun 03 '15 at 14:38
  • 1
    @skarface "I want to have module A require version 1.2.0 of module B and module C require version 2.1.1 of module B" Are you saying you want to use different versions of the same module simultaneously in your application? – ThisSuitIsBlackNot Jun 03 '15 at 14:41
  • @ThisSuitIsBlackNot Yes. If I have module A that's been written against the version 1 API of module B, and the version 1 API is still supported, I'd like to allow module A to continue to use the version 1 API and leave module C free to use version 2 of module B's API. I'm not sure if this is even possible, but I've really liked the way node/npm handles this, and was trying to see if perl could do the same or similar. I'm not looking to install the modules globally, having them be installed in a directory local to the module using the particular version is fine. Carton seems to get close. – skarface Jun 03 '15 at 14:45
  • 1
    @skarface I would [edit] your question to clarify that point. – ThisSuitIsBlackNot Jun 03 '15 at 14:46
  • @ThisSuitIsBlackNot done. Thanks for the recommendation. – skarface Jun 03 '15 at 14:51
  • 1
    I'm not sure it's possible in every case. In Perl, you can't have two versions of the same subroutine in the same namespace, so using the module in a different version would overwrite the subroutines of the same names. – choroba Jun 03 '15 at 14:54

1 Answers1

2

I have solved this in the past by having a copy of the dependency in all versions, with the version in the namespace. That seems like it's code-duplication, but it's really just making sure you provide a stable API without relying on all the loading.

API::Version1::Dependency
API::Version2::Dependency

If we are talking a web-faced API (maybe REST), you can have your APIs be seperate processes so they don't get conflicts of loading stuff, and call them with something like http://www.example.org/api/1/frobnicate

simbabque
  • 53,749
  • 8
  • 73
  • 136
  • hmm, that may work nicely. it's not strictly a web facing API (there is some of that) it's mostly module to module. – skarface Jun 03 '15 at 16:48
  • I think this is the direction I'd have to go ... this kinda worked https://gist.github.com/skarfacegc/5f69a92ea2e891d1575a but the namespace collision stops it from working. Whatever version of the module that loads first wins (even if different modules ask for a different version) – skarface Jun 05 '15 at 14:49
  • Well if all of those modules are under your controll you can still copy and rename them to have one in each possible version also. If not, well. – simbabque Jun 05 '15 at 15:03
  • 1
    Yeah, I (well, my team) controls all of the code we'd want to version. I like the idea of Module::v1.1.0::Module over Module-v1.0.0 since the previous keeps the actual to level source directories a bit cleaner. Thanks for the suggestion. – skarface Jun 05 '15 at 19:30