1package Dancer::ModuleLoader; 2our $AUTHORITY = 'cpan:SUKRIA'; 3#ABSTRACT: dynamic module loading helpers for Dancer core components 4$Dancer::ModuleLoader::VERSION = '1.3513'; 5# Abstraction layer for dynamic module loading 6 7use strict; 8use warnings; 9use Module::Runtime qw/ use_module /; 10 11sub load { 12 my ($class, $module, $version) = @_; 13 14 my ($res, $error) = $class->require($module, $version); 15 return wantarray ? ($res, $error) : $res; 16} 17 18sub require { 19 my ($class, $module, $version) = @_; 20 eval { defined $version ? use_module( $module, $version ) 21 : use_module( $module ) } 22 or return wantarray ? (0, $@) : 0; 23 return 1; #success 24} 25 26sub load_with_params { 27 my ($class, $module, @args) = @_; 28 my ($res, $error) = $class->require($module); 29 $res or return wantarray ? (0, $error) : 0; 30 31 # From perlfunc : If no "import" method can be found then the call is 32 # skipped, even if there is an AUTOLOAD method. 33 if ($module->can('import')) { 34 35 # bump Exporter Level to import symbols in the caller 36 local $Exporter::ExportLevel = ($Exporter::ExportLevel || 0) + 1; 37 local $@; 38 eval { $module->import(@args) }; 39 my $error = $@; 40 $error and return wantarray ? (0, $error) : 0; 41 } 42 return 1; 43} 44 45sub use_lib { 46 my ($class, @args) = @_; 47 use lib; 48 local $@; 49 lib->import(@args); 50 my $error = $@; 51 $error and return wantarray ? (0, $error) : 0; 52 return 1; 53} 54 55sub class_from_setting { 56 my ($self, $namespace, $setting) = @_; 57 58 my $class = ''; 59 for my $token (split /_/, $setting) { 60 $class .= ucfirst($token); 61 } 62 return "${namespace}::${class}"; 63} 64 651; 66 67__END__ 68 69=pod 70 71=encoding UTF-8 72 73=head1 NAME 74 75Dancer::ModuleLoader - dynamic module loading helpers for Dancer core components 76 77=head1 VERSION 78 79version 1.3513 80 81=head1 SYNOPSIS 82 83Taken directly from Dancer::Template::TemplateToolkit (which is core): 84 85 die "Template is needed by Dancer::Template::TemplateToolkit" 86 unless Dancer::ModuleLoader->load('Template'); 87 88 # we now have Template loaded 89 90=head1 DESCRIPTION 91 92Sometimes in Dancer core we need to use modules, but we don't want to declare 93them all in advance in compile-time. These could be because the specific modules 94provide extra features which depend on code that isn't (and shouldn't) be in 95core, or perhaps because we only want these components loaded in lazy style, 96saving loading time a bit. For example, why load L<Template> (which isn't 97required by L<Dancer>) when you don't use L<Dancer::Template::TemplateToolkit>? 98 99To do such things takes a bit of code for localizing C<$@> and C<eval>ing. That 100code has been refactored into this module to help Dancer core developers. 101 102B<Please only use this for Dancer core modules>. If you're writing an external 103Dancer module (L<Dancer::Template::Tiny>, L<Dancer::Session::Cookie>, etc.), 104please simply "C<use ModuleYouNeed>" in your code and don't use this module. 105 106=head1 METHODS/SUBROUTINES 107 108=head2 load 109 110Runs something like "C<use ModuleYouNeed>" at runtime. 111 112 use Dancer::ModuleLoader; 113 ... 114 Dancer::ModuleLoader->load('Something') 115 or die "Couldn't load Something\n"; 116 117 # load version 5.0 or more 118 Dancer::ModuleLoader->load('Something', '5.0') 119 or die "Couldn't load Something\n"; 120 121 # load version 5.0 or more 122 my ($res, $error) = Dancer::ModuleLoader->load('Something', '5.0'); 123 $res or die "Couldn't load Something : '$error'\n"; 124 125Takes in arguments the module name, and optionally the minimum version number required. 126 127In scalar context, returns 1 if successful, 0 if not. 128In list context, returns 1 if successful, C<(0, "error message")> if not. 129 130If you need to give argument to the loading module, please use the method C<load_with_params> 131 132=head2 require 133 134Runs a "C<require ModuleYouNeed>". 135 136 use Dancer::ModuleLoader; 137 ... 138 Dancer::ModuleLoader->require('Something') 139 or die "Couldn't require Something\n"; 140 my ($res, $error) = Dancer::ModuleLoader->require('Something'); 141 $res or die "Couldn't require Something : '$error'\n"; 142 143If you are unsure what you need (C<require> or C<load>), learn the differences 144between C<require> and C<use>. 145 146Takes in arguments the module name. 147 148In scalar context, returns 1 if successful, 0 if not. 149In list context, returns 1 if successful, C<(0, "error message")> if not. 150 151=head2 load_with_params 152 153Runs a "C<use ModuleYouNeed qw(param1 param2 ...)>". 154 155 use Dancer::ModuleLoader; 156 ... 157 Dancer::ModuleLoader->load_with_params('Something', qw(param1 param2) ) 158 or die "Couldn't load Something with param1 and param2\n"; 159 160 my ($res, $error) = Dancer::ModuleLoader->load_with_params('Something', @params); 161 $res or die "Couldn't load Something with @params: '$error'\n"; 162 163Takes in arguments the module name, and optionally parameters to pass to the import internal method. 164 165In scalar context, returns 1 if successful, 0 if not. 166In list context, returns 1 if successful, C<(0, "error message")> if not. 167 168=head2 use_lib 169 170Runs a "C<use lib qw(path1 path2)>" at run time instead of compile time. 171 172 use Dancer::ModuleLoader; 173 ... 174 Dancer::ModuleLoader->use_lib('path1', @other_paths) 175 or die "Couldn't perform use lib\n"; 176 177 my ($res, $error) = Dancer::ModuleLoader->use_lib('path1', @other_paths); 178 $res or die "Couldn't perform use lib : '$error'\n"; 179 180Takes in arguments a list of path to be prepended to C<@INC>, in a similar way 181than C<use lib>. However, this is performed at run time, so the list of paths 182can be generated and dynamic. 183 184In scalar context, returns 1 if successful, 0 if not. 185In list context, returns 1 if successful, C<(0, "error message")> if not. 186 187=head2 class_from_setting 188 189Given a setting in Dancer::Config, composes the class it should be. 190 191This is the function that translates: 192 193 # in config.yaml 194 template: "template_toolkit" 195 196To the class: 197 198 Dancer::Template::TemplateToolkit 199 200Example: 201 202 use Dancer::ModuleLoader; 203 my $class = Dancer::ModuleLoader->class_from_setting( 204 'Dancer::Template' => 'template_toolkit', 205 ); 206 207 # $class == 'Dancer::Template::TemplateToolkit 208 209 $class = Dancer::ModuleLoader->class_from_setting( 210 'Dancer::Template' => 'tiny', 211 ); 212 213 # class == 'Dancer::Template::Tiny 214 215=head1 SEE ALSO 216 217L<Module::Load>, L<Module::New::Loader> 218 219=head1 AUTHOR 220 221Dancer Core Developers 222 223=head1 COPYRIGHT AND LICENSE 224 225This software is copyright (c) 2010 by Alexis Sukrieh. 226 227This is free software; you can redistribute it and/or modify it under 228the same terms as the Perl 5 programming language system itself. 229 230=cut 231