Subverting case insensitivity for module names under Mac HFS

Andy Wardley abw at wardley.org
Mon Jun 23 10:52:03 BST 2008


I'm trying to write some code that will automagically load plugin modules on
demand but I'm being thwarted by the case insensitivity of Apple's HFS.

Case insensitivity is a Good Thing in this case.  I would like a user to be
able to write:

   [% USE wibble %]

and have TT figure out that it needs to load the Template::Plugin::Wibble
module.  To make this Just Work[tm],  I thought it was simple case of trying
a few different capitalisations of the request module tacked onto my base
name:

   * the name exactly as specified, e.g. FooBar ==> Template::Plugin::FooBar
   * the capitalised name, e.g. wibble => Template::Plugin::Wibble
   * the upper case name, e.g. url => Template::Plugin::URL

The code looks something like this:

   sub load_plugin {
     my ($self, $name) = @_;
     my $bases = $self->plugin_base;		  # e.g. ['Template::Plugin']
     my @names = ($name, ucfirst $name, uc $name); # e.g. foo, Foo, FOO
     my $module;

     foreach my $base (@$bases) {
         foreach my $name (@names) {
             $module = $base . '::' . $name;
             return $module if UTILS->maybe_load_module($module);
         }
     }
     return $self->error_msg( not_found => plugin => $name );
   }

So far so good.  The load_plugin() module returns the name of the module
that successfully loaded so we can write this:

   my $class = $self->load_plugin($name);
   $plugin = $class->new($config);

Except that Apple's brain-dead HFS treats filenames case insensitively.  It
will merrily load Template::Plugin::URL if you ask for Template::Plugin::url
without so much as raising an eyebrow.  The problem is that Perl's classnames
are case *sensitive*, so the subsequent new() call will fail:

   $class->new($config)      # ===> Template::Plugin::url->new()    # FAIL!

Has anyone come across this before and found an easy and/or elegant way to
work around it?  The only approach that comes to mind is to let the module
get loaded and then do some symbol table inspection to figure out what the
class name really is.  But that requires some messy OS detection and smells
a bit like apple-scented camel droppings to me.  Anyone got any better ideas?

The TT2 approach is to use an explicit table mapping lower case names to their
correct-case equivalents.  However, that only works for the core plugins and
doesn't include 3rd party plugin modules that may get installed later.

Cheers
A




More information about the london.pm mailing list