2011-01-24 2 views
6

G'Day,Включая хеши в хэши в Perl

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

Для например, давайте посмотрим на некоторые небольшие хэшей

Файл personcontact.pl:

return { 
      \'firstname\' => { 
       \'__type\' => \'String\' 
      }, 
     \'lastname\' => { 
      \'__type\' => \'String\' 
      }, 
     %{include("/tmp/address.pl")} 
    } 

Файл address.pl:

return { 
     \'address\' => { 
     \'street\' => { 
      \'__type\' => \'String\' 
      }, 
     \'unit\' => { 
      \'__type\' => \'String\', 
      \'__validation_function\' => { 
       \'is_a_number\' => \'\' 
      }, 
      \'__schema_constraints\' => { 
       \'is_not_null\' => \'\' 
      } 
     }, 
     \'suburb\' => { 
      \'__type\' => \'String\' 
     }, 
     \'__type\' => \'ARRAY\' 
     } 
    } 

И у меня есть большое количество этих ...

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

sub include { 
my ($filename) = @_; 
my $file; 
open(my $fh, "<", $filename) or die ("FILEOPEN: $!"); 
while(my $line = <$fh>) { $file .= $line; } 
my $result = eval $file; 
die("EVAL: [email protected]") if [email protected]; 
close($fh) or die("FILECLOSE: $!"); 
return $result; 
} 

Я знаю, что я должен делать что-то неправильно, но я не уверен, что. Я продолжаю получать ошибки, такие как Useless use of a variable in void context at (eval 11) line 4, <SCHEMAFILE> line 6 или Odd number of elements in anonymous hash at (eval 11) line 5, <SCHEMAFILE> line 6. Я не уверен, как идти о поиске (eval 11) линии 4-3, строка 6, хотя. Любые предложения по использованию отладчиков Perl или любых указателей, где я мог бы ошибиться, будут высоко оценены.

Спасибо!

+2

Не нужно читать по строкам. Используйте «режим slurp», поместив 'local $ /;' перед чтением файла и измените 'while (my $ line ...)' на 'my $ line = <$fh>;'. – Mikel

+0

Спасибо за подсказку! Как вы могли догадаться, я довольно новичок в Perl :) –

+3

Возможно, что-то вроде YAML. http://search.cpan.org/dist/YAML/lib/YAML.pm – Mikel

ответ

11

Добро пожаловать на Perl. Надеюсь, вы хорошо учитесь и используете его.

В начало бизнеса, с чего начать? У меня есть много, чтобы сказать здесь.

Во-первых, неоправданно рискованно загружать данные путем оценки файлов. Если вы просто хотите сериализовать данные, попробуйте JSON::XS или YAML, или даже Storable. Если вы хотите создать файл конфигурации, в CPAN есть много и много модулей, которые помогают в решении этой задачи. Выезд Config::Any.

Если вы хотите создать структуры данных для загрузки через eval (что не очень хорошая идея), Data::Dumper генерирует код perl, необходимый для создания любых структур данных, которые вы ему кормите. Основная причина, о которой я упоминаю, заключается в том, что он гораздо полезнее в качестве вспомогательной отладки, чем сериализатор.

Теперь, когда что заботятся, если вы хотите загрузить файл и оценить его (опять же, не самая лучшая идея, почти в каждом случае), вы должны смотреть на do или require.

my $stuff = do 'address.pl'; 

Но не делайте этого. Строка eval - инструмент, который обычно лучше всего не использовать. 99% времени, если вы планируете использовать строку eval, остановитесь и подумайте о другом способе решения проблемы. Do - это неявная оценка, поэтому она тоже считается.

Perl дает вам множество инструментов для создания рискованной и мощной магии. Большая часть становления квалифицированным программированием на Perl заключается в понимании того, что вещи рискованны, почему и когда имеет смысл использовать их. Не ожидайте, что Perl поможет вам с забором и воротами, чтобы вы были в безопасности. Серьезно подумайте о получении копии Effective Perl Programming или Perl Best Practices. Как новичок, многое пойдет вам на голову, когда вы читаете в первый раз, но любая книга может стать отличной ссылкой, когда вы будете расти и учиться.

Следующая тема, что в мире вы пытаетесь достичь со всеми этими убедительными цитатами? Мне больно смотреть на это! Perl имеет some very, very nice quoting operators, который вы можете использовать, чтобы избежать необходимости возиться с кавычками в ваших литеральных строках.

=> или жирная запятая автоматически цитирует левую сторону (LHS), как если бы она была только буквенно-цифровой. Но все кавычки и убеждения делают вещи действительно изворотливыми.

Когда вы говорите \'address\' => {}, Perl видит это как \, оператор «get reference» применяется к строковому литералу. В этом случае - листинг без прерывания строки, потому что вы никогда не предлагаете unescaped ' после первого.

Если ваша цель состоит в том, чтобы использовать 'address', цитаты и все в качестве хэш-ключа, вы можете сделать это:

my %foo = ("'address'" => 'blah'); 

Если вы не хотите, котировки, которые, кажется гораздо более обычного варианта использования, просто выполните:

my %foo = (address => 'blah'); 

К сообщениям об ошибках, которые вы получали! У Perl есть несколько хороших сообщений об ошибках, когда вы узнаете, что все они означают. До тех пор это может быть немного сложно понять их значение. К счастью, Perl поставляется со сценарием под названием splain: удобный инструмент dandy, который будет объяснять сообщения об ошибках гораздо более подробно. Вы также можете использовать модуль diagnostics, чтобы автоматически получать одинаковые расширенные сообщения об ошибках.

Теперь, если я пишу это, я бы сделать что-то вдоль этих линий:

gen_schema_files.pl - файл для записи файлов схемы JSON. Вы можете отредактировать свои схемы, если хотите. Вы также можете настроить вывод, чтобы быть более красивым, если вы хотите улучшить читаемость.

#!/usr/bin/perl 

use JSON::XS; 
use File::Spec; 

use constant BASEDIR => '.'; 

# Key is the file name, value is the data to put into the file. 
my %schemata = (
    'address.json' => { 
     address => { 
      street => { __type => 'String' }, 
      unit => { 
       __type => 'String', 
       __validation_function => { is_a_number => '' }, 
       __schema_constraints => { is_not_null => '' } 
      }, 
      suburb => { __type => 'String' }, 
      __type => 'ARRAY' 
     }, 
    }, 

    'person_contact.json' => { 
     firstname => { __type => 'String' }, 
     lastname => { __type => 'String' }, 

     # Use a special key to indicate that additional files should be 
     # loaded into this hash. 
     INCLUDE => [qw(address.json)], 
    }, 

    # And so forth 
); 

for my $schema (keys %schemata) { 
    my $path = File::Spec->catfile(BASEDIR, $schema); 

    open my $fh, '>', $path 
     or die "Error opening '$path' for writing - $!\n"; 

    print $fh encode_json $schemata{$schema}; 
} 

load_schemas.pl - это код, который загружает схемы и делает вещи. Моя только загружается. Я понятия не имею, что вы делаете с данными ...

#!/usr/bin/perl 
use strict; 
use warnings; 

use Data::Dumper; 

use JSON::XS; 
use File::Spec; 

use constant BASEDIR => '.'; 


my $schema = load_schema('person_contact.json'); 

print Dumper $schema; 


sub load_schema { 
    my $file = shift; 

    my $path = File::Spec->catfile(BASEDIR, $file); 

    open my $fh, '<', $path 
     or die "Error opening file '$path' - $!\n"; 

    my $json = join '', <$fh>; # reads a list of lines and cats them into one string. 
           # One way to slurp out of many. 

    my $schema = decode_json($json); 

    # Handle the inclusion stuff: 

    if(exists $schema->{INCLUDE}) { 
     # Copy the files to load into an array. 
     my @loadme = @{$schema->{INCLUDE}}; 
     # delete the magic special include key. 
     delete $schema->{INCLUDE}; 

     # Load each file and copy it into the schema hash. 
     for my $load (@loadme) { 
      my $loaded = load_schema($load); 

      # This is a bit of weird syntax. 
      # We are using a hash slice assignment to copy the loaded data into the existing hash. 
      # keys and values are guaranteed to come out in the same (random) order as each other. 
      # the @{$foo}{blahbhal} is how you dereference a hash reference as a slice. 
      @{$schema}{keys %$loaded} = values %$loaded; 
     } 
    } 

    return $schema; 
} 

Я приукрасил несколько вещей, но я пытался оставить комментарии с достаточным количеством терминов (словарный запас или даже жаргоне, если вам нравится), чтобы вы могли делать выгодные поиски.

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

Perldoc - удивительный ресурс, но есть так много, что требуется время, чтобы научиться находить вещи. Взгляните на Perl Data Structures Cookbook и на номер Arrays of Arrays tutorial. Как новичок, я нашел Perl Functions by Category section of perlfunc невероятно полезным.

Думаю, я остановлюсь, теперь, когда я написал более чем достаточно текста, чтобы ослепить среднего человека. Надеюсь, вы найдете эту диссертацию полезной. Добро пожаловать, еще раз, и добрый вечер (пожалуйста, приспособитесь к тому, что ваше местное время, когда вы найдете этот ответ).

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