File Coverage

blib/lib/Module/Load/Util.pm
Criterion Covered Total %
statement 62 64 96.8
branch 48 54 88.8
condition 5 7 71.4
subroutine 5 5 100.0
pod 2 2 100.0
total 122 132 92.4


line stmt bran cond sub pod time code
1             package Module::Load::Util;
2              
3 1     1   75253 use strict 'subs', 'vars';
  1         13  
  1         33  
4 1     1   444 use Regexp::Pattern::Perl::Module ();
  1         278  
  1         57  
5              
6             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
7             our $DATE = '2023-06-13'; # DATE
8             our $DIST = 'Module-Load-Util'; # DIST
9             our $VERSION = '0.009'; # VERSION
10              
11 1     1   7 use Exporter 'import';
  1         2  
  1         758  
12             our @EXPORT_OK = qw(
13             load_module_with_optional_args
14             instantiate_class_with_optional_args
15             );
16              
17             sub load_module_with_optional_args {
18 20 100   20 1 35034 my $opts = ref($_[0]) eq 'HASH' ? shift : {};
19 20         37 my $module_with_optional_args = shift;
20              
21             my $target_package =
22             defined $opts->{target_package} ? $opts->{target_package} :
23             defined $opts->{caller} ? $opts->{caller} :
24 20 50       68 caller(0);
    100          
25             # check because we will use eval ""
26             $target_package =~ $Regexp::Pattern::Perl::Module::RE{perl_modname}{pat}
27 20 50       517 or die "Invalid syntax in target package '$target_package'";
28              
29 20         45 my ($module, $args) = @_;
30 20 100       83 if (ref $module_with_optional_args eq 'ARRAY') {
    50          
    100          
31 7 100 66     45 die "array form or module/class name must have 1 or 2 elements"
32             unless @$module_with_optional_args == 1 || @$module_with_optional_args == 2;
33 6         12 $module = $module_with_optional_args->[0];
34 6   50     15 $args = $module_with_optional_args->[1] || [];
35 6 100       20 $args = [%$args] if ref $args eq 'HASH';
36 6 100       25 die "In array form of module/class name, the 2nd element must be ".
37             "arrayref or hashref" unless ref $args eq 'ARRAY';
38             } elsif (ref $module_with_optional_args) {
39 0         0 die "module/class name must be string or 2-element array, not ".
40             $module_with_optional_args;
41             } elsif ($module_with_optional_args =~ /(.+?)=(.*)/) {
42 8         25 $module = $1;
43 8         30 $args = [split /,/, $2];
44             } else {
45 5         8 $module = $module_with_optional_args;
46 5         9 $args = [];
47             }
48              
49 1         5 my @ns_prefixes = $opts->{ns_prefixes} ? @{$opts->{ns_prefixes}} :
50 18 100       64 defined($opts->{ns_prefix}) ? ($opts->{ns_prefix}) : ('');
    100          
51 18 100       37 my $try_all = $opts->{ns_prefixes} ? 1:0;
52 18         23 my $module_with_prefix;
53 18         53 for my $i (0 .. $#ns_prefixes) {
54 19         35 my $ns_prefix = $ns_prefixes[$i];
55 19 100       35 if (length $ns_prefix) {
56 3 50       13 $module_with_prefix =
57             $ns_prefix . ($ns_prefix =~ /::\z/ ? '':'::') . $module;
58             } else {
59 16         23 $module_with_prefix = $module;
60             }
61              
62 19 100 100     75 if ($opts->{load} // 1) {
63 17         84 (my $module_with_prefix_pm = "$module_with_prefix.pm") =~ s!::!/!g;
64 17 100       34 if ($try_all) {
65 2 100       11 eval { require $module_with_prefix_pm }; last unless $@;
  2         694  
  2         271  
66 1 50       10 warn $@ if $@ !~ /\ACan't locate/;
67             } else {
68 15         1779 require $module_with_prefix_pm;
69             }
70             }
71             }
72 14 50       436 if ($@) {
73 0         0 die "load_module_with_optional_args(): Failed to load module '$module' (all prefixes tried: ".join(", ", @ns_prefixes).")";
74             }
75 14         33 $module = $module_with_prefix;
76              
77 14 100       31 my $do_import = defined $opts->{import} ? $opts->{import} : 1;
78 14 100       31 if ($do_import) {
79 9         740 eval "package $target_package; $module->import(\@{\$args});"; ## no critic: BuiltinFunctions::ProhibitStringyEval
80 9 100       559 die if $@;
81             }
82              
83 13         63 {module=>$module, args=>$args};
84             }
85              
86             sub instantiate_class_with_optional_args {
87 4 100   4 1 14803 my $opts = ref($_[0]) eq 'HASH' ? {%{shift()}} : {}; # shallow copy
  3         10  
88 4         9 my $class_with_optional_args = shift;
89              
90 4         7 $opts->{import} = 0;
91 4         13 $opts->{target_package} = caller(0);
92 4         67 my $res = load_module_with_optional_args($opts, $class_with_optional_args);
93 4         8 my $class = $res->{module};
94 4         8 my $args = $res->{args};
95              
96 4 100       11 my $do_construct = defined $opts->{construct} ? $opts->{construct} : 1;
97 4 100       10 if ($do_construct) {
98             my $constructor = defined $opts->{constructor} ?
99 3 100       7 $opts->{constructor} : 'new';
100 3         19 my $obj = $class->$constructor(@$args);
101 3         29 return $obj;
102             } else {
103 1         5 return +{class=>$class, args=>$args};
104             }
105             }
106              
107             1;
108             # ABSTRACT: Some utility routines related to module loading
109              
110             __END__