Как правильно рекурсировать через perl-хеш? - PullRequest
0 голосов
/ 05 января 2012

Я использую Config :: General для загрузки данных настройки для скрипта.Как часть этого, я бы хотел, чтобы скрипт выполнял поиск и замену значений в данных конфигурации.Поскольку значения могут быть вложены на несколько уровней вниз, кажется, что наилучшим подходом будет использование рекурсивной функции для выполнения подстановки.Я пришел к следующему, который, кажется, работает нормально:

#!/usr/bin/perl -w

use strict;
use Config::General;
use YAML::XS;

### Load in the config data and move it into the hash.
my $configObj = new Config::General(-ConfigFile => \*DATA);
my %config_hash = $configObj->getall;

### define the year to use as the replacement
my $current_year = (localtime())[5] + 1900;

### Call the function to update the data.
recursive_hash_replacement(\%config_hash, $current_year);


sub recursive_hash_replacement {

    ### Pull in the hash ref.
    my $tmp_hash_ref = shift;
    my $replacment_year = shift;


    ### Loop through all the keys in the hash ref.
    for my $tmp_hash_key (keys %{$tmp_hash_ref}) {

        ### If the value is another hash ref, call the function recursively.
        if(ref $tmp_hash_ref->{$tmp_hash_key} eq ref {}) {
            recursive_hash_replacement($tmp_hash_ref->{$tmp_hash_key}, $replacment_year);
        }

        ### otherwise, just update the value.
        else {
            $tmp_hash_ref->{$tmp_hash_key} =~ s{!YEAR!}{$replacment_year}g;
        }

    }
}


### Show the output with the updated values.
print Dump \%config_hash;


### Define the config data locally for testing.
__DATA__

key1 = /path/with/no/update
key2 = /path/with/new/!YEAR!/update

<level1>
    <level2>
        key3 = /another/!YEAR!/update
    </level2>
</level1>

Есть ли лучший способ сделать это?И, что еще более важно, есть ли какие-то ошибки, скрывающиеся в этом коде, которые ждут, чтобы укусить меня?

Ответы [ 2 ]

2 голосов
/ 06 января 2012

Вы можете упростить несколько вещей, работая со значениями хеша, а не с ключами.Вы также хотите проверить другие типы ссылок, потому что слепое выполнение регулярных выражений для других типов ссылок, вероятно, не будет делать то, что вы хотели.

sub recursive_hash_replacement {

    ### unpack multiple args with list assignment:
    my ($hash, $year) = @_;

    ### Loop through all the values in the hash ref.
    for my $value (values %$hash) {

        ### If the value is another hash ref, call the function recursively.
        if (ref $value) {
            if (ref $value eq 'HASH') {
                 recursive_hash_replacement($value, $year);
            }
            else {
                 # handle other reftypes, or skip them, or throw an error
                 die "non hash reference: $value"
            }
        }
        ### otherwise, just update the value.
        else {
            $value =~ s{!YEAR!}{$year}g;
        }

    }
}

Наконец, работа с strict хороша,работа с strict и warnings лучше, и будет ловить намного больше потенциальных ошибок.Наконец, иногда вы можете столкнуться с проблемами с синтаксисом косвенного объекта, поэтому используйте стандартные вызовы методов для конструкторов:

Config::General->new(-ConfigFile => \*DATA);

или, если вам нравится синтаксис косвенного объекта, сделайте его однозначным, добавив :: кконец имени пакета:

new Config::General:: -ConfigFile => \*DATA;
0 голосов
/ 06 января 2012

Стоит взглянуть на Data :: Visitor на CPAN. Это то, что Config :: JFDI использует за кулисами, чтобы сделать его замены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...