Creating recursive pattern blocks in Mojolicious
I would like to create a recursive block of templates in Mojolicious to create a complex menu from nested arrays.
Ideally, the array ["a", ["ba", "bb"], "c"]
would result in this nested list:
<ul>
<li>a</li>
<li>
<ul>
<li>ba</li>
<li>bb</li>
</ul>
</li>
<li>c</li>
</ul>
The following code doesn't work because blocks are anonymous subroutines and cannot use a reference for themselves:
% my $block = begin
% my $menu = shift;
<ul>
% foreach my $item (@{$menu}){
% if(ref($item) eq 'ARRAY') {
<li>
%= $block->($item);
</li>
% } else {
<li><%= $item %></li>
% }
% }
</ul>
% end
%= $block->( ["a", ["ba", "bb"], "c"] )
source to share
To use a variable in an expression, you need to declare that variable before the expression. So this will work:
% my $block; $block = begin
But it will leak memory because $ block is now a circular reference that perl cannot delete when it goes out of scope. Since perl 5.16, you can use the __SUB__ keyword inside the anonymous sub to get a reference to that subroutine. This way it will be as easy as
% use v5.16;
% my $block = begin
...
__SUB__->($item)
...
% end
And if you want to run your code on perl <5.16 you can use an alternative way to avoid memory leak. Just don't use a closure and instead pass the block reference as an argument
% my $block = begin
% my ($block, $menu) = @_;
...
%= $block->($block, $item);
...
% end
%= $block->( $block, ["a", ["ba", "bb"], "c"] )
source to share