Skip to content

Instantly share code, notes, and snippets.

@bbkr
Last active February 28, 2017 18:16
Show Gist options
  • Save bbkr/8728a26ef6ee12eaf4e91f8210318d88 to your computer and use it in GitHub Desktop.
Save bbkr/8728a26ef6ee12eaf4e91f8210318d88 to your computer and use it in GitHub Desktop.
Template engines
use v6;
my $template = q{
Hi [VARIABLE person]!
You can change your password by visiting [VARIABLE link] .
Best regards.
};
my %fields = (
'person' => 'John',
'link' => 'http://example.com'
);
sub substitutions ( $template is copy, %fields ) {
for %fields.kv -> $key, $value {
$template ~~ s:g/'[VARIABLE ' $key ']'/$value/;
}
return $template;
}
sub substitution ( $template is copy, %fields ) {
$template ~~ s:g/'[VARIABLE ' (\w+) ']'/{ %fields{$0} }/;
return $template;
}
grammar Grammar {
regex TOP { ^ [ <chunk=text> | <chunk=variable> ]* $}
regex text { <-[ [ ] >+ }
regex variable { '[VARIABLE ' $<name>=(\w+) ']' }
}
class ActionsDirect {
has %.fields is required;
method TOP ( $/ ) {
make [~]( map { .made }, $/{'chunk'} );
}
method text ( $/ ) {
make ~$/;
}
method variable ( $/ ) {
make %.fields{$/{'name'}};
}
}
sub grammar_actions_direct ( $template, %fields ) {
my $actions = ActionsDirect.new( fields => %fields );
return Grammar.parse($template, :$actions).made;
}
class ActionsClosure {
method TOP ( $/ ) {
my @chunks = $/{'chunk'};
make sub ( %fields ) {
return [~]( map { .made.( %fields ) }, @chunks );
};
}
method text ( $/ ) {
my $text = ~$/;
make sub ( %fields ) {
return $text;
};
}
method variable ( $/ ) {
my $name = $/{'name'};
make sub ( %fields ) {
return %fields{$name}
};
}
}
sub grammar_actions_closures ( $template, %fields ) {
state %cache{Str};
my $closure = %cache{$template} //= Grammar.parse(
$template, actions => ActionsClosure.new
).made;
return $closure( %fields );
}
class ActionsClosureParallel is ActionsClosure {
method TOP ( $/ ) {
my @chunks = $/{'chunk'};
make sub ( %fields ) {
return [~]( @chunks.hyper.map( {.made.( %fields ) } ).list );
};
}
}
sub grammar_actions_closures_parallel ( $template, %fields ) {
state %cache{Str};
my $closure = %cache{$template} //= Grammar.parse(
$template, actions => ActionsClosureParallel.new
).made;
return $closure( %fields );
}
use Bench;
my $template_short = $template;
my %fields_short = %fields;
my $template_long = join( ' lorem ipsum ', map( { '[VARIABLE ' ~ $_ ~ ']' }, 'a' .. 'z') ) x 100;
my %fields_long = ( 'a' .. 'z' ) Z=> ( 'lorem ipsum' xx * );
my $b = Bench.new;
$b.timethese(
1000,
{
'substitutions_short' => sub {
substitution( $template_short, %fields_short )
},
'substitutions_long' => sub {
substitution( $template_long, %fields_long )
},
'substitution_short' => sub {
substitution( $template_short, %fields_short )
},
'substitution_long' => sub {
substitution( $template_long, %fields_long )
},
'grammar_actions_direct_short' => sub {
grammar_actions_direct( $template_short, %fields_short )
},
'grammar_actions_direct_long' => sub {
grammar_actions_direct( $template_long, %fields_long )
},
'grammar_actions_closures_short' => sub {
grammar_actions_closures( $template_short, %fields_short )
},
'grammar_actions_closures_long' => sub {
grammar_actions_closures( $template_long, %fields_long )
},
'grammar_actions_closures_parallel_short' => sub {
grammar_actions_closures_parallel( $template_short, %fields_short )
},
'grammar_actions_closures_parallel_long' => sub {
grammar_actions_closures_parallel( $template_long, %fields_long )
}
}
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment