Mercurial > pub > Impl
view lib/IMPL/Object/_Base.pm @ 424:87af445663d7 ref20150831
IMPL::Object::_Base
author | cin |
---|---|
date | Tue, 03 Apr 2018 10:54:09 +0300 |
parents | 60c2892a577c |
children | c27434cdd611 |
line wrap: on
line source
package IMPL::Object::_Base; use strict; use warnings; use mro; sub __construct; sub __destroy; *__construct = _strap_ctor(__PACKAGE__); *__destroy = _strap_dtor(__PACKAGE__); sub DESTROY { shift->__destroy(); } sub _strap_ctor { my ($class, $ctor) = @_; no strict 'refs'; no warnings 'redefine'; return sub { my $self = ref shift; if ($self ne $class) { my $t = _get_ctor($self, undef, '@_'); *{"${self}::__construct"} = _strap_ctor($self, $t); goto &$t if $t; } else { goto &$ctor if $ctor; } }; } sub _strap_dtor { my ($class, $dtor) = @_; no strict 'refs'; no warnings 'redefine'; return sub { my $self = ref shift; if ($self ne $class) { my $t = _get_dtor($self); *{"${self}::__destroy"} = _strap_dtor($self, $t); goto &$t if $t; } else { goto &$dtor if $dtor; } }; } sub _get_ctor { my ($class, $prev, $t) = @_; no strict 'refs'; #say "_get_ctor($class, $prev, $t)"; my $isolate = ((not defined($t)) or ($t ne '@_')); my $ctor = $isolate ? *{"${class}::CTOR"}{CODE} : _chain_call(*{"${class}::CTOR"}{CODE}, $prev); foreach my $base (@{"${class}::ISA"}) { $ctor = _get_ctor($base, $ctor, exists ${"${class}::ISA"}{$base} ? ${"${class}::ISA"}{$base} : '@_'); } if ($isolate) { $ctor = _chain_call(_chain_params($ctor, $t), $prev); } return $ctor; } sub _get_dtor { my ($class, $prev) = @_; no strict 'refs'; my $dtor = _chain_call(*{"${class}::DTOR"}{CODE}, $prev); $dtor = _get_dtor($_, $dtor) foreach @{"${class}::ISA"}; return $dtor; } sub _chain_call { my ($method, $next) = @_; return $method unless $next; return $next unless $method; return sub { &$method(@_); goto &$next; } } sub _chain_params { my ($method, $prepare) = @_; return unless $method; if (not defined $prepare) { return sub { @_ = (shift); goto &$method }; } elsif ($prepare eq '@_') { return $method; } elsif (ref $prepare eq 'CODE') { return sub { @_ = (shift, &$prepare(@_)); goto &$method; } } } 1;