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"] )

      

+3


source to share


1 answer


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"] )

      

+8


source







All Articles