[Kiev-pm] Данные из конфига считываются с позиции предыдущего обхода (mojolicious)

Maxim Vuets maxim.vuets at gmail.com
Sat Oct 27 14:30:10 PDT 2012


On Sat, Oct 27, 2012 at 11:48:24PM +0300, Виктор Турский wrote:
>Каждый хеш хранит в себе внутренний итератор. При обращении к хешу при
>помощи each - мы смещаем позицию на один элемент. Если мы доходим до
>конца хеша, то позиция сбрасывается.
>В данном случае мы до конца не доходим и состояние позиции сохраняется
>между вызовами.

Мне эта "особенность" и похожая ситуация стоила когда-то нескольких
часов полного недоумения. Был конфиг. файл вида:

    target_name => {
        foo         => 'bar',
        baz         => [qw(100 200 300)],
        quux        => {checkbox => 1},
    }

Мне нужно было вынести общий параметр quux в секцию DEFAULT.
В результате получился странный результат: на веб-странице состояние
этого checkbox-а для каждой секции чередовалось.

Оказалось, что автор кода для обработки конфига использовал each не по
назначению, а для мнимой красоты в коде:

    if (ref $param_val eq 'HASH') {
        my ($control, $value)= each %$val;
        ...
    }

Я сделал этот hashref общим для всех секций, как и его внутренний
each-итератор. Получилось, что в одном случае был нормальный результат
(флажок стоял), а в другом --- пустой список как признак окончания
итерации (флажок был сброшен).

>keys - сбрасывает итератор.
>Если добавить "keys %{ $self->config->{ test } }" перед циклом, то
>тесты пройдут. (но это далеко не лучшее решение)
...
>>   while ( my ( $key, $val ) = each %{ $self->config->{ test } } ) {
>>     if ( $test =~ $key ) {
>>         $test = $val;
>>         last;
>>     }
>>   }

Лучшим решением будет не использовать while+each и last. Вместо:

    my $config= $self->config->{test};
    for my $key (keys %$config) {
        my $val= $config->{$key};
        ...
    }

-- 
maxim.vuets.name


More information about the Kiev-pm mailing list