Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

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/Async.pm' => 'Future::HTTP::NetAsync' ], ['Mojo/IOLoop.pm' => 'Future::HTTP::Mojo' ], ['AnyEvent.pm' => 'Future::HTTP::AnyEvent'], ['AE.pm' => '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, threads.pm and HTTP::Tiny... #['threads.pm' => 'Future::HTTP::Tiny::threaded' ], ['HTTP/Tiny/Paranoid.pm' => 'Future::HTTP::Tiny::Paranoid'], # The fallback, will always catch due to loading Future::HTTP ['Future/HTTP.pm' => '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?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (3)
As of 2019-09-23 04:45 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    The room is dark, and your next move is ...












    Results (276 votes). Check out past polls.

    Notices?