Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses

Re: Best practice for a module which can use one of multiple image modules

by Corion (Pope)
on Aug 17, 2019 at 06:27 UTC ( #11104600=note: print w/replies, xml ) Need Help??

in reply to Best practice for a module which can use one of multiple image modules

Personally, I've settled on having one top-level module that looks at what is available (resp. what the programmer specifies), and a set of modules below that, which are the implementations for each "real" module:

package Future::HTTP; use strict; use Filter::signatures; no warnings 'experimental::signatures'; use feature 'signatures'; our $VERSION = '0.12'; our @loops; push @loops, ( ['IO/' => 'Future::HTTP::NetAsync' ], ['Mojo/' => 'Future::HTTP::Mojo' ], ['' => 'Future::HTTP::AnyEvent'], ['' => 'Future::HTTP::AnyEvent'], # POE support would be nice # LWP::UserAgent support would be nice # A threaded backend would also be nice but likely brings in other # interesting problems. How will we load this? We have two prerequ +isites # now, and HTTP::Tiny... #['' => 'Future::HTTP::Tiny::threaded' ], ['HTTP/Tiny/' => 'Future::HTTP::Tiny::Paranoid'], # The fallback, will always catch due to loading Future::HTTP ['Future/' => 'Future::HTTP::Tiny'], ); our $implementation; sub new($factoryclass, @args) { $implementation ||= $factoryclass->best_implementation(); # return a new instance $implementation->new(@args); } sub best_implementation( $class, @candidates ) { if(! @candidates) { @candidates = @loops; }; # Find the currently running/loaded event loop(s) #use Data::Dumper; #warn Dumper \%INC; #warn Dumper \@candidates; my @applicable_implementations = map { $_->[1] } grep { $INC{$_->[0]} } @candidates; # Check which one we can load: for my $impl (@applicable_implementations) { if( eval "require $impl; 1" ) { return $impl; }; }; };

This is likely overkill when the real meat is a subroutine of three or four lines and mostly parameter swapping, but I find the above approach easier, since each module can be conveniently tested.

Otherwise, I'll likely do the above except that best_implementation returns a reference to a subroutine:

sub do_imagemagick { require Image::Magick; Image::Magick->import(...); # ... } sub do_imager { require Imager; Imager->import(...); # ... }

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://11104600]
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chilling in the Monastery: (5)
As of 2020-08-14 20:05 GMT
Find Nodes?
    Voting Booth?
    Which rocket would you take to Mars?

    Results (76 votes). Check out past polls.