Skip to content

Instantly share code, notes, and snippets.

@neilb
Last active April 4, 2021 11:15
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save neilb/52f043c4d863a56fbe4534632f6658e6 to your computer and use it in GitHub Desktop.
An experimential module that uses Keyword::Simple to provide syntax for optionally loading a module
package optionally;
# optionally load a module and import functions
#
# Syntax:
#
# use optionally;
# optionally use Module::Foo 1.37 function1 function2;
#
# This was an experiment, and is not at all ready for real use.
use strict;
use warnings;
use Keyword::Simple ();
use Carp qw/ croak /;
use Module::Runtime qw/ require_module /;
use Class::Unload ();
my %have_loaded;
sub import
{
my $importing_package = caller;
Keyword::Simple::define('optionally' => sub {
my $line = shift;
# my ($matched, $action, $module, $rest) = ( $$line =~ m!\A(\s*(\S+)\s+(\S+)\s*(.*?);)!ms )
my ($matched, $action, $module, $rest) = ( $$line =~ m!\A(\s*(\S+)\s+(\S+)\s*(.*?);)! )
or croak "syntax error near 'optiona'";
substr($$line, 0, length($matched)) = "BEGIN { optionally::run(\"$importing_package\", \"$action\", \"$module\", \"$rest\"); }";
});
}
sub run
{
my ($importing_package, $action, $module_name, $rest) = @_;
croak "sorry, I don't know how to optionally '$action' yet ..." unless $action eq 'use';
# If we can't even load the specified package, then silently do no more
return unless require_module($module_name);
$have_loaded{ $module_name } = 1;
my @args = split(/\s+/, $rest);
# If there's no args, then we call the default import on the
if (@args > 0 && _looks_like_version_number($args[0])) {
my $required_version = shift @args;
eval "${module_name}->VERSION($required_version);\n";
if ($@) {
delete $INC{ $module_name };
Class::Unload->unload($module_name);
return;
}
}
if (@args > 0) {
no strict 'refs';
foreach my $subname (@args) {
*{"${importing_package}::$subname"} = *{"${module_name}::$subname"}{CODE}
// croak "No $subname() available for import from $module_name";
}
}
else {
eval "package $importing_package; ${module_name}->import()";
}
}
sub _looks_like_version_number
{
my $string = shift;
return $string =~ m!^[0-9\.]+$!;
}
sub loaded
{
my $module_name = shift;
print STDERR "HELLO!\n";
return $have_loaded{ $module_name };
}
1;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment