in reply to Gracefully choosing which module to use

When I have to do something like that I usually write compatible warppers.

What I mean by this is that I have a small module, one for each module my app knows how to use:

package MyApp::URLFetcher::LWP; use base qw/MyApp::URLFetcher/; use LWP::Simple; # define the most convenient interface you can think of # if you need just the contents of a URL in a string, do that sub get_url_to_str { my $url = shift; get($url); # our chosen interface is simple with LWP }
package MyApp::URLFetcher::NetFTP; use base qw/MyApp::URLFetcher/; use Net::FTP; sub get_url_to_str { my $self = shift; my $url = shift; # I don't know Net::FTP # either way, our interface is a bit harder to pull off # with Net::FTP # but this complexity will be in the software anyway # it's better to hide it here my $f = Net::FTP->new; # ... # ... $f->get("..."); }
I usually write one driver, the simplest one, and then add others later.

Then in your app, say you need a URL:

use UNIVERSAL::require; my $fetcher_class = choose_fetcher_class(); my $fetcher = $fetcher_class->new; # this is the good part # this line of code does not care what driver it's using, as # long as the subclass of MyApp::URLFetcher is implemented correctly # isn't polymorphism great? my $content = $fetcher->get($url); sub choose_fetcher_class { foreach my $driver (qw/LWP NetFTP/){ my $class = "MyApp::URLFetcher::$driver"; # UNIVERSAL::require let's us avoid an eval return $class if $class->require; } die "couldn't load any driver"; }

Update: Oops! I forgot the classes in the foreach loop

Also, you might want to look into Module::Pluggable and friends, they might be useful for "finding" drivers, without the code that uses them even caring about their names. I don't think they have an API to skip failed modules, and furthermore to only get the first successful one.

-nuffin
zz zZ Z Z #!perl

Replies are listed 'Best First'.
Re^2: Gracefully choosing which module to use
by gaal (Parson) on Jun 13, 2005 at 20:22 UTC
      Yeah, I know it's guts. But good point =)

      What I meant is that you don't have to construct some perl code, eval it, and maybe get it wrong and stuff.

      Encapsulation let's me feel free to ignore most of what's underneath, but normally before I get to that stage I take a good look at the insides to make sure I can trust it.

      -nuffin
      zz zZ Z Z #!perl
        The only thing it does different from what I would have naively done before I read its source code is to call CORE::require instead of require. But such streaks of paranoia are only necessary in a world where people do things like putting code in UNIVERSAL, so... :-)

        PS: Yes, I know it does that not out of paranoia but rather out of having a sub named "require" in it's own namespace. I was joking.