Skip to content

Instantly share code, notes, and snippets.

@japhb
Created November 14, 2013 20:11
Show Gist options
  • Save japhb/7473529 to your computer and use it in GitHub Desktop.
Save japhb/7473529 to your computer and use it in GitHub Desktop.
Using the Perl 6 metamodel to serialize class *definitions*.
use v6;
#= Composed into an Attribute subclass that can serialize attribute definitions to Perl source
role PerlableAttribute {
method traits_perl() {
my $traits = '';
$traits ~= ' is rw' if self.rw;
$traits ~= ' is box_target' if self.box_target;
$traits;
}
multi method perl(PerlableAttribute:) {
my $type = self.type.^name;
my $name = self.name;
$name .= subst('!', '.') if self.has_accessor;
my $traits = self.traits_perl;
"has $type $name$traits";
}
}
#= Composed into a ClassHOW subclass that can serialize class definitions to Perl source
role PerlableClass {
multi method perl(Mu $class) {
my $perl = "class $class.^name()";
$perl ~= " is $_.^name()" for $class.^parents;
$perl ~= " does $_.^name()" for $class.^roles;
$perl ~= " \{\n";
for $class.^attributes -> $attr {
my $attr_perl = $attr.perl;
if $class.defined {
my $value = $class."$attr.name.substr(2)"();
$attr_perl ~= " = $value.perl()";
}
$perl ~= " $attr_perl;\n";
}
$perl ~= "}\n";
$perl;
}
}
#= A metaclass for classes whose definition can be serialized into Perl source
class PerlableClassHOW is Metamodel::ClassHOW does PerlableClass { }
#= An extended Attribute type for Test::Message attributes
class Test::Metamodel::Attribute is Attribute does PerlableAttribute {
has Bool $.frobulated is rw;
method traits_perl() {
my $traits = callsame;
$traits ~= ' is frobulated' if $.frobulated;
}
}
# A test message
class Test::Message { }
my $name := 'FooBar::Test::BazQuux';
my $class := PerlableClassHOW.new_type(:$name);
$class.HOW.add_parent($class, Test::Message);
my $attr := Test::Metamodel::Attribute.new(:name<$!foo>, :type(Str), :package($class), :has_accessor);
$attr.set_rw;
$attr.frobulated = True;
$class.^add_attribute($attr);
$class.^compose;
say $class.^perl;
my $o = $class.new(foo => 'bar');
say $o.^perl;
$ perl6 metamodel-test.pl
class FooBar::Test::BazQuux is Test::Message {
has Str $.foo is frobulated;
}
class FooBar::Test::BazQuux is Test::Message {
has Str $.foo is frobulated = "bar";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment