I would like to create a recursive template block in Mojolicious to generate complex menu's 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 does not work since blocks are anonymous subroutines and cannot use a reference to 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"] )
To use variable in the expression you need to declare this variable before expression. So, this will work:
% my $block; $block = begin
But will produce a memory leak, because $block now is a circular reference, which perl can't delete when it'll go out of the scope. Since perl 5.16 you can use __SUB__ keyword inside anonymous sub to get reference to this subroutine. So this will be as simple 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 alternative way to avoid memory leak. Just don't use closure and instead pass reference to the block as argument
% my $block = begin
% my ($block, $menu) = @_;
...
%= $block->($block, $item);
...
% end
%= $block->( $block, ["a", ["ba", "bb"], "c"] )