2

私はPerlについて十分に知らないので、私が何を求めているのかさえ正確に知ることはできませんが、すべてが異なる着信フラットファイルを処理する多くの個々のスクリプトで利用できる一連のサブルーチンを書いています。プロセスは完璧にはほど遠いですが、それは私が対処しなければならないことであり、私はそれをすべて管理するのを簡単にするサブの小さなライブラリを自分で構築しようとしています。各スクリプトは、独自のフォーマット、並べ替え、グループ化、および出力の要件を備えた、異なる受信フラットファイルを処理します。一般的な側面の1つは、出力ファイルに名前を付けるために使用されるカウンターを格納する小さなテキストファイルがあるため、ファイル名が重複しないことです。

データの処理はファイルごとに異なるため、カウンター値を取得するためにファイルを開く必要があります。これは一般的な操作であるため、カウンターを取得するためにサブに入れたいと思います。ただし、データを処理するための特定のコードを作成する必要があります。そして、データを処理した後、カウンターでカウンターを更新できるようにする2番目のサブが必要です。

最初のサブコールが呼び出された場合に、2番目のサブコールを要件にする方法はありますか?理想的には、構文エラーのようにスクリプトをまったく実行できなくなるようなエラーでさえある可能性があります。

編集:これは、現在のプロセスが何であるかをよりよく理解するための、少し[醜く単純化された]疑似コードです。

require "importLibrary.plx";

#open data source file
open DataIn, $filename;

# call getCounterInfo from importLibrary.plx to get 
# the counter value from counter file
$counter = &getCounterInfo($counterFileName);

while (<DataIn>) {
  # Process data based on unique formatting and requirements
  # output to task files based on requirements and name files 
  # using the $counter increment $counter
}

#update counter file with new value of $counter
&updateCounterInfo($counter);
4

2 に答える 2

4

私はあなたが試していることを完全には理解していませんが、あなたはいつでもあなたの潜水艦をプラグイン可能にすることができます:

サブがありprocess_fileます。これは、メイン処理を実行する引数としてサブルーチンを取ります。

our $counter;
sub process_file {
   my ($subroutine, @args) = @_;
   local $counter = get_counter();
   my @return_value = $subroutine->(@args);
   set_counter($counter);
   return @return_value;
}
# Here are other sub definitions for the main processing
# They can see $counter and always magically have the right value.
# If they assign to it, the counter file will be updated afterwards.

サブがあると仮定すると、次のprocess_type_Aことができます

my @return_values = process_file(\&process_type_A, $arg1, $arg2, $arg3);

process_type_A($arg1, $arg2, $arg3)これは、追加の呼び出しスタックフレームと設定を除いて、と同じように動作し$counterます。

coderefの代わりに名前を渡すことを好む場合は、それも手配できます。

package MitchelWB::FileParsingLib;
our $counter;
our %file_type_processing_hash = (
  "typeA" => \&process_type_A,
  "typeB" => \&process_type_B,
  "countLines" => sub { # anonymous sub
     open my $fh, '<', "./dir/$counter.txt" or die "cant open $counter file";
     my $lines = 0;
     $lines++ while <$fh>;
     return $lines;
  },
);

sub process_file {
   my ($filetype, @args) = @_;
   local $counter = get_counter();
   # fetch appropriate subroutine:
   my $subroutine = $file_type_processing_hash{$filetype};
   die "$filetype is not registered" if not defined $subroutine;  # check for existence
   die "$filetype is not assigned to a sub" if ref $subroutine ne 'CODE';  # check that we have a sub
   # execute
   my @return_value = $subroutine->(@args);
   set_counter($counter);
   return @return_value;
}
...;
my $num_of_lines = process_file('countLines');

編集:最もエレガントなソリューション

または:属性は本当にきれいです

なぜ愚かなコールバック?なぜ余分なコード?なぜ規約を呼び出すのですか?なぜテーブルをディスパッチするのですか?それらはすべて非常に興味深く柔軟ですが、よりエレガントなソリューションがあります。ほんの少しの情報を忘れていたのですが、今ではすべてがうまくいきました。Perlには、他の言語では「注釈」と呼ばれる「属性」があり、コードや変数に注釈を付けることができます。

新しいPerl属性の定義は簡単です。使用する属性と同じ名前のサブをuse Attribute::Handlers定義します。

sub file_processor :ATTR(CODE) {
  my (undef, $glob, $subroutine) = @_;
  no strict 'refs';
  ${$glob} = sub {
    local $counter = get_counter();
    my @return_value = $subroutine->(@_);
    set_counter($counter);
    return @return_value;
}

この属性を使用して:ATTR(CODE)、これがサブルーチンに適用可能な属性であることを示します。必要な引数は2つだけです。注釈を付けるサブルーチンのフルネームと、サブルーチンへのcoderefです。

次に、厳密性の一部をオフにして、サブを。で再定義し${$glob}ます。これは少し高度ですが、基本的には内部シンボルテーブルにアクセスするだけです。

注釈付きのサブを、上記のようにダムダウンしたバージョンに置き換えprocess_fileます。@_さらに処理することなく、すべての引数()を直接渡すことができます。

その後、以前に使用した潜水艦に小さな情報を追加します。

sub process_type_A :file_processor {
  print "I can haz $counter\n";
}

…そしてそれはそれ以上の変更なしでただ交換をします。ライブラリを使用する場合、変更は表示されません。私はこのアプローチの制限を認識していますが、通常のコードを書くときにそれらに遭遇する可能性はほとんどありません。

于 2012-09-10T20:19:16.503 に答える
0

そうですね、グローバルフラグを設定して、ENDブロックを使用することができます。

おそらく、きちんとしたものは、@ amonの提案のようなものであるか、ファイル処理をsubという名前の標準に入れて、カウンターコードから呼び出すだけです。

my ($fh, counter) = get_counter(...);
my $ok = process_file($fh, $counter);
update_counter($counter) if $ok;

process_fileはモジュールからエクスポートされます。これを非常に単純にしたい場合は、perlの-Μを使用して、process_filesubを使用してモジュールをロードします。

于 2012-09-10T21:35:53.970 に答える