Thanks for the compliment :)
Anyone have suggestions how I should go about modularizing this?
At first I didn't see any way to meaningfully transform it into a module since it has to have a useful interface. Then I began thinking.. the following is a brainstorming transcript if you will, so bear with me and give me feedback.
I guess I should swap out the inner loop into of the script into a subroutine and package it with the table. The rest of the hoohah for calling the script from the commandline could ship as a script like the GET, HEAD etc ones that come with LWP. The inner loop alone probably offers too little control - extra routines to allow to ask for specific conversions should be useful. So I should probably add an interface to ask whether a unit is known. Actually, the best way to do that is probably to have an interface that returns all possible conversion targets for a given unit, which would obviously return nothing (= false in scalar context) if the unit is unknown.
The question of whether there should be an interface to add new conversions at runtime and how it should look repeatedly crossed my mind during all this, but I don't feel like it's a direction I'd want to take the module in. It's probably better if it remains something a.. "metaconstant" module, a bunch of oft needed calculations you just drop in your script and don't think about. It almost makes me think the "introspection" interface (requesting what conversion targets exist for a given unit) is overkill, but then it is probably useful even for static uses for things like maybe dynamically populating dropdowns or such.
If I'm gonna go there, maybe there should plaintext names and/or descriptions for the units supported.. on second thought, that would require translation and all the countless headaches it brings along, which is definitely farther out than I want to go. It would require an extra interface for the language selection and querying the available languages too, and people will probably still have to reimplement those themselves if it doesn't happen to support their language. If could include a lot of languages - but neither do I know who I'd ask for translations, nor would I be willing to put in the effort to maintain all of that. And it would probably be useless bloat for the vast majority of users. Maybe as an addon module ::Descriptions or something, should the interest in this module ever warrant that amount of work.
So I have a module containing the conversion table, a routine for one-shot conversions, one for broadside salvo conversions (calculate any, all and every related unit you can get to), and one to ask whether a unit is known and what conversion targets it has, if so.
Then the query routine should probably differentiate between all available direct conversion targets that can be reached via the one-shot routine and the full list of related units you can get via the broadside converter.
Maybe there should be a single unit to single unit conversion routine which does not care whether a direct conversion is possible or intermediate conversions have to be done. But that would be complex - choosing the conversion steps such that you get from the source to the destination in the shortest possible way - or even at all - is far from trivial. It is simpler to just bruteforce a broadside conversion and pluck the result out of it. But the user can do that too, esp if the broadside conversion function returns its results in a convenient format. There's no point in adding garden decoration to the module.
The most convenient format is probably to return either a hashref or flat list according to the context.
Ok, I'm done. Suggestions, anyone?
Makeshifts last the longest.