in reply to Re^2: File::Spec::Win32 returning different result than File::Spec when doing catfile with empty string
in thread File::Spec::Win32 returning different result than File::Spec when doing catfile with empty string

Here is a quick solution that took me less time to write again than it would have taken to find where I wrote this before:

#!/usr/bin/perl use strict; use warnings; use File::Spec; # Note that test data is Unix-format! warn "Test data is in Unix format; may not work on $^O" unless File::Spec->isa('File::Spec::Unix'); my @Files = map {chomp; $_} (<DATA>); # find common prefix directories for a list of files; assuming that al +l # files are on the same volume, if the system has volumes sub common_prefix (@) { my @dirs = map {[File::Spec->splitdir((File::Spec->splitpath($_))[1] +)]} @_; my @prefix = @{shift @dirs}; foreach my $dir (@dirs) { for (my $i = 0; $i < @$dir && $i < @prefix; $i++) { splice @prefix, $i unless $dir->[$i] eq $prefix[$i] } } return @prefix } print "Sample files:\n"; print ' ',$_,"\n" for @Files; print "Common prefix:\n"; print ' ',File::Spec->catdir(common_prefix @Files),"\n"; __DATA__ /foo/bar/bax /foo/bar/baz /foo/baz/quux

Sample output:

Sample files: /foo/bar/bax /foo/bar/baz /foo/baz/quux Common prefix: /foo
  • Comment on Re^3: File::Spec::Win32 returning different result than File::Spec when doing catfile with empty string
  • Select or Download Code

Replies are listed 'Best First'.
Re^4: File::Spec::Win32 returning different result than File::Spec when doing catfile with empty string
by afoken (Chancellor) on Sep 09, 2019 at 18:54 UTC
    warn "Test data is in Unix format; may not work on $^O" unless File::Spec->isa('File::Spec::Unix');

    Fails on Win32, because File::Spec::Win32 inherits from File::Spec::Unix (see line 11 of File::Spec::Win32 v3.75). Another design issue in File::Spec (in addition to case_tolerant()). File::Spec::Unix is also used as base class for other, unrelated operating systems, instead of using an explicit base class.

    Microsoft Windows [Version 6.1.7601] Copyright (c) 2009 Microsoft Corporation. All rights reserved. C:\Users\alex>perl -MFile::Spec -E "say File::Spec->isa('File::Spec::W +in32')" 1 C:\Users\alex>perl -MFile::Spec -E "say File::Spec->isa('File::Spec::U +nix')" 1 C:\Users\alex>

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

      Fun... does $File::Spec::ISA[0] eq 'File::Spec::Unix' work reliably, then?

        Fun...

        Not fun, broken design.

        does $File::Spec::ISA[0] eq 'File::Spec::Unix' work reliably, then?

        Have a look at the source code:

        package File::Spec; use strict; our $VERSION = '3.75'; $VERSION =~ tr/_//d; my %module = ( MSWin32 => 'Win32', os2 => 'OS2', VMS => 'VMS', NetWare => 'Win32', # Yes, File::Spec::Win32 works on Ne +tWare. symbian => 'Win32', # Yes, File::Spec::Win32 works on sy +mbian. dos => 'OS2', # Yes, File::Spec::OS2 works on DJGP +P. cygwin => 'Cygwin', amigaos => 'AmigaOS'); my $module = $module{$^O} || 'Unix'; require "File/Spec/$module.pm"; our @ISA = ("File::Spec::$module"); 1;

        On all operating systems not listed in %module, File::Spec will inherit from File::Spec::Unix.

        Should be right very often. But are all non-Unix operating systems perl runs on listed in %modules? If not, File::Spec is even more broken than I tought.

        If you run Cygwin, you should be able to use case sensitive Unix-style paths. But if you run Cygwin, File::Spec will inherit from File::Spec::Cygwin (which inherits from File::Spec::Unix). At this point, $File::Spec::ISA[0] ne 'File::Spec::Unix'. Fail.

        And exactly at this point, it depends on the path that you use if the path is case sensitive or not. See File::Spec->case_tolerant() is broken, especially the Cygwin part.

        Apart from that, you should not mess with other modules' interna. Perl will let you do that, but you should not:

        Perl does not enforce private and public parts of its modules as you may have been used to in other languages like C++, Ada, or Modula-17. Perl doesn't have an infatuation with enforced privacy. It would prefer that you stayed out of its living room because you weren't invited, not because it has a shotgun.

        The module and its user have a contract, part of which is common law, and part of which is "written". Part of the common law contract is that a module doesn't pollute any namespace it wasn't asked to. The written contract for the module (A.K.A. documentation) may make other provisions. But then you know when you use RedefineTheWorld that you're redefining the world and willing to take the consequences.

        (perlmodlib)

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
Re^4: File::Spec::Win32 returning different result than File::Spec when doing catfile with empty string
by nysus (Parson) on Sep 09, 2019 at 14:42 UTC

    Thanks so much!

    $PM = "Perl Monk's";
    $MCF = "Most Clueless Friar Abbot Bishop Pontiff Deacon Curate Priest Vicar";
    $nysus = $PM . ' ' . $MCF;
    Click here if you love Perl Monks