Problem: you have some kind of data that needs to be distributed with your Perl module. Where do you put it in a cross-platform way?
Solution #1: Put it in a giant datastructure inside some module. This ends up with a big .pm file that chews up memory.
Solution #2: Put it in a __DATA__ section. But you only get one of those per module, and binary data might get hairy.
Best solution: File::ShareDir.
If you’ve ever looked through your Perl module directory, you’ve no doubt seen a directory called ‘auto’. This was used for a few different autoloading systems, but there’s no reason you can’t use it for your own module.
When I added SDL navigation data output to UAV::Pilot, the text overlayed on the screen needed a specific font. SDLx::Text can take a path to a TrueType font file, but where do you put that file?
The answer is that you create a ‘share/’ directory in your project and drop it in. The files there will be placed in your module’s ‘auto/’ entry. You can then get the path to the file with:
1 2 3 4 5 |
use File::ShareDir 'dist_dir'; use File::Spec; my $dir = dist_dir( 'UAV-Pilot' ); my $file = File::Spec::catfile( $dir, 'font.ttf' ); |
Thus providing a safe, cross-platform way of storing module files.
Nifty! I’ve had that problem many times.
I use it in https://metacpan.org/release/WebService-ReutersConnect
Also it’s worth mentioning File::Share, which is a drop-in replacement that will also work in your unit tests, using your development’s ‘shared’ directory.
In production, you don’t have to have File::Share installed, providing you use some code like that to load the dist_file function in your namespace:
BEGIN{
eval{ require File::Share; File::Share->import(‘dist_file’); };
if( $@ ){
require File::ShareDir;
File::ShareDir->import(‘dist_file’);
}
};
Also, don’t forget to skip your unit test if File::Share is not available on the system.
Jerome.