File Coverage

blib/lib/Eobj.pm
Criterion Covered Total %
statement 99 220 45.0
branch 14 76 18.4
condition 0 3 0.0
subroutine 21 30 70.0
pod 0 10 0.0
total 134 339 39.5


line stmt bran cond sub pod time code
1             #
2             # This file is part of the Eobj project.
3             #
4             # Copyright (C) 2003, Eli Billauer
5             #
6             # This program is free software; you can redistribute it and/or modify
7             # it under the terms of the GNU General Public License as published by
8             # the Free Software Foundation; either version 2 of the License, or
9             # (at your option) any later version.
10             #
11             # This program is distributed in the hope that it will be useful,
12             # but WITHOUT ANY WARRANTY; without even the implied warranty of
13             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14             # GNU General Public License for more details.
15             #
16             # You should have received a copy of the GNU General Public License
17             # along with this program; if not, write to the Free Software
18             # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19             #
20             # A copy of the license can be found in a file named "licence.txt", at the
21             # root directory of this project.
22             #
23              
24 1     1   7180 use Eobj::PLerror;
  1         2  
  1         89  
25             package Eobj;
26              
27 1     1   5 use Eobj::PLerror;
  1         2  
  1         60  
28              
29 1     1   24 use 5.004;
  1         3  
  1         59  
30 1     1   5 use strict 'vars';
  1         3  
  1         25  
31 1     1   6 use warnings;
  1         2  
  1         167  
32              
33             require Exporter;
34              
35              
36             BEGIN {
37 1     1   3 @Eobj::warnings = ();
38 1         2 %Eobj::classes = ();
39             $SIG{__WARN__} = sub {
40 0         0 my ($class) = ($_[0] =~ /unquoted string.*?\"(.*?)\".*may clash/i);
41 0 0       0 if (defined $class) {
42 0         0 push @Eobj::warnings, $_[0];
43             } else {
44 0         0 warn ($_[0])
45             }
46 1         2479 };
47             }
48              
49             END {
50 1     1   9 $SIG{__WARN__} = sub {warn $_[0]; }; # Prevent an endless recursion
  0         0  
51 1         10 foreach (@Eobj::warnings) {
52 0         0 my ($class) = ($_ =~ /unquoted string.*?\"(.*?)\".*may clash/i);
53 0 0       0 warn ($_)
54             unless (defined $Eobj::classes{$class});
55             }
56              
57             # Now we destroy all objects in an orderly fashion...
58 1         7 foreach (sort { $b->get('eobj-object-count') <=> $a->get('eobj-object-count') }
  1         4  
59             values %Eobj::objects) {
60 2         12 $_->survivor();
61 2         11 $_->destroy();
62             }
63             }
64              
65             # We use explicit package names rather than Perl 5.6.0's "our", so
66             # perl 5.004 won't yell at us.
67              
68             @Eobj::ISA = qw[Exporter];
69             @Eobj::EXPORT = qw[&init &override &underride &inherit &inheritdir &definedclass &globalobj];
70             $Eobj::VERSION = '0.23';
71             $Eobj::STARTTIME = localtime();
72              
73             $Eobj::eobjflag = 0;
74             $Eobj::globalobject=();
75              
76             unless ($Eobj::eobjflag) {
77             $Eobj::eobjflag = 1; # Indicate that this clause has been run once
78             $Eobj::errorcrawl='system';
79             $Eobj::callbacksdepth = 0; # This indicates when callbacks are going on.
80             undef $Eobj::wrong_flag;
81              
82             #For unloaded classes: Value is [classfile, parent class, first-given classname].
83             %Eobj::classes = ('PL_hardroot', 1);
84             %Eobj::objects = ();
85             $Eobj::objectcounter = 0;
86            
87             {
88             my $home = $INC{'Eobj.pm'};
89             ($home) = ($home =~ /^(.*)Eobj\.pm$/);
90             blow("Failed to resolve Eobj.pm's directory")
91             unless (defined $home);
92             $Eobj::home = $home;
93             }
94              
95             $Eobj::classhome = "${Eobj::home}Eobj/";
96             inherit('root',"${Eobj::classhome}PLroot.pl",'PL_hardroot');
97             inherit('global',"${Eobj::classhome}PLglobal.pl",'root');
98             inherit('site_init',"${Eobj::classhome}site_init.pl",'PL_hardroot');
99             }
100              
101             sub init {
102 1     1 0 22 site_init -> init;
103             }
104             sub inherit {
105 4     4 0 90 my $class = shift;
106 4         6 my $file = shift;
107 4         5 my $papa = shift;
108              
109 4 50       11 puke("Attempt to create the already existing class \'$class\'\n")
110             if $Eobj::classes{$class};
111              
112 4 50       11 puke("No parent class defined for \'$class\'\n")
113             unless (defined $papa);
114 4         12 $Eobj::classes{$class} = [$file, $papa, $class];
115             # The following two lines are a Perl 5.8.0 bug workaround (early
116             # versions). Google "stash autoload" for why.
117 4         5 undef ${"${class}::Eobj_dummy_variable"};
  4         30  
118 4         4 undef ${"${class}::Eobj_dummy_variable"}; # No single use warning...
  4         9  
119 4         7 return 1;
120             }
121              
122             sub inheritdir {
123 0     0 0 0 my $dir = shift;
124 0         0 my $papa = shift;
125              
126 0         0 ($dir) = ($dir =~ /^(.*?)[\/\\]*$/); # Remove trailing slashes
127              
128 0 0       0 blow("Nonexistent directory \'$dir\'\n")
129             unless (-d $dir);
130              
131 0         0 do_inheritdir($dir, $papa);
132 0         0 return 1;
133             }
134              
135             sub do_inheritdir {
136 0     0 0 0 my $dir = shift;
137 0         0 my $papa = shift;
138              
139 0         0 ($dir) = ($dir =~ /^(.*?)[\/\\]*$/); # Remove trailing slashes
140              
141 0 0       0 return unless (opendir(DIR,$dir));
142 0         0 my @files=sort readdir(DIR);
143 0         0 closedir(DIR);
144 0         0 my @dirs = ();
145 0         0 my %newclasses = ();
146              
147 0         0 foreach my $file (@files) {
148 0 0 0     0 next if (($file eq '.') || ($file eq '..'));
149 0         0 my $thefile = $dir.'/'.$file;
150              
151 0 0       0 if (-d $thefile) {
152 0 0       0 next unless ($file =~ /^[a-zA-Z][a-zA-Z0-9_]*$/);
153 0         0 push @dirs, $file, $thefile;
154             } else {
155 0         0 my ($class) = ($file =~ /^([a-zA-Z][a-zA-Z0-9_]*)\.pl$/i);
156 0 0       0 next unless (defined $class);
157 0         0 $class = lc $class; # Lowercase the class
158 0 0       0 blow("inheritdir: Attempt to create the already existing class \'".$class.
159             "\' with \'$thefile\' (possibly symbolic link loop?)\n")
160             if ($Eobj::classes{$class});
161 0         0 inherit($class, $thefile, $papa);
162 0         0 $newclasses{$class} = 1;
163             }
164             }
165 0         0 while ($#dirs > 0) { # At least two entries...
166 0         0 my $newpapa = lc shift @dirs;
167 0         0 my $descend = shift @dirs;
168            
169 0 0       0 blow("inheritdir: Could not descend to directory \'$descend\' because there was no \'".
170             $newpapa.".pl\' file in directory \'$dir\'\n")
171             unless ($newclasses{$newpapa});
172 0         0 do_inheritdir($descend, $newpapa);
173             }
174             }
175              
176             sub override {
177 0     0 0 0 my $class = shift;
178 0         0 my $file = shift;
179 0         0 my $papa = shift;
180              
181 0 0       0 unless ($Eobj::classes{$class}) {
182 0 0       0 return inherit($class, $file, $papa)
183             if defined ($papa);
184 0         0 puke("Tried to override nonexisting class \'$class\', and no alternative parent given\n");
185             }
186              
187 0 0       0 puke("Attempt to override class \'$class\' after it has been loaded\n")
188             unless ref($Eobj::classes{$class});
189              
190             # Now create a new name for the previous class pointer
191              
192 0         0 my $newname=$class.'_PL_';
193 0         0 my $i=1;
194 0         0 while (defined $Eobj::classes{$newname.$i}) {$i++;}
  0         0  
195 0         0 $newname=$newname.$i;
196            
197             # This is the operation of overriding
198              
199 0         0 $Eobj::classes{$newname}=$Eobj::classes{$class};
200 0         0 $Eobj::classes{$class}=[$file, $newname, $class];
201              
202             # The following two lines are a Perl 5.8.0 bug workaround (early
203             # versions). Google "stash autoload" for why.
204 0         0 undef ${"${newname}::Eobj_dummy_variable"};
  0         0  
205 0         0 undef ${"${newname}::Eobj_dummy_variable"}; # No single use warning
  0         0  
206              
207 0         0 return 1;
208             }
209              
210             sub underride {
211 0     0 0 0 my $class = shift;
212 0         0 my $file = shift;
213              
214 0 0       0 unless ($Eobj::classes{$class}) {
215 0         0 puke("Tried to underride a nonexisting class \'$class\'\n");
216             }
217              
218 0 0       0 puke("Attempt to underride class \'$class\' after it has been loaded\n")
219             unless ref($Eobj::classes{$class});
220              
221             # Now create a new name for the previous class pointer
222              
223 0         0 my $newname=$class.'_PL_';
224 0         0 my $i=1;
225 0         0 while (defined $Eobj::classes{$newname.$i}) {$i++;}
  0         0  
226 0         0 $newname=$newname.$i;
227            
228 0         0 my $victim = $class;
229              
230             # Now we look for the grandfather
231 0         0 SEARCH: while (1) {
232 0         0 my $parent = ${$Eobj::classes{$victim}}[1];
  0         0  
233 0 0       0 if (${$Eobj::classes{$parent}}[2] ne $class) { # Same family?
  0         0  
234 0         0 last SEARCH;
235             } else {
236 0         0 $victim = $parent; # Climb up the family tree
237             }
238             }
239             # This is the operation of parenting
240              
241 0         0 $Eobj::classes{$newname}=[$file, ${$Eobj::classes{$victim}}[1], $class];
  0         0  
242 0         0 ${$Eobj::classes{$victim}}[1]=$newname;
  0         0  
243              
244             # The following two lines are a Perl 5.8.0 bug workaround (early
245             # versions). Google "stash autoload" for why.
246 0         0 undef ${"${newname}::Eobj_dummy_variable"};
  0         0  
247 0         0 undef ${"${newname}::Eobj_dummy_variable"}; # No single use warning.
  0         0  
248 0         0 return 1;
249             }
250              
251             #definedclass:
252             #0 - not defined, 1 - defined but not loaded, 2 - defined and loaded
253              
254             sub definedclass {
255 0     0 0 0 my $class = shift;
256 0         0 my $p = $Eobj::classes{$class};
257 0 0       0 return 0 unless (defined $p);
258 0 0       0 return 1 if ref($p);
259 0         0 return 2;
260             }
261              
262             sub classload {
263 7     7 0 11 my ($class, $schwonz) = @_;
264 7         11 my $p = $Eobj::classes{$class};
265 7         5 my $err;
266              
267 7 50       15 blow($schwonz."Attempt to use undeclared class \'$class\'\n")
268             unless (defined $p);
269              
270             # If $p isn't a reference, the class has been loaded.
271             # This trick allows recursive calls.
272 7 100       16 return 1 unless ref($p);
273              
274 4         7 $Eobj::classes{$class} = 1;
275              
276 4         5 my ($file, $papa, $original) = @{$p};
  4         11  
277              
278 4         82 classload($papa, $schwonz); # Make sure parents are loaded
279              
280             # Now we create the package wrapping
281              
282 4         12 my $d = "package $class; use strict 'vars'; use Eobj::PLerror;\n";
283 4         11 $d.='@'.$class."::ISA=qw[$papa];\n";
284              
285             # Registering MUST be the last line before the text itself,
286             # since the line number is recorded. Line count in error
287             # messages begin immediately after the line that registers.
288              
289 4         19 $d.="&Eobj::PLerror::register(\'$file\');\n# line 1 \"$file\"\n";
290              
291 4 50       197 open (CLASSFILE, $file) ||
292             blow($schwonz."Failed to open resource file \'$file\' for class \'$class\'\n");
293 4         447 $d.=join("",);
294 4         69 close CLASSFILE;
295 1     1   8 eval($d);
  1     1   2  
  1     1   41  
  1     1   5  
  1     1   2  
  1     1   228  
  1     1   6  
  1     1   1  
  1         21  
  1         4  
  1         1  
  1         4541  
  1         9  
  1         2  
  1         35  
  1         4  
  1         2  
  1         223  
  1         6  
  1         2  
  1         28  
  1         4  
  1         1  
  1         136  
  4         332  
296 4 50       22 blow ($schwonz."Failed to load class \'$original\':\n $@")
297             if ($@);
298             }
299              
300             sub globalobj {
301 0 0   0 0 0 return $Eobj::globalobject if (ref $Eobj::globalobject);
302 0         0 puke("Global object was requested before init() was executed\n");
303             }
304              
305             # This routine attempts to keep lines below 80 chrs/lines
306             sub linebreak {
307 0     0 0 0 my $data = shift;
308 0         0 my $extraindent = shift;
309              
310 0 0       0 $extraindent = '' unless (defined $extraindent);
311              
312 0         0 my @chunks = split("\n", $data);
313              
314 0         0 foreach (@chunks) {
315 0         0 my $realout = '';
316 0         0 while (1) { # Not forever. We'll break this in proper time
317 0 0       0 if (/^.{0,79}$/) { # The rest fits well...
318 0         0 $realout .= $_;
319 0         0 last;
320             }
321             # We try to break the line after a comma.
322 0         0 my ($x, $y) = (/^(.{50,78},)\s*(.*)$/);
323             # Didn't work? A whitespace is enough, then.
324 0 0       0 ($x, $y) = (/^(.{50,79})\s+(.*)$/)
325             unless (defined $x);
326             # Still didn't work? Break at first white space.
327 0 0       0 ($x, $y) = (/^(.{50,}?)\s+(.*)$/)
328             unless (defined $x);
329            
330             # THAT didn't work? Give up. Just dump it all out.
331 0 0       0 unless (defined $x) {
332 0         0 $realout .= $_;
333 0         0 last;
334             } else { # OK, we have a line split!
335 0         0 $realout .= $x."\n";
336 0         0 $_ = $extraindent.$y; # The rest, only indented.
337             }
338             }
339 0         0 $_ = $realout;
340             }
341 0         0 my $final = join("\n", @chunks);
342 0 0       0 $final .= "\n" if ($data =~ /\n$/);
343 0         0 return $final;
344             }
345              
346             # Just empty packages (used by PLroot).
347             package PL_hardroot;
348             package PL_settable;
349             package PL_const;
350             package PL_destroyed;
351 1     1   8 use Eobj::PLerror;
  1         2  
  1         219  
352             # Here we yell on all attempts to run a method on a destroyed
353             # object. Only calling destroy is OK...
354             $PL_destroyed::errorcrawl='system';
355              
356             sub destroy {
357 0     0   0 return undef;
358             }
359              
360             sub AUTOLOAD {
361 0     0   0 my $class = shift;
362 0         0 my $method = $PL_destroyed::AUTOLOAD;
363 0         0 my ($package) = $method =~ /^(.*?)::/;
364 0         0 $method =~ s/.*:://;
365              
366 0 0       0 return undef if ($method eq 'DESTROY');
367              
368 0         0 blow("Attempt to call method \'$method\' on a destroyed object\n");
369             }
370              
371             # And now the magic of autoloading.
372             package UNIVERSAL;
373 1     1   6 use Eobj::PLerror;
  1         3  
  1         426  
374             $UNIVERSAL::errorcrawl='skip';
375             %UNIVERSAL::blacklist=();
376              
377             sub AUTOLOAD {
378 5     5   24 my $class = shift;
379 5         6 my $method = $UNIVERSAL::AUTOLOAD;
380 5         16 my ($junk,$file,$line)=caller;
381 5         19 my $schwonz = "at $file line $line";
382 5 100       22 return undef if $method =~ /::SUPER::/;
383              
384 3         24 my ($package) = $method =~ /^(.*?)::/;
385 3         16 $method =~ s/.*:://;
386              
387 3         6 my $name = ref($class);
388              
389 3 50       9 return undef if ($method eq 'DESTROY');
390            
391 3 50       6 print "$class, $package\n" unless ($class eq $package);
392 3 50       10 puke("Undefined function/method \'$method\' $schwonz\n")
393             unless ($class eq $package);
394              
395 3 50       7 if ($name) {
396             # Forgive. This is not our class anyway...
397 0         0 return undef;
398             }
399              
400             # Now we protect ourselves against infinite recursion, should
401             # the classload call fail silently. This will happen if the
402             # first attempt to call a method in a class is to a
403             # method that isn't defined.
404 3 50       8 puke("Undefined method \'$method\' in class \'$class\' $schwonz\n")
405             if $UNIVERSAL::blacklist{$class};
406 3         5 $UNIVERSAL::blacklist{$class}=1;
407              
408 3         19 &Eobj::classload($class,
409             "While trying to load class \'$class\' due to call ".
410             "of method \'$method\' $schwonz:\n");
411            
412             #Just loaded the new class? Let's use it!
413 3         17 return $class->$method(@_);
414             }
415              
416             # Now have the "defineclass" subroutine defined, so we can use it to
417             # generate bareword warnings for anything but a class name.
418              
419              
420              
421             1; # Return true
422             __END__