package Dancer::ModuleLoader; # Abstraction layer for dynamic module loading use strict; use warnings; sub load { my ($class, $module, $version) = @_; # 0 is a valid version, so testing trueness of $version is not enough if (defined $version && length $version) { my ($res, $error) = $class->load_with_params($module); $res or return wantarray ? (0, $error) : 0; local $@; eval { $module->VERSION($version) }; $error = $@; $error and return wantarray ? (0, $error) : 0; return 1; } # normal 'use', can be done via require + import my ($res, $error) = $class->load_with_params($module); return wantarray ? ($res, $error) : $res; } sub require { my ($class, $module) = @_; local $@; my $module_filename = $module; $module_filename =~ s!::|'!/!g; $module_filename .= '.pm'; eval { require $module_filename }; my $error = $@; $error and return wantarray ? (0, $error) : 0; return 1; } sub load_with_params { my ($class, $module, @args) = @_; my ($res, $error) = $class->require($module); $res or return wantarray ? (0, $error) : 0; # From perlfunc : If no "import" method can be found then the call is # skipped, even if there is an AUTOLOAD method. if ($module->can('import')) { # bump Exporter Level to import symbols in the caller local $Exporter::ExportLevel = ( $Exporter::ExportLevel || 0 ) + 1; local $@; eval { $module->import(@args) }; my $error = $@; $error and return wantarray ? (0, $error) : 0; } return 1; } sub use_lib { my ($class, @args) = @_; use lib; local $@; lib->import(@args); my $error = $@; $error and return wantarray ? (0, $error) : 0; return 1; } sub class_from_setting { my ($self, $namespace, $setting) = @_; my $class = ''; for my $token (split /_/, $setting) { $class .= ucfirst($token); } return "${namespace}::${class}"; } 1; __END__ =head1 NAME Dancer::ModuleLoader - dynamic module loading helpers for Dancer core components =head1 SYNOPSIS Taken directly from Dancer::Template::TemplateToolkit (which is core): die "Template is needed by Dancer::Template::TemplateToolkit" unless Dancer::ModuleLoader->load('Template'); # we now have Template loaded =head1 DESCRIPTION Sometimes in Dancer core we need to use modules, but we don't want to declare them all in advance in compile-time. These could be because the specific modules provide extra features which depend on code that isn't (and shouldn't) be in core, or perhaps because we only want these components loaded in lazy style, saving loading time a bit. For example, why load L