File Coverage

blib/lib/PDL/AutoLoader.pm
Criterion Covered Total %
statement 66 92 71.7
branch 19 50 38.0
condition 2 11 18.1
subroutine 12 14 85.7
pod 1 4 25.0
total 100 171 58.4


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             PDL::AutoLoader - MatLab style AutoLoader for PDL
4              
5             =head1 SYNOPSIS
6              
7             use PDL::AutoLoader;
8             $x = func1(...); # Load file func1.pdl
9             $y = func2(...); # Load file func2.pdl
10              
11             $PDL::AutoLoader::Rescan = 1; # Enable re-scanning
12              
13             =head1 DESCRIPTION
14              
15             This module implements a MatLab style AutoLoader for PDL. If an unknown
16             function C is called, PDL looks for a file called C.
17             If it finds one, it compiles the file and calls the function C.
18              
19             The list of directories to search in is given by the shell environment
20             variable C. This is a colon-separated list of directories. On
21             MSWindows systems, is it a I -separated list of directories.
22              
23             For example, in csh:
24              
25             setenv PDLLIB "/home/joe/pdllib:/local/pdllib"
26              
27             B: This variable is unrelated to Perl's C.
28              
29             If you add a leading '+' on a directory name, PDL will search the
30             entire directory tree below that point. Internally, PDL stores the
31             directory list in the variable C<@PDLLIB>, which can be modified at
32             run time.
33              
34             For example, in csh:
35              
36             setenv PDLLIB "+/home/joe/PDL"
37              
38             will search /home/joe/PDL and all its subdirectories for .pdl files.
39              
40             =head2 AUTO-SCANNING
41              
42             The variable C<$PDL::AutoLoader::Rescan> controls whether files
43             are automatically re-scanned for changes at the C
44             command line.
45              
46             If C<$PDL::AutoLoader::Rescan == 1> and the file is changed
47             then the new definition is reloaded auto-matically before
48             executing the C command line. Which means
49             in practice you can edit files, save changes and have C
50             see the changes automatically.
51              
52             The default is '0' - i.e. to have this feature disabled.
53              
54             As this feature is only pertinent to the PDL shell it imposes
55             no overhead on PDL scripts. Yes Bob you can have your cake and
56             eat it too!
57              
58             Note: files are only re-evaled if they are determined to have
59             been changed according to their date/time stamp.
60              
61             No doubt this interface could be improved upon some more. :-)
62              
63             =head2 Sample file:
64              
65             sub foo { # file 'foo.pdl' - define the 'foo' function
66             my $x=shift;
67             return sqrt($x**2 + $x**3 + 2);
68             }
69             1; # File returns true (i.e. loaded successfully)
70              
71             =head1 AUTHOR
72              
73             Copyright(C) 1997 Karl Glazebrook (kgb@aaoepp.aao.gov.au);
74             several extensions by Craig DeForest (deforest@boulder.swri.edu)
75             All rights reserved. There is no warranty. You are allowed
76             to redistribute this software / documentation under certain
77             conditions. For details, see the file COPYING in the PDL
78             distribution. If this file is separated from the PDL distribution,
79             the copyright notice should be included in the file.
80              
81             =head1 BUGS
82              
83             No doubt this interface could be improved upon some more. :-)
84              
85             Will probably be quite slow if C<$PDL::AutoLoader::Rescan == 1>
86             and thousands of functions have been autoloaded.
87              
88             There could be a race condition in which the file changes
89             while the internal autoloader code is being executed but it
90             should be harmless.
91              
92             Probably has not been tested enough!
93              
94             =head1 SEE ALSO
95              
96             For an alternative approach to managing a personal collaction of
97             modules and functions, see L.
98              
99             =cut
100              
101 1     1   228041 use strict;
  1         2  
  1         31  
102 1     1   5 use warnings;
  1         1  
  1         174  
103              
104             our @PDLLIB;
105             BEGIN{
106 1 50   1   5 if (defined $ENV{"PDLLIB"}) {
107 0 0       0 if ( $^O eq 'MSWin32' ) { # win32 flavors
108 0         0 @PDLLIB = (".",split(';',$ENV{"PDLLIB"}));
109 0         0 s/"//g for @PDLLIB;
110             } else { # unixen systems
111 0         0 @PDLLIB = (".",split(':',$ENV{"PDLLIB"}));
112             }
113 0         0 @PDLLIB = grep length, @PDLLIB;
114             }
115 1         2 $PDL::AutoLoader::Rescan=0;
116 1         723 %PDL::AutoLoader::FileInfo = ();
117             }
118              
119             # Code to reload stuff if changed
120              
121             sub PDL::AutoLoader::reloader {
122 0 0   0 0 0 return unless $PDL::AutoLoader::Rescan;
123              
124             # Now check functions and reload if changed
125              
126 0         0 my ($file, $old_t);
127 0         0 for my $func (sort keys %PDL::AutoLoader::FileInfo) {
128 0         0 ($file, $old_t) = @{ $PDL::AutoLoader::FileInfo{$func} };
  0         0  
129 0 0       0 if ( (stat($file))[9]>$old_t ) { # Reload
130 0 0       0 print "Reloading $file as file changed...\n" if $PDL::verbose;
131 0         0 PDL::AutoLoader::autoloader_do($file);
132 0         0 $PDL::AutoLoader::FileInfo{$func} = [ $file, (stat($file))[9] ];
133             }
134             }
135             }
136              
137             # Used for Beta, and should probably be used generall in this mod
138             #use File::Spec;
139              
140             sub PDL::AutoLoader::import {
141              
142             # Beta folder support
143             # foreach (@INC) {
144             # $Beta_dir = File::Spec->catfile($_, 'PDL', 'Beta');
145             # push @PDLLIB, "+$Beta_dir" if -d $Beta_dir;
146             # }
147              
148 1     1   11 my $pkg = (caller())[0];
149 1         2 my $toeval = "package $pkg; no strict; no warnings;\n";
150              
151             # Make sure that the eval gets NiceSlice if we have it in this level
152             # (it's a drag that preprocessors aren't transitive...)
153 1 50       5 $toeval .= "use PDL::NiceSlice;\n" if(defined $PDL::NiceSlice::VERSION);
154              
155 1         3 $toeval .= <<'EOD';
156             $PDLLIB_CT = 0;
157              
158             push @PERLDL::AUTO, \&PDL::AutoLoader::reloader;
159              
160             sub AUTOLOAD {
161             local @INC = @INC;
162             my @args = @_;
163             $AUTOLOAD =~ /::([^:]*)$/;
164             my $func = $1;
165              
166             # Trap spurious calls from 'use UnknownModule'
167              
168             goto &$AUTOLOAD if ord($func)==0;
169              
170             # Check if the PDLLIB needs to be expanded and, if so, expand it.
171             # This only updates when PDLLIB changes size, which should be OK
172             # for most things but doesn't catch new directories in expanded
173             # directory trees. It seems like an OK compromise between never
174             # catching anything and always thrashing through the directories.
175             if($PDLLIB_CT != scalar(@PDLLIB)) {
176             @PDLLIB_EXPANDED = PDL::AutoLoader::expand_path(@PDLLIB);
177             $PDLLIB_CT = scalar(@PDLLIB);
178             }
179              
180             print "Loading $func.pdl ..." if $PDL::verbose;
181             my $file;
182              
183             my $s = "PDL AutoLoader: Undefined subroutine $func() cannot be autoloaded.\n";
184              
185             for my $dir (@PDLLIB_EXPANDED) {
186             $file = $dir . "/" . "$func.pdl";
187             if (-e $file) {
188            
189             print "found $file\n" if $PDL::verbose;
190              
191             PDL::AutoLoader::autoloader_do($file);
192            
193            
194             # Remember autoloaded functions and do some reasonably
195             # smart cacheing of file/directory change times
196            
197             if ($PDL::AutoLoader::Rescan) {
198             $PDL::AutoLoader::FileInfo{$func} = [ $file, (stat($file))[9] ];
199             }
200            
201             # Now go to the autoload function
202             ##goto &$AUTOLOAD(@args) unless ($@ || !defined(&{$AUTOLOAD}));
203             return &$AUTOLOAD(@args) unless ($@ || !defined(&{$AUTOLOAD}));
204              
205             die $s."\tWhile parsing file `$file':\n$@\n" if($@);
206             die $s."\tFile `$file' doesn't \n\tdefine ${AUTOLOAD}().\n"
207             }
208             }
209              
210             die $s."\tNo file `$func.pdl' was found in your \@PDLLIB path.\n";
211             }
212              
213             EOD
214              
215 1 50 33 1   8 eval $toeval;
  1 50   1   3  
  1 50   1   31  
  1 50   1   4  
  1 50       1  
  1 50       37  
  1 0       4  
  1 50       11  
  1         9  
  1         86  
  1         41  
  1         2  
  1         4  
  1         3  
  1         3  
  1         3  
  1         2  
  1         16  
  1         3  
  1         2  
  1         1  
  1         2  
  1         2  
  1         26  
  1         3  
  1         3  
  1         3  
  0         0  
  1         5  
  1         16  
  0         0  
  0         0  
  0         0  
216              
217             }
218              
219              
220             # Simple 'do' doesn't work with preprocessing -- this replaces
221             # "do file" and sticks NiceSlice in manually if it's needed (yuck).
222              
223             sub PDL::AutoLoader::autoloader_do {
224 1     1 0 2 my ($file) = shift;
225 1 50       3 if(defined($PDL::NiceSlice::VERSION)) {
226 1 50       2 print "AutoLoader: NiceSlice enabled...\n" if($PDL::debug);
227 1 50       32 return if !open my $fh ,"<", $file;
228 1         50 my $text = join "", <$fh>;
229 1         8 my $script = PDL::NiceSlice::perldlpp("PDL::NiceSlice", $text);
230 1     1   6 eval $script;
  1     1   1  
  1         6  
  1         65  
  1         2  
  1         2  
  1         4  
231             } else {
232 0 0       0 print "AutoLoader: no NiceSlice...\n" if($PDL::debug);
233 0         0 do $file;
234             }
235             }
236              
237              
238             # Expand directories recursively...
239             sub PDL::AutoLoader::expand_dir {
240 0     0 0 0 my $dir = shift;
241 0 0       0 return undef if !-d $dir;
242 0         0 opendir my($dh), $dir;
243 0   0     0 ($dir, map PDL::AutoLoader::expand_dir($_),
244             grep +(!m/^\./ && ($_="$dir/$_") && (-d $_)), readdir $dh);
245             }
246              
247              
248             =head2 PDL::AutoLoader::expand_path
249              
250             =for ref
251              
252             Expand a compactified path into a dir list
253              
254             You supply a pathlist and leading '+' and '~' characters get expanded into
255             full directories. Normally you don't want to use this -- it's internal to the
256             autoloader -- but some utilities, like the online documentation searcher, need
257             to be able to use it.
258              
259             =cut
260              
261             sub PDL::AutoLoader::expand_path {
262 2     2 1 649 my @PDLLIB = @_;
263 2         2 my @PDLLIB_EXPANDED;
264            
265 2 50       5 print "AutoLoader: Expanding directories from ".join(':',@PDLLIB)."...\n"
266             if($PDL::debug);
267 2         2 local $_;
268 2         5 foreach $_(@PDLLIB) {
269             # Expand ~{name} and ~ conventions.
270 2 100       19 if(s/^(\+?)\~(\+||[a-zA-Z0-9]*)//) {
271 1 50       6 if($2 eq '+') {
    50          
272             # Expand shell '+' to CWD.
273 0   0     0 $_= $1 . ($ENV{'PWD'} || '.');
274             } elsif(!$2) {
275             # No name mentioned -- use current user.
276             # Ideally would use File::HomeDir->my_home() here
277 1   33     5 $_ = $1 . ( $ENV{'HOME'} || (( getpwnam( getlogin || getpwuid($<) ))[7]) ) . $_;
278             } else {
279             # Name mentioned - try to get that user's home directory.
280 0         0 $_ = $1 . ( (getpwnam($2))[7] ) . $_;
281             }
282             }
283            
284             # If there's a leading '+', include all subdirs too.
285 2 50       7 push(@PDLLIB_EXPANDED,
286             s/^\+// ? PDL::AutoLoader::expand_dir($_) : $_
287             );
288             }
289              
290 2 50       3 print "AutoLoader: returning ",join(",",@PDLLIB_EXPANDED),"\n" if($PDL::debug);
291 2         19 @PDLLIB_EXPANDED;
292             }
293              
294              
295             ;# Exit with OK status
296              
297             1;