Skip to content

Instantly share code, notes, and snippets.

@jberger
Last active December 13, 2015 21:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jberger/4975132 to your computer and use it in GitHub Desktop.
Save jberger/4975132 to your computer and use it in GitHub Desktop.
beginnings of a closure based MOP
use strict;
use warnings;
package ClosureClass::Meta;
use mro;
sub new {
my $class = shift;
my $package = shift;
my $self = { package => $package };
return bless $self, $class;
}
sub get_linear_isa {
my $self = shift;
return @{ mro::get_linear_isa( $self->{package} ) };
}
sub add_method {
my $self = shift;
my $name = shift;
$self->{methods}{$name} = shift;
}
sub get_method {
my $self = shift;
my $name = shift;
return $self->{methods}{$name};
}
sub make_immutable {
my $self = shift;
$self->{immutable} = 1;
}
package ClosureClass;
sub new {
my $class = shift;
my $meta = ClosureClass::Meta->new($class);
my $args = ref $_[0] ? shift : { @_ };
my @isa = $meta->get_linear_isa;
foreach my $package (reverse @isa) {
my $init = $package->can('INITIALIZE') || next;
$meta->$init($args);
}
my $self = sub {
unless (@_) {
return $meta->{immutable} ? undef : $meta;
}
my $name = shift;
my $method = $meta->get_method( $name );
return $method;
#TODO invoke when given args
#return $method unless @_;
#die "Cannot find method $name" unless $method;
};
return bless $self, $class;
}
sub AUTOLOAD {
my $name = (split /::/, our $AUTOLOAD)[-1];
my $method = $_[0]->($name) || die "Cannot find method $name\n";
goto $method;
}
sub DESTROY {}
package Person;
our @ISA = 'ClosureClass';
sub INITIALIZE {
my ($meta, $args) = @_;
my $secret = 'Secret';
$meta->add_method( hi => sub { print "Hello world\n" } );
$meta->add_method( secret => sub { print "$secret\n" } );
}
package main;
my $person = Person->new;
$person->hi;
$person->secret;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment