Написание отчетов с Perl - PullRequest
2 голосов
/ 21 мая 2010

Я пытаюсь записать несколько файлов отчетов, используя perl. Каждый файл имеет одинаковую структуру, но с разными данными. Итак, мой основной код выглядит примерно так:

#begin code
our $log_fh;
open %log_fh, ">" . $logfile

our $rep;

if (multipleReports)
{
   while (@reports) {
     printReport($report[0]);
   }
}

sub printReports
{
   open $rep, ">" . $[0];
   printHeaders();
   printBody();
   close $rep;
}

sub printHeader() {
format HDR =
@>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
$generatedLine
.

format HDR_TOP =
.

$rep->format_name("HDR");
$rep->format_top_name("HDR_TOP");

$generatedLine = "test";
write($rep);
$generatedLine = "next item";
write($rep);
$generatedLine = "last header item";
write($rep);
}

sub printBody #There are multiple such sections in my code. For simplicity, I have just shown 1 here
{
 #declare own header and header top. Set report to use these and print items to $rep
}

#end code

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

тест
следующий предмет
последний пункт

читает

последний пункт
последний пункт
последний пункт

Я перепробовал множество вариантов, в первую очередь, для автоматической промывки, но, по жизни, не могу понять, почему он это делает. Я использую Perl 5.8.2. Любая помощь / указатели очень ценятся.

Спасибо George

Редактировать 1 Я попытался передать дескриптор файла в качестве параметра подпрограммам, но все еще видел проблему. Затем я переместил оператор формата за пределы подпрограммы и объявил переменную, сгенерированную $, как глобальную. Это, казалось, исправило это. Я думаю, что по какой-то причине объявление формата каждый раз, когда вызывается подпрограмма, казалось, портит ее. Не знаю точно, почему. Странно то, что я переместил оператор формата обратно в подпрограмму (мне не нравилась идея объявить все переменные во всех моих операторах формата глобальными). Но на этот раз я изменил объявление на

my $generatedLine = "";
my $format = "format HDR = \n" .
'@>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>' . "\n" .
'$generatedLine' . "\n" .
'.';

my $formatTop = "format HDR_TOP = \n".
'.';

   eval $format;
   eval $formatTop;

Кажется, это тоже работает - я вижу правильные результаты в нескольких файлах (ну, в настоящее время я тестирую только с 2 файлами, завтра буду проводить еще тестирование).

Есть идеи, почему объявление формата таким образом работает? Что-то особенное происходит с Eval?

Спасибо George

Ответы [ 2 ]

8 голосов
/ 21 мая 2010

Я никогда не использовал его, но Text :: Report выглядит многообещающе, если вы делаете сложные отчеты.

Что касается более общих вопросов, ваш код заставляет меня думать, что вы не используете use strict и use warnings. Если нет, включите их. Это даст много подсказок.

Кроме того, вы, похоже, используете подпрограммы, что хорошо, но не пользуетесь преимуществом одной из их основных целей, а именно - обеспечения четко определенных областей для переменной области видимости. Например, почему $rep должна быть глобальной переменной? Если подпрограмме требуется некоторая информация, передайте ее в качестве аргумента. Особенно, когда ваша программа пытается выполнять одну и ту же задачу снова и снова - например, генерировать кучу отчетов - вы должны быть осторожны, чтобы не позволить переменным из одной итерации сохранять устаревшие значения во время последующих итераций.

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

use strict;
use warnings;

# Example usage: perl script.pl foo.txt bar.txt
main(@ARGV);

sub main {
    my @report_names = @_;
    for my $rep_name (@report_names) {
        my @fake_data = map rand(), 1..10;
        printReport($rep_name, @fake_data);
    }
}

sub printReport {
    my ($rep_name, @data) = @_;
    open my $fh, ">", $rep_name or die $!;
    printHeader($fh);
    printBody($fh, @data);
    close $fh;
}

sub printHeader() {
    my $fh = shift;
    print $fh "Header\n";
}

sub printBody {
    my ($fh, @data) = @_;
    print $fh "Body\n";
    print $fh $_, "\n" for @data;
}
0 голосов
/ 21 мая 2010

Я думаю, что в моем исходном коде выражение формата ведет себя как статическое. Он выполняется только один раз, когда подпрограмма вызывается первой. В следующий раз, когда вызывается подпрограмма, так как формат не оценивается, переменная формата $ generateLine указывает на предыдущую устаревшую переменную из последнего вызова подпрограммы. Вызов write () означает просто перезапись того же текста из последнего вызова подпрограммы.
С помощью нового метода он оценивает формат каждый раз, когда вызывается подпрограмма, и, следовательно, переменная формата $ generateLine указывает на последний локальный $ generateLine, связанный с новым вызовом подпрограммы. Таким образом, он печатает правильные данные.

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