File Coverage

blib/lib/Aion.pm
Criterion Covered Total %
statement 685 842 81.3
branch 166 304 54.6
condition 43 117 36.7
subroutine 120 121 99.1
pod 9 27 33.3
total 1023 1411 72.5


line stmt bran cond sub pod time code
1             package Aion;
2              
3 4     4   139311 use common::sense;
  4         6  
  4         21  
4              
5             our $VERSION = "2.2";
6              
7 4     4   1229 use Aion::Types qw//;
  4         10  
  4         103  
8 4     4   1572 use Aion::Meta::RequiresAnyFunction;
  4         9  
  4         111  
9 4     4   1094 use Aion::Meta::Feature;
  4         10  
  4         117  
10 4     4   1436 use Aion::Meta::RequiresFeature;
  4         8  
  4         112  
11 4     4   998 use Aion::Meta::Subroutine;
  4         8  
  4         129  
12              
13             # Когда осуществлять проверки:
14             # ro - только при выдаче
15             # wo - только при установке
16             # rw - при выдаче и уcтановке
17             # no - никогда не проверять
18 4     4   1213 use Aion::Env AION_ISA => (default => 'rw');
  4         2974  
  4         22  
19              
20             sub export($@);
21              
22             # Классы в которых подключён Aion с метаинформацией
23             our %META;
24              
25             # Вызывается из другого пакета, для импорта данного
26             sub import {
27 57     57   6059 my (undef, $attr) = @_;
28 57         145 my $pkg = caller;
29              
30 57 50       546 *{"$pkg\::DOES"} = \&does if \&does != $pkg->can('DOES');
  57         184  
31              
32 57 100       141 if($attr ne '-role') { # Класс
33 49         113 export $pkg, qw/extends/;
34 49         56 *{"${pkg}::new"} = \&initialize;
  49         147  
35             } else { # Роль
36 8         16 export $pkg, qw/requires req/;
37             }
38              
39 57         99 export $pkg, qw/with has aspect does exactly/;
40              
41             # Метаинформация
42 57         725 $META{$pkg} = {
43             order => scalar keys %META,
44             require => {},
45             feature => {},
46             subroutine => {},
47             aspect => {
48             is => \&is_aspect,
49             isa => \&isa_aspect,
50             coerce => \&coerce_aspect,
51             lazy => \&lazy_aspect,
52             default => \&default_aspect,
53             trigger => \&trigger_aspect,
54             release => \&release_aspect,
55             init_arg => \&init_arg_aspect,
56             accessor => \&accessor_aspect,
57             writer => \&writer_aspect,
58             reader => \&reader_aspect,
59             predicate => \&predicate_aspect,
60             clearer => \&clearer_aspect,
61             cleaner => \&cleaner_aspect,
62             eon => \&eon_aspect,
63             }
64             };
65              
66 4 50   4   42 eval "package $pkg; use Aion::Types; 1" or die;
  4     3   6  
  4     3   1294  
  3     1   15  
  3     1   6  
  3     1   1187  
  3     1   16  
  3     1   5  
  3     1   1127  
  1     1   5  
  1     1   1  
  1     1   336  
  1     1   5  
  1     1   1  
  1     1   385  
  1     1   5  
  1     1   2  
  1     1   286  
  1     1   5  
  1     1   2  
  1     1   308  
  1     1   4  
  1     1   1  
  1     1   274  
  1     1   5  
  1     1   3  
  1     1   294  
  1     1   5  
  1     1   2  
  1     1   315  
  1     1   5  
  1     1   1  
  1     1   286  
  1     1   5  
  1     1   1  
  1     1   333  
  1     1   5  
  1     1   1  
  1     1   306  
  1     1   5  
  1     1   1  
  1     1   313  
  1     1   5  
  1     1   2  
  1     1   288  
  1     1   5  
  1     1   2  
  1     1   299  
  1     1   5  
  1     1   1  
  1         288  
  1         5  
  1         2  
  1         281  
  1         5  
  1         1  
  1         321  
  1         5  
  1         1  
  1         307  
  1         6  
  1         2  
  1         293  
  1         5  
  1         1  
  1         295  
  1         5  
  1         1  
  1         304  
  1         5  
  1         2  
  1         293  
  1         5  
  1         1  
  1         281  
  1         5  
  1         2  
  1         274  
  1         5  
  1         1  
  1         284  
  1         5  
  1         2  
  1         287  
  1         5  
  1         2  
  1         538  
  1         6  
  1         1  
  1         284  
  1         5  
  1         2  
  1         325  
  1         5  
  1         1  
  1         300  
  1         4  
  1         2  
  1         296  
  1         5  
  1         1  
  1         289  
  1         5  
  1         2  
  1         312  
  1         5  
  1         1  
  1         302  
  1         5  
  1         1  
  1         271  
  1         5  
  1         2  
  1         306  
  1         5  
  1         2  
  1         297  
  1         5  
  1         1  
  1         287  
  1         8  
  1         3  
  1         298  
  1         5  
  1         1  
  1         309  
  1         5  
  1         2  
  1         315  
  1         6  
  1         1  
  1         298  
  1         4  
  1         2  
  1         292  
  1         6  
  1         1  
  1         322  
  1         6  
  1         2  
  1         297  
  1         6  
  1         2  
  1         429  
  1         5  
  1         2  
  1         306  
  1         5  
  1         2  
  1         330  
  57         5273  
67             }
68              
69             # Удаляет добавленные символы
70             sub unimport {
71 0     0   0 my $pkg = caller;
72            
73 0         0 undef &{"${pkg}::$_"} for qw/extends with aspect requires req/;
  0         0  
74            
75 0 0       0 eval "package $pkg; no Aion::Types; 1" or die;
76             }
77              
78             # Экспортирует функции в пакет, если их там ещё нет
79             sub export($@) {
80 114     114 0 130 my $pkg = shift;
81 114         149 for my $sub (@_) {
82 350         916 my $can = $pkg->can($sub);
83 350 50 33     476 die "$pkg can $sub!" if $can && $can != \&$sub;
84 350 50       546 *{"${pkg}::$sub"} = \&$sub unless $can;
  350         603  
85             }
86             }
87              
88             # Проверяет, что этот пакет инициализирован Aion
89             sub is_aion($) {
90 118     118 0 144 my $pkg = shift;
91 118 50       291 die "$pkg is'nt class of Aion!" if !exists $META{$pkg};
92             }
93              
94             #@category Aspects
95              
96             # ro, rw, + и -, *
97             sub is_aspect {
98 36     36 0 57 my ($is, $feature) = @_;
99 36 50       209 die "Use is => '{ro|rw|wo|no} {+|-} {*} {?} {!}'" if $is !~ /^(?ro|rw|wo|no)?(?[+-])?(?\*)?(?\??)(?!?)\z/;
100              
101 36         72 my ($construct, $name) = @$feature{qw/construct name/};
102              
103 36 100       341 $construct->getter("die 'Feature $name cannot be get!';") if $+{access} ~~ [qw/wo no/];
104              
105 36 100       492 $construct->setter("die 'Feature $name cannot be set!';") if $+{access} ~~ [qw/ro no/];
106              
107 36 100       120 $construct->add_trigger("%(weaken)s") if $+{weak};
108              
109 36 100       217 $feature->{required} = 1, $construct->not_specified(' else { die "%(init_arg)s required!" }') if $+{require} eq '+';
110            
111 36 100       130 $feature->{excessive} = 1, $construct->initer('die "%(init_arg)s excessive!"') if $+{require} eq '-';
112              
113 36 100       103 $feature->{make_predicate} = 1 if $+{has};
114 36 100       171 $feature->{make_clearer} = 1 if $+{clear};
115             }
116              
117             # isa => Type
118             sub isa_aspect {
119 26     26 0 45 my ($isa, $feature) = @_;
120 26         44 my ($construct, $name) = @$feature{qw/construct name/};
121              
122 26         78 $feature->{isa} = Aion::Types::External[$isa];
123              
124 26 50       109 $construct->add_release("${\$feature->meta}\{isa}->validate(\$val, 'Get feature $name');") if AION_ISA =~ /ro|rw/;
  26         52  
125              
126 26 50       126 $construct->add_preset("${\$feature->meta}\{isa}->validate(\$val, 'Set feature $name');") if AION_ISA =~ /wo|rw/;
  26         59  
127             }
128              
129             # coerce => 1
130             sub coerce_aspect {
131 4     4 0 6 my ($coerce, $feature) = @_;
132              
133 4 50       8 return unless $coerce;
134              
135 4 50       14 die "coerce: isa not present!" unless $feature->{isa};
136              
137 4 50       32 $feature->{construct}->add_preset("\$val = ${\$feature->meta}\{isa}->coerce(\$val);", 1) if AION_ISA =~ /wo|rw/;
  4         10  
138             }
139              
140             my $pleroma;
141              
142             sub pleroma {
143 1     1   2434 require Aion::Pleroma;
144 1         6 $pleroma = Aion::Pleroma->new;
145 1     1   5 *pleroma = sub { $pleroma };
  1         483  
146 1         7 $pleroma
147             }
148              
149             # eon => $key
150             sub eon_aspect {
151 3     3 1 5 my ($key, $feature) = @_;
152              
153 3 50       9 die "eon is not compatible with default!" if $feature->{opt}{default};
154              
155 3 100       9 if($key eq 1) {
    100          
156 1         3 my $isa = $feature->{isa};
157 1 50 33     3 $key = $isa && $isa->{name} eq "Object" && $isa->{args}[0]
158             or die "use: has $feature->{name} => (isa => Object[...], eon => 1)";
159             }
160             elsif($key eq 2) {
161 1         2 my $isa = $feature->{isa};
162 1   50     3 $key = ($isa && $isa->{name} eq "Object" && $isa->{args}[0]
163             or die "use: has $feature->{name} => (isa => Object[...], eon => 2)")
164             . "#$feature->{name}";
165            
166             }
167              
168 3     3   38 default_aspect(sub { Aion->pleroma->resolve($key) }, $feature);
  3         10  
169             }
170              
171             # lazy => 1|0
172             sub lazy_aspect {
173 4     4 0 7 my ($lazy, $feature) = @_;
174              
175 4         12 $feature->{lazy} = $lazy;
176             }
177              
178             # default => value
179             sub default_aspect {
180 17     17 0 27 my ($default, $feature) = @_;
181              
182 17         262 my $name = $feature->name;
183 17         29 my $default_is_code = ref $default eq "CODE";
184              
185 17 100       31 if($default_is_code) {
186 9         21 $feature->{builder} = $default;
187             } else {
188 8         16 $feature->{default} = $default;
189 8 100       25 $feature->{isa}->validate($default, $name) if $feature->{isa};
190             }
191              
192 17 100 100     82 if($feature->{opt}{lazy} // $default_is_code) {
193 7         14 $feature->{lazy} = 1;
194              
195 7 100       17 if ($default_is_code) {
196 6         105 $feature->construct->add_access("unless(%(has)s) {
197 6         16 my \$val = ${\$feature->meta}\{builder}->(\$self);
198             %(write)s
199             }");
200             } else {
201 1         13 $feature->construct->add_access("unless(%(has)s) {
202 1         2 my \$val = ${\$feature->meta}\{default};
203             %(write)s
204             }");
205             }
206             } else {
207 10 100       37 if($default_is_code) {
208 3         7 $feature->{construct}->not_specified(" else {
209 3         7 my \$val = ${\$feature->meta}\{builder}->(\$self);
210             %(write)s
211             }");
212             } else {
213 7         14 $feature->{construct}->not_specified(" else {
214 7         19 my \$val = ${\$feature->meta}\{default};
215             %(write)s
216             }");
217             }
218            
219             }
220             }
221              
222             # trigger => $sub
223             sub trigger_aspect {
224 1     1 0 3 my ($trigger, $feature) = @_;
225              
226 1         2 $feature->{trigger} = $trigger;
227              
228 1         2 my $construct = $feature->{construct};
229              
230 1         4 $construct->add_preset("my \@old = %(has)s? %(get)s: ();");
231 1         2 $construct->add_trigger("${\$feature->meta}\{trigger}->(\$self, \@old);");
  1         3  
232             }
233              
234             # release => $sub
235             sub release_aspect {
236 1     1 0 2 my ($release, $feature) = @_;
237              
238 1         3 $feature->{release} = $release;
239              
240 1         1 $feature->{construct}->add_release("${\$feature->meta}\{release}->(\$self, \$val);");
  1         3  
241             }
242              
243             # init_arg => $name
244             sub init_arg_aspect {
245 1     1 0 3 my ($init_arg, $feature) = @_;
246              
247 1         13 $feature->construct->init_arg($init_arg);
248             }
249              
250             # accessor => $name
251             sub accessor_aspect {
252 1     1 0 3 my ($accessor, $feature) = @_;
253              
254 1         16 $feature->construct->accessor_name($accessor);
255             }
256              
257             # writer => $name
258             sub writer_aspect {
259 1     1 0 2 my ($writer, $feature) = @_;
260              
261 1         3 $feature->{make_writer} = 1;
262 1         13 $feature->construct->writer_name($writer);
263             }
264              
265             # reader => $name
266             sub reader_aspect {
267 1     1 0 3 my ($reader, $feature) = @_;
268              
269 1         3 $feature->{make_reader} = 1;
270 1         13 $feature->construct->reader_name($reader);
271             }
272              
273             # predicate => $name
274             sub predicate_aspect {
275 1     1 0 2 my ($predicate, $feature) = @_;
276              
277 1         3 $feature->{make_predicate} = 1;
278 1         14 $feature->construct->predicate_name($predicate);
279             }
280              
281             # clearer => $name
282             sub clearer_aspect {
283 1     1 0 2 my ($clearer, $feature) = @_;
284              
285 1         3 $feature->{make_clearer} = 1;
286 1         16 $feature->construct->clearer_name($clearer);
287             }
288              
289             # cleaner => $sub
290             sub cleaner_aspect {
291 1     1 0 3 my ($cleaner, $feature) = @_;
292              
293 1         3 my ($cls, $construct) = @$feature{qw/pkg construct/};
294            
295 1         2 $feature->{cleaner} = $cleaner;
296              
297 1         3 $construct->add_cleaner("${\$feature->meta}\{cleaner}->(\$self);");
  1         3  
298             }
299              
300             # Расширяет класс или роль
301             sub inherits($$@) {
302 14     14 0 20 my $pkg = shift; my $is_with = shift;
  14         19  
303              
304 14         25 is_aion $pkg;
305              
306 14         24 my $FEATURE = $Aion::META{$pkg}{feature};
307 14         22 my $ASPECT = $Aion::META{$pkg}{aspect};
308 14   50     31 my $REQUIRE = $Aion::META{$pkg}{require} //= {};
309              
310             # Добавляем наследуемые свойства и атрибуты
311 14         22 for my $module (@_) {
312 16 100 50     245 eval "require $module" or die unless $module->can('with') || $module->can('new');
      66        
313              
314 16 50       45 if(my $meta = $Aion::META{$module}) {
315 16         25 %$FEATURE = (%$FEATURE, %{$meta->{feature}}) ;
  16         28  
316 16         61 %$ASPECT = (%$ASPECT, %{$meta->{aspect}});
  16         174  
317 16         41 %$REQUIRE = (%$REQUIRE, %{$meta->{require}});
  16         39  
318             }
319             }
320              
321 14 100       24 my $import_name = $is_with? 'import_with': 'import_extends';
322 14         21 for my $module (@_) {
323 16         59 my $import = $module->can($import_name);
324 16 100       31 $import->($module, $pkg) if $import;
325             }
326              
327 14         851 return;
328             }
329              
330             # Наследование классов
331             sub extends(@) {
332 3     3 1 5378 my $pkg = caller;
333              
334 3         9 is_aion $pkg;
335              
336 3         5 push @{"${pkg}::ISA"}, @_;
  3         59  
337 3         7 push @{$Aion::META{$pkg}{extends}}, @_;
  3         13  
338              
339 3         7 unshift @_, $pkg, 0;
340 3         10 goto &inherits;
341             }
342              
343             # Расширение ролями
344             sub with(@) {
345 11     11 1 5831 my $pkg = caller;
346              
347 11         42 is_aion $pkg;
348              
349 11         14 push @{"${pkg}::ISA"}, @_;
  11         133  
350 11         20 push @{$Aion::META{$pkg}{with}}, @_;
  11         32  
351              
352 11         20 unshift @_, $pkg, 1;
353 11         31 goto &inherits;
354             }
355              
356             sub requires(@) {
357 1     1 1 3622 my $pkg = caller;
358              
359 1         4 is_aion $pkg;
360              
361             #TODO: добавить проверку на существование
362 1         12 $Aion::META{$pkg}{require}{$_} = Aion::Meta::RequiresAnyFunction->new(pkg => $pkg, name => $_) for @_;
363             }
364              
365             # Требуется свойство
366             sub req(@) {
367 1     1 1 4 my ($name) = @_;
368 1         2 my $pkg = caller;
369              
370 1         4 is_aion $pkg;
371              
372 1         2 my $meta = $Aion::META{$pkg};
373              
374             #TODO: добавить проверку на существование по модулю и сравнить, что не одинаковы, если модули не совпадают
375             # die "Feature `$name` already required!" if exists $meta->{require}{$name};
376              
377 1         9 $meta->{require}{$name} = Aion::Meta::RequiresFeature->new($pkg, @_);
378 1         2 return;
379             }
380              
381             # Добавляется аспект
382             sub aspect($$) {
383 2     2 1 3351 my ($name, $sub) = @_;
384 2         5 my $pkg = caller;
385              
386 2         6 is_aion $pkg;
387              
388 2         3 my $ASPECT = $Aion::META{$pkg}{aspect};
389 2 50       6 die "Aspect `$name` exists!" if exists $ASPECT->{$name};
390 2         4 $ASPECT->{$name} = $sub;
391 2         3 return;
392             }
393              
394             # Ищет именно классы, а не роли
395             sub exactly {
396 7     7 1 2531 my ($self, $class) = @_;
397 7 100       158 return '' if Aion::Types::ClassName->exclude($class);
398 6         22 goto &UNIVERSAL::isa;
399             }
400              
401              
402             # Определяет - подключена ли роль
403             sub does {
404 6     6 1 2112 my ($self, $role) = @_;
405 6 100       133 return '' if Aion::Types::ClassName->include($role);
406 5         21 goto &UNIVERSAL::isa;
407             }
408              
409             # Создаёт свойство
410             sub has(@) {
411 47     47 1 36917 my $property = shift;
412              
413 47         80 my $pkg = caller;
414 47         115 is_aion $pkg;
415              
416 47         160 my %opt = @_;
417 47         72 my $meta = $Aion::META{$pkg};
418              
419             # создаём фичи
420 47 100       116 for my $name (ref $property? @$property: $property) {
421              
422             die "has: the method $name is already in the package $pkg"
423 48 50 33     458 if $pkg->can($name) && !exists $meta->{feature}{$name};
424              
425 48         224 my $feature = Aion::Meta::Feature->new($pkg, $name, @_);
426              
427 48         90 my $require = delete $meta->{require}{$name};
428 48 100       78 $require->compare($feature) if $require;
429              
430 48         62 my $overload = $meta->{feature}{$name};
431 48 50       61 $overload->compare($feature) if $overload;
432            
433 48         143 $feature->mk_property;
434 48         169 $meta->{feature}{$name} = $feature;
435             }
436 47         136 return;
437             }
438              
439             # Инициализатор: закрывает класс и заменяется на конструктор
440             sub initialize {
441 39     39 0 174411 my ($cls) = @_;
442              
443 39   33     147 $cls = ref $cls || $cls;
444 39         105 is_aion $cls;
445              
446 39         63 my $REQUIRE = $Aion::META{$cls}{require};
447 39         49 my $FEATURE = $Aion::META{$cls}{feature};
448 39         70 my $SUBROUTINE = $Aion::META{$cls}{subroutine};
449 39         100 for my $key (keys %$REQUIRE) {
450 6         11 my $require = $REQUIRE->{$key};
451            
452 6 100       46 if ($require->isa('Aion::Meta::RequiresAnyFunction')) {
    100          
453 2         19 $require->compare($cls->can($key));
454             } elsif ($require->isa('Aion::Meta::RequiresFeature')) {
455 1         21 $require->compare($FEATURE->{$require->name});
456             } else {
457 3         93 $require->compare($SUBROUTINE->{$require->subname});
458             }
459             }
460              
461 36         47 %$REQUIRE = ();
462              
463             # TODO: очищать класс от вспомогательных функций
464             #eval "package $cls; Aion->unimport; 1" or die;
465              
466 36         47 my $new = << 'END';
467             package %(cls)s {
468             sub new {
469             my ($cls, %value) = @_;
470             $cls = ref $cls || $cls;
471             my $self = bless {}, $cls;
472            
473             %(initializers)s
474            
475             if(scalar keys %value) {
476             my @fakekeys = sort keys %value;
477             die "@fakekeys is'nt feature!" if @fakekeys == 1;
478             local $" = ", ";
479             die "@fakekeys is'nt features!"
480             }
481              
482             return $self;
483             }
484             }
485             END
486              
487 36         41 my @destroyers;
488             my $initializers = join "", map {
489 47 100       96 push @destroyers, $_->{construct}->destroyer if $_->{cleaner};
490             $_->{construct}->initializer
491 36         134 } sort { $a->{order} <=> $b->{order} } values %$FEATURE;
  47         228  
  20         55  
492            
493 36         122 my %var = (
494             cls => $cls,
495             initializers => $initializers,
496             );
497            
498 36         165 $new =~ s/%\((\w+)\)s/$var{$1}/ge;
  72         273  
499              
500 36 100 33 6   11353 eval $new;
  6 0 33 7   596  
  6 50 33 8   29  
  6 100 33 1   12  
  6 0 33 2   16  
  4 50 33 2   7  
  4 50 33 1   41  
  4 50 33 9   17  
  3 50 33 1   13  
  5 50 33 2   15  
  0 50 33 1   0  
  0 50 33 2   0  
  1 50 33 1   16  
  7 0 33 1   549  
  12 50 33 1   158  
  7 100 33 1   14  
  7 0 33 1   22  
  5 50 33 1   11  
  5 50 33 1   21  
  5 0 33 1   15  
  2 50 33 1   8  
  4 100 33 1   8  
  0 100 33 1   0  
  0 100 33 1   0  
  3 0 33 1   54  
  0 50 33 6   0  
  4 50 33 1   49  
  8 0 33 1   23184  
  8 50 33 1   37  
  8 50 33 1   16  
  8 0 33 5   20  
  0 50       0  
  0 50       0  
  1 0       3  
  7 50       22  
  7 100       37  
  7 100       22  
  7 50       16  
  1 0       2  
  1 50       4  
  1 50       4  
  8 0       18  
  1 50       3  
  0 50       0  
  0 50       0  
  8 50       35  
  8 0       38  
  8 50       21  
  7 50       15  
  0 0       0  
  0 50       0  
  0 50       0  
  1 50       3  
  9 50       532  
  2 0       10  
  2 50       4  
  2 0       5  
  2 50       3  
  2 0       7  
  2 50       5  
  0 50       0  
  0 0       0  
  0 50       0  
  0 0       0  
  2 50       15  
  2 50       513  
  2 0       9  
  2 50       4  
  2 50       6  
  1 0       1  
  1 50       3  
  1 0       2  
  1 50       5  
  2 50       4  
  0 0       0  
  0 50       0  
  0 50       0  
  0 0       0  
  2 50       32  
  1 100       2  
  1 100       5  
  1 100       2  
  1 100       3  
  0 100       0  
  0 50       0  
  1 50       3  
  0 0       0  
  0 50       0  
  0 50       0  
  0 0       0  
  1 50       2  
  9 50       5452  
  9 50       75  
  9 0       24  
  9 50       26  
  2 50       6  
  2 0       6  
  9 50       24  
  8 100       16  
  8 100       44  
  1 100       10  
  8 0       22  
  1 50       10  
  7         20  
  0         0  
  0         0  
  0         0  
  0         0  
  7         250  
  1         3  
  1         4  
  1         2  
  1         4  
  0         0  
  0         0  
  0         0  
  1         3  
  1         4  
  1         6  
  1         3  
  0         0  
  0         0  
  0         0  
  0         0  
  1         30  
  2         511  
  2         8  
  2         5  
  2         6  
  2         2  
  2         11  
  2         7  
  2         6  
  2         4  
  0         0  
  0         0  
  0         0  
  0         0  
  2         28  
  1         4  
  1         5  
  1         2  
  1         3  
  1         1  
  1         5  
  1         2  
  0         0  
  0         0  
  0         0  
  0         0  
  1         3  
  2         2945  
  2         9  
  2         4  
  2         7  
  1         2  
  1         9  
  1         4  
  1         3  
  1         5  
  1         5  
  2         7  
  1         3  
  1         5  
  1         3  
  2         6  
  0         0  
  0         0  
  0         0  
  2         10  
  2         6  
  2         5  
  2         5  
  0         0  
  0         0  
  0         0  
  0         0  
  2         6  
  1         2  
  1         5  
  1         2  
  1         4  
  0         0  
  0         0  
  1         128  
  0         0  
  0         0  
  0         0  
  0         0  
  1         6  
  1         4  
  1         5  
  1         2  
  1         3  
  1         1  
  1         7  
  1         1  
  1         5  
  1         3  
  0         0  
  0         0  
  1         2  
  0         0  
  0         0  
  0         0  
  0         0  
  1         3  
  1         3  
  1         6  
  1         2  
  1         3  
  1         1  
  1         5  
  1         3  
  0         0  
  0         0  
  0         0  
  0         0  
  1         15  
  1         5  
  1         4  
  1         3  
  1         3  
  1         2  
  1         6  
  1         5  
  0         0  
  1         2  
  1         2  
  1         5  
  1         2  
  0         0  
  1         3  
  0         0  
  0         0  
  0         0  
  1         2  
  1         3  
  1         2  
  1         3  
  0         0  
  0         0  
  0         0  
  0         0  
  1         6  
  1         3  
  1         6  
  1         2  
  1         3  
  0         0  
  0         0  
  0         0  
  0         0  
  1         3  
  1         2  
  1         7  
  1         2  
  1         3  
  0         0  
  0         0  
  0         0  
  0         0  
  1         5  
  1         7  
  1         7  
  1         4  
  1         4  
  1         2  
  1         7  
  0         0  
  1         4  
  0         0  
  0         0  
  0         0  
  0         0  
  1         30  
  1         3  
  1         5  
  1         2  
  1         4  
  0         0  
  0         0  
  0         0  
  0         0  
  1         4  
  1         4  
  1         6  
  1         3  
  1         5  
  0         0  
  0         0  
  1         4  
  0         0  
  0         0  
  0         0  
  0         0  
  1         4  
  1         2  
  1         6  
  1         2  
  1         3  
  0         0  
  0         0  
  1         2  
  0         0  
  0         0  
  0         0  
  0         0  
  1         15  
  1         3  
  1         5  
  1         2  
  1         3  
  0         0  
  0         0  
  0         0  
  0         0  
  1         4  
  1         3  
  1         6  
  1         2  
  1         3  
  0         0  
  0         0  
  0         0  
  1         3  
  0         0  
  0         0  
  0         0  
  0         0  
  1         6  
  1         3  
  1         5  
  1         3  
  1         3  
  0         0  
  0         0  
  1         3  
  0         0  
  0         0  
  0         0  
  0         0  
  1         18  
  6         3611  
  6         23  
  6         11  
  6         13  
  1         2  
  1         6  
  1         2  
  6         11  
  5         7  
  5         27  
  5         12  
  1         36  
  5         9  
  1         6  
  4         8  
  2         7  
  2         10  
  1         1  
  1         8  
  2         5  
  1         4  
  1         5  
  1         2  
  1         4  
  1         2  
  1         6  
  1         4  
  0         0  
  1         3  
  0         0  
  1         2  
  1         2  
  1         4  
  1         5  
  0         0  
  0         0  
  0         0  
  0         0  
  1         4  
  1         4  
  1         4  
  1         3  
  1         2  
  0         0  
  0         0  
  0         0  
  1         3  
  0         0  
  0         0  
  0         0  
  0         0  
  1         18  
  1         5  
  1         5  
  1         2  
  1         3  
  1         2  
  1         5  
  1         12  
  1         3  
  1         2  
  1         3  
  1         2  
  1         179  
  0         0  
  0         0  
  0         0  
  0         0  
  1         5  
  1         3  
  1         5  
  1         3  
  1         3  
  0         0  
  0         0  
  1         2  
  0         0  
  0         0  
  0         0  
  0         0  
  1         3  
  5         3138  
  5         34  
  5         12  
  5         16  
  2         5  
  2         12  
  1         3  
  4         13  
  1         3  
  1         9  
  0         0  
  3         9  
  1         3  
  1         8  
  1         62  
  1         5  
  3         7  
  0         0  
  0         0  
  0         0  
  0         0  
  3         76  
501 36 50       190 die if $@;
502              
503 36 100       102 if (@destroyers) {
504 1         3 my $destroyer = << 'END';
505             package %(cls)s {
506             sub DESTROY {
507             my ($self) = @_;
508              
509             warn "${\ref $self}#${\Scalar::Util::id $self} destroy in global phase!" if ${^GLOBAL_PHASE} eq 'DESTRUCT';
510              
511             %(destroyers)s
512             }
513             }
514             END
515              
516 1         10 my %var = (
517             cls => $cls,
518             destroyers => join "", @destroyers,
519             );
520            
521 1         13 $destroyer =~ s/%\((\w+)\)s/$var{$1}/ge;
  2         16  
522              
523 1 50   2   297 eval $destroyer;
  2 50       422  
  2 100       7  
  0         0  
  0         0  
  2         6  
  1         1  
  1         4  
  1         5  
524 1 50       8 die $@ if $@;
525             }
526            
527 36         41 goto &{"${cls}::new"};
  36         673  
528             }
529              
530             1;
531              
532             __END__