2014-10-08 2 views
2

Я хотел бы создать рекурсивный блок шаблонов в Mojolicious для создания сложных меню из вложенных массивов.Создание рекурсивных блоков шаблонов в Mojolicious

В идеале массив ["a", ["ba", "bb"], "c"] приведет этот вложенный список:

<ul> 
    <li>a</li> 
    <li> 
     <ul> 
      <li>ba</li> 
      <li>bb</li> 
     </ul> 
    </li> 
    <li>c</li> 
</ul> 

Следующий код не работает, так как блоки анонимные подпрограмм и не может использовать ссылку на себя:

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

ответ

7

Для используйте переменную в выражении, которое нужно объявить этой переменной перед выражением. Таким образом, это будет работать:

% my $block; $block = begin

Но будет производить утечки памяти, потому что $ блок в настоящее время является циклическая ссылка, которая Perl не может удалить, когда он будет выходить за рамки. Поскольку perl 5.16 вы можете использовать ключевое слово __SUB__ внутри анонимного суб, чтобы получить ссылку на эту подпрограмму. Так что это будет так просто, как

% use v5.16; 
% my $block = begin 
    ... 
     __SUB__->($item) 
    ... 
% end 

И если вы хотите, чтобы запустить свой код на Perl < 5.16 вы можете использовать альтернативный способ, чтобы избежать утечки памяти. Только не используйте закрытие и вместо того, чтобы передать ссылку на блок в качестве аргумента

% my $block = begin 
    % my ($block, $menu) = @_; 
    ... 
     %= $block->($block, $item); 
    ... 
% end 
%= $block->($block, ["a", ["ba", "bb"], "c"]) 
+0

@ikegami, спасибо Я обновил мой ответ –

+0

Большое спасибо за отличное решение (ов) и отличное объяснение! – PJVolders

Смежные вопросы