Anyone for metaprogramming?
What is metaprogramming? Well this question caused a heated discussion on Hacker News yesterday.
I personally would describe that metaprogramming provides the ability to:
transform programs with programs
and leave it at that!
The article that stirred the metaprogramming pot was Metaprogramming: Ruby vs. Javascript. This actually is a good post and it helped fill in a few holes in my “fragile” Javascript knowledge.
Luckily I believe my Perl is a bit less fragile!, so I thought I would convert the metaprogramming examples into Perl & Moose.
So following the blogs examples, below defines the Ninja class in Moose. MooseX::SingletonMethod loads Moose with a bit of singleton method sugar.
use Modern::Perl; { package Ninja; use MooseX::SingletonMethod; use namespace::clean -except => 'meta'; has name => ( is => 'rw', isa => 'Str' ); } my $drew = Ninja->new( name => 'Drew' ); my $adam = Ninja->new( name => 'Adam' );
NB. namespace::clean stops the Moose sugar percolating into Ninja class (except meta… which is the Meta Object Protocol method… which handy for metaprogramming!).
Now we re-open the Ninja class and add battle_cry
method like so:
{ package Ninja; sub battle_cry { my $self = shift; say $self->name . ' says zing!!!'; } } $drew->battle_cry; # => Drew says zing!!! $adam->battle_cry; # => Adam says zing!!!
Now using MooseX::SingletonMethod we add throw_star
singleton method into $drew object:
$drew->add_singleton_method( throw_star => sub { say "throwing star"; }); $drew->throw_star; # => throwing a star
To call method dynamically we do this:
$drew->${ \'battle_cry' }; # => Drew says zing!!!
Create colour
method closing over $colour_name (ie. closure):
my $colour_name = 'black'; Ninja->meta->add_method( colour => sub { my $self = shift; say "${ \$self->name }'s colour is $colour_name"; }); $drew->colour; # => Drew's colour is black $adam->colour; # => Adam's colour is black
Finally… “defining a method dynamically on an instance that closes over local scope and accesses the instance’s state”
my $sword_symbol = '********'; $drew->add_singleton_method( swing => sub { my ($self, $sound_effect) = @_; say "${ \$self->name }: $sword_symbol $sound_effect"; }); $drew->swing( 'slash!!' ); # => Drew: ********* slash!!
Everything nicely works the same as the Ruby & Javascript blog examples.
To round things off, below is the complete example but with MooseX::Declare sugar stirred into the pot.
use Modern::Perl; use MooseX::Declare; class Ninja with MooseX::SingletonMethod::Role is mutable { has name => ( is => 'rw', isa => 'Str' ); } my $drew = Ninja->new( name => 'Drew' ); my $adam = Ninja->new( name => 'Adam' ); ########################################################### class Ninja is mutable { method battle_cry { say $self->name . ' says zing!!!'; } } $drew->battle_cry; # => Drew says zing!!! $adam->battle_cry; # => Adam says zing!!! ########################################################### $drew->add_singleton_method( throw_star => sub { say "throwing star"; }); $drew->throw_star; # => throwing a star ########################################################### $drew->${ \'battle_cry' }; # => Drew says zing!!! ########################################################### my $colour_name = 'black'; Ninja->meta->add_method( colour => sub { my $self = shift; say "${ \$self->name }'s colour is $colour_name"; }); $drew->colour; # => Drew's colour is black $adam->colour; # => Adam's colour is black ########################################################### my $sword_symbol = '********'; $drew->add_singleton_method( swing => sub { my ($self, $sound_effect) = @_; say "${ \$self->name }: $sword_symbol $sound_effect"; }); $drew->swing( 'slash!!' ); # => Drew: ********* slash!!
/I3az/
PS. If you want Moose in Javascript then have a look at Joose
Trackbacks