File Coverage

blib/lib/Module/Load/Util.pm
Criterion Covered Total %
statement 60 62 96.7
branch 45 50 90.0
condition 3 5 60.0
subroutine 5 5 100.0
pod 2 2 100.0
total 115 124 92.7


line stmt bran cond sub pod time code
1             package Module::Load::Util;
2              
3 1     1   65121 use strict 'subs', 'vars';
  1         12  
  1         31  
4 1     1   465 use Regexp::Pattern::Perl::Module ();
  1         178  
  1         47  
5              
6             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
7             our $DATE = '2021-09-30'; # DATE
8             our $DIST = 'Module-Load-Util'; # DIST
9             our $VERSION = '0.007'; # VERSION
10              
11 1     1   6 use Exporter 'import';
  1         2  
  1         599  
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 18 100   18 1 28332 my $opts = ref($_[0]) eq 'HASH' ? shift : {};
19 18         28 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 18 50       69 caller(0);
    100          
25             # check because we will use eval ""
26             $target_package =~ $Regexp::Pattern::Perl::Module::RE{perl_modname}{pat}
27 18 50       447 or die "Invalid syntax in target package '$target_package'";
28              
29 18         39 my ($module, $args) = @_;
30 18 100       85 if (ref $module_with_optional_args eq 'ARRAY') {
    50          
    100          
31 5 100 66     31 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 4         9 $module = $module_with_optional_args->[0];
34 4   50     12 $args = $module_with_optional_args->[1] || [];
35 4 100       10 $args = [%$args] if ref $args eq 'HASH';
36 4 100       17 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         31 $args = [split /,/, $2];
44             } else {
45 5         7 $module = $module_with_optional_args;
46 5         8 $args = [];
47             }
48              
49 1         3 my @ns_prefixes = $opts->{ns_prefixes} ? @{$opts->{ns_prefixes}} :
50 16 100       60 defined($opts->{ns_prefix}) ? ($opts->{ns_prefix}) : ('');
    100          
51 16 100       32 my $try_all = $opts->{ns_prefixes} ? 1:0;
52 16         26 my $module_with_prefix;
53 16         45 for my $i (0 .. $#ns_prefixes) {
54 17         24 my $ns_prefix = $ns_prefixes[$i];
55 17 100       34 if (length $ns_prefix) {
56 3 50       12 $module_with_prefix =
57             $ns_prefix . ($ns_prefix =~ /::\z/ ? '':'::') . $module;
58             } else {
59 14         18 $module_with_prefix = $module;
60             }
61              
62             # XXX option load=0?
63 17         78 (my $module_with_prefix_pm = "$module_with_prefix.pm") =~ s!::!/!g;
64 17 100       35 if ($try_all) {
65 2 100       3 eval { require $module_with_prefix_pm }; last unless $@;
  2         630  
  2         282  
66             } else {
67 15         1760 require $module_with_prefix_pm;
68             }
69             }
70 12 50       425 if ($@) {
71 0         0 die "load_module_with_optional_args(): Failed to load module '$module' (all prefixes tried: ".join(", ", @ns_prefixes).")";
72             }
73 12         23 $module = $module_with_prefix;
74              
75 12 100       48 my $do_import = defined $opts->{import} ? $opts->{import} : 1;
76 12 100       27 if ($do_import) {
77 8         736 eval "package $target_package; $module->import(\@{\$args});"; ## no critic: BuiltinFunctions::ProhibitStringyEval
78 8 100       463 die if $@;
79             }
80              
81 11         50 {module=>$module, args=>$args};
82             }
83              
84             sub instantiate_class_with_optional_args {
85 3 100   3 1 9239 my $opts = ref($_[0]) eq 'HASH' ? {%{shift()}} : {}; # shallow copy
  2         6  
86 3         5 my $class_with_optional_args = shift;
87              
88 3         8 $opts->{import} = 0;
89 3         14 $opts->{target_package} = caller(0);
90 3         49 my $res = load_module_with_optional_args($opts, $class_with_optional_args);
91 3         8 my $class = $res->{module};
92 3         4 my $args = $res->{args};
93              
94 3 100       7 my $do_construct = defined $opts->{construct} ? $opts->{construct} : 1;
95 3 100       9 if ($do_construct) {
96             my $constructor = defined $opts->{constructor} ?
97 2 100       7 $opts->{constructor} : 'new';
98 2         12 my $obj = $class->$constructor(@$args);
99 2         17 return $obj;
100             } else {
101 1         5 return +{class=>$class, args=>$args};
102             }
103             }
104              
105             1;
106             # ABSTRACT: Some utility routines related to module loading
107              
108             __END__