File Coverage

blib/lib/Module/UseFrom.pm
Criterion Covered Total %
statement 103 106 97.1
branch 19 22 86.3
condition 9 10 90.0
subroutine 19 19 100.0
pod 0 5 0.0
total 150 162 92.5


line stmt bran cond sub pod time code
1             package Module::UseFrom;
2             {
3             $Module::UseFrom::VERSION = '0.03';
4             }
5              
6 6     6   295552 use strict;
  6         17  
  6         255  
7 6     6   33 use warnings;
  6         13  
  6         182  
8              
9 6     6   95 use v5.8.1;
  6         22  
  6         296  
10              
11 6     6   33 use Carp;
  6         11  
  6         602  
12 6     6   33888 use Module::CoreList;
  6         453816  
  6         100  
13 6     6   4871 use Scalar::Util qw/dualvar/;
  6         14  
  6         1203  
14 6     6   6001 use ExtUtils::Installed;
  6         656098  
  6         264  
15 6     6   59 use version 0.77;
  6         226  
  6         67  
16              
17 6     6   7218 use Devel::Declare ();
  6         47777  
  6         2064  
18              
19             my $inst = ExtUtils::Installed->new();
20              
21             our $verbose;
22             my %export_ok = (
23             'use_from' => { const => \&rewrite_use_from },
24             'use_if_available' => { const => \&rewrite_use_if_available },
25             );
26              
27             ######################
28             ## utility functions
29              
30             sub _my_warn {
31 18     18   30 my $string = shift;
32 18 100       65 if ($verbose) {
33 14 50 50     60 if ((ref $verbose || '') eq 'SCALAR') {
34 14         46 $$verbose .= $string;
35             } else {
36 0         0 warn $string;
37             }
38             }
39             }
40              
41             sub find_module_version {
42 7     7 0 14 my $module = shift;
43              
44             my $version =
45 7 100 100     15 eval { $inst->version($module) } ||
      100        
46             exists $Module::CoreList::version{$]}{$module}
47             ? ( $Module::CoreList::version{$]}{$module} || 1e-7 )
48             : 0;
49              
50             # some core module do not have version numbers, they are returned as 1e-7
51              
52 7         3558 $version = version->parse($version);
53              
54 7         19 return $version;
55             }
56              
57             sub get_varref_by_name {
58 9     9 0 24 my ($caller, $var) = @_;
59 9         27 my $varname = $caller . '::' . $var;
60              
61 6     6   136 no strict 'refs';
  6         13  
  6         1800  
62 9         42 my $varref =
63 9         28 (defined ${$varname})
64 9 50       16 ? \${$varname}
65             : croak "Cannot access variable \$$varname";
66              
67 9         28 return $varref;
68             }
69              
70             ###########
71             ## import
72              
73             sub import {
74 6     6   172 my $class = shift;
75              
76             # setup from explicit imports
77 6         26 my $export = {};
78 6         25 foreach my $keyword (@_) {
79              
80             # :all tag
81 3 100       25 if ($keyword eq ':all') {
82 1         4 $export = \%export_ok;
83 1         4 last;
84             }
85              
86             # check import is available
87 2 50       13 unless ( exists $export_ok{$keyword} ) {
88 0         0 carp "Keyword $keyword is not exported by Module::UseFrom";
89 0         0 next;
90             }
91              
92             # setup specific keyword
93 2         9 $export->{$keyword} = $export_ok{$keyword};
94             }
95              
96             # if called without explicit imports
97 6 100       51 unless (keys %$export) {
98 3         13 $export->{'use_from'} = $export_ok{'use_from'};
99             }
100              
101 6         28 my $caller = caller;
102              
103 6         92 Devel::Declare->setup_for( $caller, $export );
104              
105 6         216 foreach my $keyword (keys %$export) {
106 6     6   63 no strict 'refs';
  6         13  
  6         4551  
107 7     9   51 *{$caller.'::'.$keyword} = sub (@) {};
  7         10574  
  9         41  
108             }
109              
110             }
111              
112             ##################
113             ## rewrite rules
114              
115             sub rewrite_use_from {
116 2     2 0 318115 my $linestr = Devel::Declare::get_linestr;
117              
118 2         15 _my_warn "use_from got: $linestr";
119              
120 2         8 my $caller = Devel::Declare::get_curstash_name;
121              
122 2         33 $linestr =~ s/use_from\s+\$(\w+)/
123 2         8 my $varref = get_varref_by_name($caller, $1);
124 2         4 my $module = $$varref;
125 2         9 "use_from; use $module";
126             /e;
127            
128 2         10 _my_warn "use_from returned: $linestr";
129              
130 2         17 Devel::Declare::set_linestr($linestr);
131             }
132              
133             sub rewrite_use_if_available {
134 7     7 0 377053 my $linestr = Devel::Declare::get_linestr;
135              
136 7         31 _my_warn "use_if_available got: $linestr";
137              
138 7         21 my $caller = Devel::Declare::get_curstash_name;
139              
140 7         69 $linestr =~ s/use_if_available\s+\$(\w+)(\s+[^\s;]+)?/
141 7         23 my $name = $1;
142 7         15 my $version = $2;
143 7         21 do_use_if_available($caller, $name, $version);
144             /e;
145            
146 7         31 _my_warn "use_if_available returned: $linestr";
147              
148 7         73 Devel::Declare::set_linestr($linestr);
149             }
150              
151             sub do_use_if_available {
152 7     7 0 16 my ($caller, $name, $version) = @_;
153 7         12 my $return = 'use_if_available ';
154              
155 7         20 my $varref = get_varref_by_name($caller, $name);
156 7         11 my $module = $$varref;
157              
158 7         18 my $found_version = find_module_version($module);
159              
160 7 100       139 unless ($found_version) {
161 1         6 my $dualvar = dualvar 0, $module;
162 1         3 $$varref = $dualvar;
163 1         43 return $return;
164             }
165              
166 6         57 my $requested_version;
167 6 100       18 if ($version) {
168 4         5 $requested_version = eval { version->parse($version) };
  4         26  
169             }
170              
171 6 100 100     48 if (defined $requested_version and $requested_version > $found_version) {
172 2         9 my $dualvar = dualvar 0, $module;
173 2         3 $$varref = $dualvar;
174 2         11 return $return;
175             }
176              
177 4         63 my $dualvar = dualvar $found_version->numify, $module;
178 4         11 $$varref = $dualvar;
179              
180 4         12 $return .= "; use $module";
181 4 100       14 $return .= $version if $version;
182              
183 4         27 return $return;
184             }
185              
186             1;
187              
188             __END__