目錄

名稱

autodie::hints - 提供使用者子常式提示給 autodie

語法

package Your::Module;

our %DOES = ( 'autodie::hints::provider' => 1 );

sub AUTODIE_HINTS {
    return {
        foo => { scalar => HINTS, list => SOME_HINTS },
        bar => { scalar => HINTS, list => MORE_HINTS },
    }
}

# Later, in your main program...

use Your::Module qw(foo bar);
use autodie      qw(:default foo bar);

foo();         # succeeds or dies based on scalar hints

# Alternatively, hints can be set on subroutines we've
# imported.

use autodie::hints;
use Some::Module qw(think_positive);

BEGIN {
    autodie::hints->set_hints_for(
        \&think_positive,
        {
            fail => sub { $_[0] <= 0 }
        }
    )
}
use autodie qw(think_positive);

think_positive(...);    # Returns positive or dies.

說明

簡介

autodie pragma 在處理 Perl 內建函式時非常聰明。這些函式的行為是固定的,而 autodie 確切知道它們如何嘗試發出失敗訊號。

但模組中的使用者自訂子常式呢?如果你對使用者自訂子常式使用 autodie,它會假設以下行為來顯示失敗

所有其他傳回值(包括單一零的清單,以及包含單一空字串的清單)都視為成功。然而,實際世界的程式碼並不總是這麼簡單。也許你正在處理的程式碼會在失敗時傳回包含「FAIL」字樣的字串,或包含 (undef, "human error message") 的二元素清單。若要讓 autodie 與這些類型的子常式一起使用,我們有提示介面

提示介面允許向 autodie 提供提示,說明它應該如何從使用者自訂子常式偵測失敗。雖然這些提示可以由 autodie 的最終使用者提供,但理想情況下會寫入模組本身,或寫入 autodie 本身的輔助模組或子類別。

提示是什麼?

提示是針對自動死亡子常式的傳回值檢查的子常式或值。如果比對傳回 true,autodie 會認為子常式已失敗。

如果提供的提示是子常式,則 autodie 會將完整的傳回值傳遞給該子常式。如果提示是任何其他值,則 autodie 會針對提供的值進行智慧比對。在 Perl 5.8.x 中沒有智慧比對運算子,因此這些版本僅支援子常式提示。

提示可以提供給純量和清單內容。請注意,自動死亡子常式永遠不會看到空內容,因為 autodie 始終需要擷取傳回值以進行檢查。在空內容中呼叫的自動死亡子常式會像在純量內容中呼叫一樣,但在檢查其傳回值後會將其捨棄。

提示範例

提示可能包含子常式參照、重載智慧比對的物件、正規表示式,以及視 Perl 版本而定的其他內容。你可以指定不同的提示,說明如何在純量和清單內容中識別失敗。

這些範例適用於在 AUTODIE_HINTS 子常式中使用,以及在呼叫 autodie::hints->set_hints_for() 時使用。

最常見的特定於內容的提示為

# Scalar failures always return undef:
    {  scalar => sub { !defined($_[0]) }  }

# Scalar failures return any false value [default expectation]:
    {  scalar => sub { ! $_[0] }  }

# Scalar failures always return zero explicitly:
    {  scalar => sub { defined($_[0]) && $_[0] eq '0' }  }

# List failures always return an empty list:
    {  list => sub { !@_ }  }

# List failures return () or (undef) [default expectation]:
    {  list => sub { ! @_ || @_ == 1 && !defined $_[0] }  }

# List failures return () or a single false value:
    {  list => sub { ! @_ || @_ == 1 && !$_[0] }  }

# List failures return (undef, "some string")
    {  list => sub { @_ == 2 && !defined $_[0] }  }

# Unsuccessful foo() returns 'FAIL' or '_FAIL' in scalar context,
#                    returns (-1) in list context...
autodie::hints->set_hints_for(
    \&foo,
    {
        scalar => qr/^ _? FAIL $/xms,
        list   => sub { @_ == 1 && $_[0] eq -1 },
    }
);

# Unsuccessful foo() returns 0 in all contexts...
autodie::hints->set_hints_for(
    \&foo,
    {
        scalar => sub { defined($_[0]) && $_[0] == 0 },
        list   => sub { @_ == 1 && defined($_[0]) && $_[0] == 0 },
    }
);

這個「在所有內容中」的建構非常常見,可以使用「失敗」鍵進行縮寫。這會將 scalarlist 提示都設定為相同的值

        # Unsuccessful foo() returns 0 in all contexts...
        autodie::hints->set_hints_for(
            \&foo,
            {
                fail => sub { @_ == 1 and defined $_[0] and $_[0] == 0 }
            }
	);

        # Unsuccessful think_positive() returns negative number on failure...
        autodie::hints->set_hints_for(
            \&think_positive,
            {
                fail => sub { $_[0] < 0 }
            }
	);

        # Unsuccessful my_system() returns non-zero on failure...
        autodie::hints->set_hints_for(
            \&my_system,
            {
                fail => sub { $_[0] != 0 }
            }
	);

從您的程式內部手動設定提示

如果您使用的是在失敗時傳回特殊內容的模組,則您可以手動為每個所需的子常式建立提示。一旦指定提示,它們就會提供給之後載入的所有檔案和模組,因此您可以將這項工作移至模組中,它仍然會運作。

	use Some::Module qw(foo bar);
	use autodie::hints;

	autodie::hints->set_hints_for(
		\&foo,
		{
			scalar => SCALAR_HINT,
			list   => LIST_HINT,
		}
	);
	autodie::hints->set_hints_for(
		\&bar,
                { fail => SOME_HINT, }
	);

可以傳遞子常式參考(建議)或完全限定的子常式名稱作為第一個引數。這表示您可以設定可能會載入的模組提示

use autodie::hints;
autodie::hints->set_hints_for(
	'Some::Module:bar', { fail => SCALAR_HINT, }
);

當您有一個使用許多第三方模組的專案時,此技術最為有用。您可以在一個地方定義所有可能的提示。這甚至可以在 autodie 的子類別中。例如

package my::autodie;

use parent qw(autodie);
use autodie::hints;

autodie::hints->set_hints_for(...);

1;

您現在可以使用 my::autodie,它將像標準的 autodie 一樣運作,但現在會知道您設定的任何提示。

將提示新增至您的模組

autodie 提供一個被動介面,讓您可以宣告模組的提示。如果載入 autodie,它會找到並使用這些提示,但如果沒有載入,則這些提示不會產生任何效果(或依賴關係)。若要設定這些提示,您的模組需要宣告它執行 autodie::hints::provider 角色。您可以撰寫自己的 DOES 方法,使用 Class::DOES 等系統為您處理繁重的工作,或宣告一個 %DOES 套件變數,其中包含 autodie::hints::provider 鍵和對應的 true 值。

請注意,檢查 %DOES hash 是 autodie 專用的捷徑。其他模組不會使用此機制來檢查角色,不過您可以使用 CPAN 中的 Class::DOES 模組來允許它。

此外,您必須定義一個 AUTODIE_HINTS 子常式,它會傳回一個包含子常式提示的 hash 參考。

        package Your::Module;

        # We can use the Class::DOES from the CPAN to declare adherence
        # to a role.

        use Class::DOES 'autodie::hints::provider' => 1;

        # Alternatively, we can declare the role in %DOES.  Note that
        # this is an autodie specific optimisation, although Class::DOES
        # can be used to promote this to a true role declaration.

        our %DOES = ( 'autodie::hints::provider' => 1 );

        # Finally, we must define the hints themselves.

	sub AUTODIE_HINTS {
	    return {
	        foo => { scalar => HINTS, list => SOME_HINTS },
	        bar => { scalar => HINTS, list => MORE_HINTS },
	        baz => { fail => HINTS },
	    }
	}

這樣您的程式碼就可以設定提示,而不需要依賴載入或甚至安裝 autodieautodie::hints。如此一來,您的程式碼在安裝 autodie 時可以執行正確的動作,但不需要依賴它才能運作。

堅持提示

當使用者定義的子常式被 autodie 包裝時,它會在提示可用時使用提示,否則會回復到此文件引言中所述的預設行為。如果我們預期提示存在,但(出於任何原因)它尚未載入,這可能會造成問題。

我們可以要求 autodie 堅持使用提示,方法是在子常式名稱的開頭加上驚嘆號。單獨的驚嘆號表示所有在其後的子常式都必須宣告提示。

	# foo() and bar() must have their hints defined
	use autodie qw( !foo !bar baz );

	# Everything must have hints (recommended).
	use autodie qw( ! foo bar baz );

	# bar() and baz() must have their hints defined
	use autodie qw( foo ! bar baz );

        # Enable autodie for all of Perl's supported built-ins,
        # as well as for foo(), bar() and baz().  Everything must
        # have hints.
        use autodie qw( ! :all foo bar baz );

如果指定的子常式沒有提示可用,這將導致編譯時期錯誤。強烈建議堅持使用 Perl 內建函式的提示(例如,openclose)。

強烈建議堅持提示。

診斷

嘗試設定無法識別的子常式的提示

您使用子常式參考呼叫 autodie::hints->set_hints_for(),但無法將該參考解析回子常式名稱。它可能是匿名子常式(無法使其自動執行),或由於其他原因而沒有名稱。

如果您收到這個錯誤,而子常式具有真實名稱,那麼您可能在 autodie 中發現一個錯誤。請參閱 autodie 中的「BUGS」 以了解如何報告此錯誤。

無法提供 %s 的標量或清單提示的失敗提示

在定義提示時,您可以提供 listscalar 關鍵字,您可以提供一個 fail 關鍵字。您不能混合搭配它們。

%s 提示遺失 %s

您提供了沒有提供 list 提示的 scalar 提示,反之亦然。您必須同時提供 scalarlist 提示,提供一個 fail 提示。

致謝

作者

版權所有 2009,Paul Fenwick <pjf@perltraining.com.au>

授權

這個模組是免費軟體。您可以根據 Perl 本身的條款來散布它。

另請參閱

autodieClass::DOES