Platform-independence is something which everyone aspires to when writing code (I hope) but is often one of the first things to go out of the window when time pressures come into play. In the process of preparing the LCFG build tools Perl modules for upload to CPAN I’ve been modifying various chunks to be more platform-agnostic. In particular I’ve been focussing on the file and directory name handling, it’s not that we need the code to work on Windows right now but it’s much more likely to happen at some point in the future if we start out as we mean to go on. When the code was first written I thought it was easiest to just use these sort of idioms:
my $fullpath = join '/', $dirname, $filename; my @parts = split /\//, $fullpath; my $file = pop @parts;
It turns out that by ignoring platform-independence I didn’t get all the advantages of excellent modules like File::Spec
and File::Basename
. For example:
my $fullpath = File::Spec->catfile( $dirname, $filename ); my ($volume,$directories,$file) = File::Spec->splitpath( $path );
I think that code like that is clearer and it is platform-independent without any further effort.
One thing I’ve needed several times is the ability to take two paths and find one as relative to the other. First thoughts might suggest this is simple but I ended up with several different solutions involving regular expressions which coped with them being absolute or relative to begin with. Whilst poking around the perldoc for File::Spec
today I noticed:
abs2rel Takes a destination path and an optional base path returns a relative path from the base path to the destination path: $rel_path = File::Spec->abs2rel( $path ) ; $rel_path = File::Spec->abs2rel( $path, $base ) ; If $base is not present or ’’, then Cwd::cwd() is used. If $base is relative, then it is converted to absolute form using "rel2abs()". This means that it is taken to be relative to Cwd::cwd(). On systems with the concept of volume, if $path and $base appear to be on two different volumes, we will not attempt to resolve the two paths, and we will instead simply return $path. Note that previous versions of this module ignored the volume of $base, which resulted in garbage results part of the time.
That’s exactly what I need and it handles all the cases I need. The code can now be simplified and clarified and only by thinking about platform-independence did I actually discover that function.