File Coverage

blib/lib/Getopt/Module.pm
Criterion Covered Total %
statement 66 70 94.2
branch 25 34 73.5
condition 5 8 62.5
subroutine 10 10 100.0
pod 1 1 100.0
total 107 123 86.9


line stmt bran cond sub pod time code
1             package Getopt::Module;
2              
3 1     1   991 use strict;
  1         2  
  1         43  
4 1     1   7 use warnings;
  1         2  
  1         38  
5              
6 1     1   15 use vars qw($VERSION @EXPORT_OK);
  1         3  
  1         65  
7              
8 1     1   6 use Carp qw(confess);
  1         2  
  1         72  
9 1     1   5 use Exporter qw(import);
  1         2  
  1         30  
10 1     1   5 use Scalar::Util;
  1         2  
  1         915  
11              
12             $VERSION = '0.0.2';
13             @EXPORT_OK = qw(GetModule);
14              
15             my $MODULE_RE = qr{
16             ^ # match the beginning of the string
17             (-)? # optional: leading hyphen: use 'no' instead of 'use'
18             (\w+(?:::\w+)*) # required: Module::Name
19             (?:(=|\s+) (.+))? # optional: args prefixed by '=' e.g. 'Module=arg1,arg2' or \s+ e.g. 'Module qw(foo bar)'
20             $ # match the end of the string
21             }x;
22              
23             # return true if $ref ISA $class - works with non-references, unblessed references and objects
24             sub _isa($$) {
25 230     230   1581 my ($ref, $class) = @_;
26 230 50       3017 return Scalar::Util::blessed(ref) ? $ref->isa($class) : ref($ref) eq $class;
27             }
28              
29             # dump value like Data::Dump/Data::Dumper::Concise
30             sub _pp($) {
31 1096     1096   376781 my $value = shift;
32 1096         6523 require Data::Dumper;
33 1096         19183 local $Data::Dumper::Deepcopy = 1;
34 1096         1341 local $Data::Dumper::Indent = 0;
35 1096         1400 local $Data::Dumper::Purity = 0;
36 1096         1188 local $Data::Dumper::Terse = 1;
37 1096         1196 local $Data::Dumper::Useqq = 1;
38 1096         2652 return Data::Dumper::Dumper($value);
39             }
40              
41             sub GetModule($@) {
42 72     72 1 5848 my $target = shift;
43 72         130 my $params;
44              
45 72 50       246 if (@_ == 1) {
    0          
46 72         107 $params = shift;
47              
48 72 50       195 unless (_isa($params, 'HASH')) {
49 0         0 confess "invalid parameter; expected HASH or HASHREF, got ", _pp(ref($params));
50             }
51             } elsif ((@_ % 2) == 0) {
52 0         0 $params = { @_ };
53             } else {
54 0         0 confess "invalid parameters; expected hash or hashref, got odd number of arguments > 1";
55             }
56              
57 72         192 my $no_import = $params->{no_import};
58 72 100       234 my $separator = defined($params->{separator}) ? $params->{separator} : ' ';
59              
60             return sub {
61 72     72   272 my $name = shift;
62 72         95 my $value = shift;
63              
64 72 50 33     500 confess 'invalid option definition: option must target a scalar ("foo=s") or array ("foo=@")'
65             unless (defined($value) && (@_ == 0));
66 72 50       7971 confess sprintf("invalid value for %s option: %s", $name, _pp($value))
67             unless ($value =~ $MODULE_RE);
68              
69 72         368 my ($hyphen, $module, $args_start, $args) = ($1, $2, $3, $4);
70 72         104 my ($statement, $method, $eval);
71              
72 72 100       583 if ($hyphen) {
73 31         209 $statement = 'no';
74 31         62 $method = 'unimport';
75             } else {
76 41         58 $statement = 'use';
77 41         88 $method = 'import';
78             }
79              
80 72 100       161 if ($args_start) { # this takes precedence over no_import - see perlrun
81 31 50       91 $args = '' unless (defined $args);
82              
83 31 100       97 if ($args_start eq '=') {
84 23         84 $eval = "$statement $module split(/,/,q\0$args\0);"; # see perl.c
85             } else { # space: arbitrary expression
86 8         35 $eval = "$statement $module $args;";
87             }
88             } else {
89 41 100       267 if ($no_import) {
90 11         47 $eval = "$statement $module ();";
91             } else {
92 30         77 $eval = "$statement $module;";
93             }
94             }
95              
96 72         2803 my $spec = {
97             args => $args,
98             eval => $eval,
99             method => $method,
100             module => $module,
101             name => $name,
102             statement => $statement,
103             value => $value,
104             };
105              
106 72 100       173 if (_isa($target, 'ARRAY')) {
    100          
    100          
    50          
107 24         54 push @$target, $eval;
108             } elsif (_isa($target, 'SCALAR')) { # SCALAR ref
109 20 100 66     75 if (defined($$target) && length($$target)) {
110 4         11 $$target .= "$separator$eval";
111             } else {
112 16         26 $$target = $eval;
113             }
114             } elsif (_isa($target, 'HASH')) {
115 18   100     104 $target->{$module} ||= [];
116 18         24 push @{ $target->{$module} }, $eval;
  18         51  
117             } elsif (_isa($target, 'CODE')) {
118 10         42 $target->($name, $eval, $spec);
119             } else {
120 0         0 confess "invalid target type - expected array ref, code ref, hash ref or scalar ref, got: ", ref($target);
121             }
122              
123 72         3054 return $spec; # ignored by Getopt::Long, but useful for testing
124 72         637 };
125             }
126              
127             1;
128              
129             __END__