2012-09-10 14 views
2

我不太瞭解Perl,甚至不知道我在問什麼,但是我正在編寫一系列子程序,可用於處理不同傳入平面文件的許多單獨腳本。這個過程遠非完美,但這是我必須面對的問題,我試圖建立一個小型的潛艇庫,使我能夠更輕鬆地管理它。每個腳本使用自己的格式,排序,分組和輸出要求來處理不同的傳入平面文件。一個常見的方面是我們有小的文本文件,其中包含用於命名輸出文件的計數器,因此我們沒有重複的文件名。在Perl中可能需要調用子程序嗎?

因爲每個文件的數據處理都不同,所以我需要打開這個文件才能得到我的計數器值,因爲這是一個常用操作,我想將它放在一個子文件中以檢索計數器。但是之後需要編寫特定的代碼來處理數據。並且希望第二個子程序允許我在處理完數據後用計數器更新計數器。

如果第一個子調用被調用,是否有辦法讓第二個子調用成爲一個需求?理想情況下,如果它甚至可能是一個錯誤,會阻止腳本運行得像一個語法錯誤。

編輯:這裏是一個小[醜陋和簡化]僞代碼,給當前進程是什麼更好的手感:

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); 
+1

您可以從第一個子程序中調用第一個子程序(在完成第一個子程序中的所有錯誤處理後)。或者,您可以使用全局標誌,第二個子標籤將檢查第一個子標籤是否成功運行。或者,您可以將第一個子標識作爲參數之一傳遞給第二個子標識。 TIMTOWTDI! :) – 2012-09-10 20:08:31

+0

問題是我需要第一個子返回計數器,以便我的腳本可以使用計數器處理和輸出文件。在完成處理數據之前,我無法調用第二個更新文件。如果第一個腳本在腳本中被調用,而第二個腳本中的某個點沒有被調用,我想拋出一個錯誤。我不能在第二個測試,因爲如果它測試一個全局變量,這意味着第二個被調用,從而使全局變量測試沒有意義。 – MitchelWB

回答

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設置。

如果你喜歡傳遞名字而不是coderefs,我們也可以安排。

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)表示,這是適用於子程序一個屬性。我們只需要兩個參數,我們想要註解的子程序的全名以及子程序的coderef。

然後,我們關閉一部分的嚴格性來重新定義子${$glob}。這有點高級,但它實質上只是訪問內部符號表。

我們用上面給出的process_file的虛擬版本替換帶註釋的子版本。我們可以傳遞所有參數(@_),而不需要進一步處理。

畢竟,我們一個小豆蔻資料片添加到您之前使用的替補:

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

...它只是沒有做進一步的修改替換。使用庫時這些更改是不可見的。我意識到這種方法的限制,但在編寫普通代碼時不太可能碰到它們。

+0

我不確定這不是在吹我的Perl新手頭腦。 – MitchelWB

+0

我沒有足夠快地編輯我的評論: 所以你說的是我還需要定義幾個子例程。 get_counter()將檢索我的起始值,set_counter()會將我的最終結果寫回到我的文件中,並且在它們之間,我會調用一個唯一的子進程來處理子進程中的數據,以匹配$子例程中的字符串? 那麼$ subroutine sub中的內容就是我爲給定文件處理的數據所特有的內容? – MitchelWB

+0

@MitchelWB Perl是一種功能性語言,所以我們可以將coderefs/functions作爲參數傳遞給另一個子例程。在'process_file'裏面,我們給一個全局變量分配一個局部值 - 這個局部值可以從在這個範圍內調用的所有子元素中看到。是的,這就是我的建議。但是我們不應該傳遞函數名稱,而是傳遞給該函數的coderef(我們需要帶'\&'前綴的coderef)。這允許您爲任何地方的新文件類型創建插件函數,並間接調用它。這種模式被稱爲* callback *或* wrapper *。 – amon

0

那麼,你可以設置一個全局標誌並使用END block

也許neater是類似於@ amon的建議,或者甚至只是將您的文件處理放在標準名爲sub中,並從您的計數器代碼中調用它。

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

你process_file將從一個模塊輸出,如果你想保持它非常簡單,你process_file子使用Perl的-Μ加載模塊。

相關問題