File Coverage

blib/lib/PDL/AutoLoader.pm
Criterion Covered Total %
statement 49 84 58.3
branch 19 50 38.0
condition 2 11 18.1
subroutine 7 9 77.7
pod 1 4 25.0
total 78 158 49.3


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