Class-Closure

 view release on metacpan or  search on metacpan

lib/Class/Closure.pm  view on Meta::CPAN

			push @subisa, $pkg;
			$subobj{ $pkg } = $var;

			return;
		};

		_install can => sub {
			my ( $self, $method ) = @_;

			my $code = do { no strict 'refs'; *{ "$package\::$method" }{'CODE'} };
			return $code if $code;

			for my $pkg ( @subisa ) {
				my $obj = $subobj{ $pkg };
				$code = $pkg->can( $method ) or next;
				my $delegate = sub {
					splice @_, 0, 1, $obj;
					goto &$code;
				};
				{ no strict 'refs'; *{ "$package\::$method" } = $delegate };
				return $delegate;
			}

			return;
		};

		_install AUTOLOAD => sub {
			our $AUTOLOAD =~ s/.*:://;
			if ( my $code = $_[0]->can( $AUTOLOAD ) ) {
				goto &$code;
			}
			elsif ( my $fallback = $_[0]->can( 'FALLBACK' ) ) {
				no strict 'refs';
				local *{ "$base\::AUTOLOAD" } = \$AUTOLOAD;
				goto &$fallback;
			}
			else {
				Carp::croak "Method $AUTOLOAD not found in class $base";
			}
		};

		$pkg->can( 'CLASS' )->( @_ );

		my $self = bless {}, $PACKAGE;

		$self->BUILD( @_[ 1 .. $#_ ] ) if $self->can( 'BUILD' );

		$self;
	};
}

{
my $counter = 0;
sub _make_package {
	"Class::Closure::_package_" . $counter++;
}
}

sub _find_name {
	my ( $var, $code ) = @_;
	require PadWalker;
	my %names = reverse %{ PadWalker::peek_sub( $code ) };
	my $name = $names{ $var } || Carp::croak "Couldn't find lexical name for $var";
	$name =~ s/^[\$\@%]//;
	$name;
}

sub has (\$) : lvalue {
	my ( $var ) = @_;

	require Devel::Caller;
	my $name = _find_name $var, Devel::Caller::caller_cv(1);

	_install $name, sub { $$var };
	$$var;
}

sub public (\$) : lvalue {
	my ( $var ) = @_;

	require Devel::Caller;
	my $name = _find_name $var, Devel::Caller::caller_cv(1);

	_install $name, sub : lvalue { $$var };
	$$var;
}

sub method ($&) {
	&_install;
	return;
}

sub accessor ($@) {
	my ( $name, %arg ) = @_;
	Carp::croak "accessor needs 'get' and 'set' attributes" unless $arg{'get'} && $arg{'set'};
	require Sentinel;
	_install $name, sub : lvalue {
		my $self = shift;
		Sentinel::sentinel(
			get => sub { $arg{'get'}->( $self ) },
			set => sub { $arg{'set'}->( $self, @_ ) },
		);
	};
	return;
}

sub extends($) { &$EXTENDS }

sub destroy(&) { _install DESTROY => \Class::Closure::DestroyDelegate->new( $_[0] ) }

package Class::Closure::DestroyDelegate;
our $VERSION = '0.304';

sub new { bless $_[1] }
sub DESTROY { goto &{$_[0]} }

1;

__END__

=pod



( run in 2.158 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )