NAME
Data::Util::JA - データとデータ型のためのユーティリティ集
VERSION
This document describes Data::Util version 0.43
SYNOPSIS
use Data::Util qw(:validate);
sub foo{
# they will die if invalid values are supplied
my $sref = scalar_ref(shift);
my $aref = array_ref(shift);
my $href = hash_ref(shift);
my $cref = code_ref(shift);
my $gref = glob_ref(shift);
my $rref = regex_ref(shift);
my $obj = instance(shift, 'Foo');
# ...
}
use Data::Util qw(:check);
sub bar{
my $x = shift;
if(is_scalar_ref $x){
# $x is an array reference
}
# ...
elsif(is_instance $x, 'Foo'){
# $x is an instance of Foo
}
# ...
}
# miscelaneous
use Data::Util qw(:all);
my $ref_to_undef = anon_scalar();
$x = anon_scalar($x); # OK
my $stash = get_stash('Foo');
install_subroutine('Foo',
hello => sub{ "Hello!\n" },
goodby => sub{ "Goodby!\n" },
);
print Foo::hello(); # Hello!
my($pkg, $name) = get_code_info(\&Foo::hello); # => ('Foo', 'hello')
my $fqn = get_code_info(\&Foo::hello); # => 'Foo::bar'
uninstall_subroutine('Foo', qw(hello goodby));
print neat("Hello!\n"); # => "Hello!\n"
print neat(3.14); # => 3.14
print neat(undef); # => undef
DESCRIPTION
このモジュールはデータとデータ型のためのユーティリティ関数を提供します。
ユーティリティはチェック関数群と検証関数群とその他の関数群があります。 チェック関数群は値の型を調べ,真偽値を返す機能を提供します。 検証関数群は値の型を調べ,真であればその値自身を返し, 偽であれば致命的エラーとなる機能を提供します。 その他の関数群は,無名スカラーリファレンスの生成やシンボルテーブルの操作, コードリファレンスの操作などの機能を提供します。
このモジュールの実装はXSとPure Perl両方提供しており,Cコンパイラのある 環境ではXSバックエンドが,ない環境ではPure Perlバックエンドが使用されます。
XSバックエンドは注意深く実装されているため非常に効率がよく, Pure Perlバックエンドより2倍から10倍程度高速に動作します。
INTERFACE
Check functions
チェック関数群は:check
インポートタグによって導入できます。これらはある値 の型が目的の型であれば真を,そうでなければ偽を返します。
また,これらの関数はオーバーロードマジックも調べます。たとえば,${}
が オーバーロードされているオブジェクトは,スカラーリファレンスとして扱われます。
リファレンスの型チェックをする関数は,オブジェクトリファレンスに対しては, オーバーロードされていない限り常に偽を返します。 これは,オブジェクトの実装に依存するコードを書かないようにするためです。
- is_scalar_ref(value)
-
スカラーリファレンスかどうかのチェックを行います。
- is_array_ref(value)
-
配列リファレンスかどうかのチェックを行います。
- is_hash_ref(value)
-
ハッシュリファレンスかどうかのチェックを行います。
- is_code_ref(value)
-
コードリファレンスかどうかのチェックを行います。
- is_glob_ref(value)
-
グロブリファレンスかどうかのチェックを行います。
- is_regex_ref(value)
-
qr//
によって作られる正規表現かどうかのチェックを行います。 - is_instance(value, class)
-
classのインスタンスかどうかのチェックを行います。
Scalar::Util::blessed($value) && $value->isa($class)
というコードと ほぼ等価です。classが未定義値またはリファレンスであれば致命的エラーとなります。
- is_invocant(value)
-
valueに対してメソッドを起動できるかどうかをチェックします。
- is_value(value)
-
valueがプリミティブ値かどうかをチェックします。すなわち,定義済みであり, リファレンスではなく,型グロブでもなければ真を返します。
この関数には検証を行う対応関数がありません。
- is_string(value)
-
valueが1文字以上の内容を持つ文字列かどうかをチェックします。
is_value($value) && length($value) > 0
と同じです。この関数には検証を行う対応関数がありません。
- is_number(value)
-
valueが数値かどうかをチェックします。 この「数値」とは,
sprintf '%g', $value
などとしたときに警告を出さず, またPerlプログラム中にリテラルとしておくことができる値という意味です。すなわち,この関数は
Scalar::Util::looks_like_number()
と異なり,"Inf"
や"NaN"
を数値として扱いません。また,数値化したときに 警告を出さない例外である"0 but true"
>も数値として扱いません。この関数には検証を行う対応関数がありません。
- is_integer(value)
-
valueが整数かどうかをチェックします。これは
is_number()
の判定に加えて, 整数値かどうかをチェックします。この関数には検証を行う対応関数がありません。
Validating functions
検証関数は:validate
タグによって導入できます。これらはチェック関数と 同じ方法でチェックを行います。 ただし,その結果が真であれば第一引数をそのまま返し, 偽であれば致命的エラーとなります。
これらの関数もオーバーロードマジックをチェックします。
- scalar_ref(value)
-
スカラーリファレンスかどうかの検証を行います。
- array_ref(value)
-
配列リファレンスかどうかの検証を行います。
- hash_ref(value)
-
ハッシュリファレンスかどうかの検証を行います。
- code_ref(value)
-
コードリファレンスかどうかの検証を行います。
- glob_ref(value)
-
グロブリファレンスかどうかの検証を行います。
- regex_ref(value)
-
qr//
によって作られる正規表現かどうかの検証を行います。 - instance(value, class)
-
classのインスタンスかどうかの検証を行います。
classが未定義値またはリファレンスであれば致命的エラーとなります。
- invocant(value)
-
valueに対してメソッドを起動できるかどうかの検証を行います。
valueがクラス名である場合,そのクラス名を正規化した文字列を返します。 すなわち,
"::Foo"
や"main::Foo"
を与えると"Foo"
を返します。
Micellaneous utilities
その他,個別にインポートできるいくつかのユーティリティ関数があります。
- anon_scalar()
-
undef
を参照する匿名スカラーリファレンスを生成します。 - anon_scalar(value)
-
valueのコピーを参照する匿名スカラーリファレンスを生成します。
これは
do{ my $tmp = $value; \$value; }
というコードと等価です。 - neat(value)
-
valueを表示に適するよう整形した文字列を返します。
<do{ defined($value) ? qq{"$value"} : 'undef' }
>を置き換える機能 として提供されます。 - get_stash(invocant)
-
スタッシュ stash と呼ばれるinvocantのシンボルテーブルハッシュが 存在すれば,そのスタッシュを返します。
invocantがオブジェクトリファレンスであれば,そのオブジェクトのパッケージの スタッシュを返します。
invocantがパッケージ名であり,そのパッケージが既に存在すれば, そのパッケージのスタッシュを返します。
- install_subroutine(package, name => subr [, ...])
-
サブルーチンsubrをpackageにnameとしてインストールします。
do{ no strict 'refs'; *{$package.'::'.$name} = \&subr; }
というコードと ほぼ等価です。さらに,subrが匿名サブルーチンであればpackageに 名前付きサブルーチン&package::nameとして配置します。サブルーチンを再インストールするときは,
no warnings 'redefine'
ディレクティブを使ってください。no warnings 'redefine'; install_subrouitne($package, $name => $subr);
packageかnameが未定義値またはリファレンスであれば致命的エラーとなります。 subrがコードリファレンスでないときも致命的エラーとなりますが, オーバーロードマジックは考慮されます。
なお,Pure Perl版のコードでは匿名サブルーチンの配置は行いません。
- uninstall_subroutine(package, names ...)
-
サブルーチンnameをパッケージpackageから削除します。
undef &subr
が&subr
を未定義にして型グロブのコードスロットを そのままにするのに対して,uninstall_subroutine
は型グロブのコードスロットを 空にします。これは
Sub::Delete::delete_sub()
に似ていますが,複数のサブルーチンを一度に 削除できます。 - get_code_info(subr)
-
サブルーチンsubrのパッケージと名前のペアを返します。 これは
Sub::Identify::get_code_info()
とほぼ同じ機能です。 ただし,スカラーコンテキストでは完全修飾名を返します。 - curry(subr, args and/or placeholders)
-
サブルーチンsubrのカリー化を行います。 つまり特定の引数を固定したクロージャを生成します。
args and/or placeholdersには,固定する引数か,カリー化サブルーチンの引数に 置き換えられるプレースホルダを渡します。プレースホルダには,添え字xを参照 する
\x
と,\x
で参照した最大の添え字の以降の引数を参照する*_
があります。たとえば,以下の
$closure
と$curried
は同じ意図で呼び出すことができます。my $class = 'Foo'; $closure = sub{ is_instance($_[0], $class) }; $curried = curry \&is_instance, \0, $class; $closure = sub{ install_subroutine($class, @_) }; $curried = curry \&install_subroutine, $class, *_;
なお,
*_
は\x
で参照しなかった引数ではないので注意してください。 たとえば,curry(\&subr, *_, \1)->(0, 1, 2, 3)
というカリー化では,subr(2, 3, 1)
が呼び出されます。より詳しいサンプルコードがData::Util::Curryにあります。
- modify_subroutine(subr, modifier_type => subroutines, ...)
-
サブルーチンsubrをmodifier_typeにしたがってsubroutinesで修飾し, 無名関数modified_subrとして返します。
modifier_typeには
before
,around
,after
があり,before
は subrの呼び出し前に,after
はsubrの呼出し後に,modified_subrに 与えられた引数で呼び出されます。before
とafter
の戻り値は捨てられます。around
はsubrの入出力をフィルタリングするための修飾子です。その際,呼び出順は,
before
とaround
は後で定義されたものが先に呼び出され (last-defined-first-called),after
は先に定義されたものが先に呼び出されます(first-defined-first-called)。この呼び出し順はsubroutine_modifier()
でも同じ です。たとえば:
$modified = modify_subroutine(\&foo, around => [sub{ my $next = shift; do_something(); goto &{$next}; # continuation }]); $modified->(); $modified = modify_subroutine(\&foo, before => \@befores, around => \@arounds, after => \@afters, ); $modified->();
XSによる実装では,サブルーチンを修飾したときのコストは非常に安くなっています。
このディストリビューションに付属しているexample/lib/MethodModifiers (
modify_subroutine()
/subroutine_modifier()
のデモ)のベンチマーク benchmark/methext_bench.plによれば,メソッド修飾のコストは次のようになります:with before modifier: 100% slower with after modifier: 100% slower with around modifier: 200% slower
なお,
SUPER::
疑似クラスによるメソッドの拡張は約500% slowerですから, メソッド修飾子による拡張の方が数倍高速です。各修飾子については,"Method Modifiers" in Class::MOP::Classに 詳しい解説があります。
- subroutine_modifier(modified, modifier_type => subroutines, ...)
-
modify_subroutine()
で生成したmodifiedを操作します。引数をmodifiedのみ渡した場合は,そのmodifiedが
modify_subroutine()
で 生成されたものかどうかを示すブール値を返します。if(subroutine_modifier $subr){ # $subrは修飾子つきサブルーチン }
modifiedとmodifier_type(
before
,around
,after
およびoriginal
) を渡すと,そのmodifier_typeに応じた修飾関数 (またはoriginal
の場合,元の関数)を返します。@befores = subroutine_modifier $modified, 'before';
このほか,更に関数のリストを渡した場合には,modifiedのmodifier_typeに その関数を追加します。
subroutine_modifier $modified, before => @befores;
- mkopt(input, moniker, require_unique, must_be)
-
inputを元に配列リファレンスを作成します。
これは
Data::OptList::mkopt()
に似ています。それに加えて,must_beは 名前と型のペアからなるハッシュリファレンスでもかまいません。 - mkopt_hash(input, moniker, must_be)
-
inputを元にハッシュリファレンスを作成します。
これは
Data::OptList::mkopt_hash()
に似ています。それに加えて,must_beは 名前と型のペアからなるハッシュリファレンスでもかまいません。
DISCUSSIONS
What is a X-reference?
「Xのリファレンス」とは何を指すのでしょうか。ここではハッシュリファレンスを例にとって考えます。 まず,判断要素は以下の3つを想定します。
ref($x) eq 'HASH'
Scalar::Util::reftype($x) eq 'HASH'
overload::Method($x, '%{}')
ref()
は非常に高速なので,実用上はこれで事足りることが多いと思われます。しかし,これはオーバーロードマジックを考慮しません。
reftype()
を使うべきではありません。$xがオブジェクトである場合,オブジェクトの実装型を参照し,カプセル化を壊してしまうことになるからです。
そしてoverload::Method
が捕捉するのは,オブジェクトをある型のリファレンスとみなしてよい特殊なケースです。
なお,直接$xをハッシュリファレンスとみなして参照すること($x->{$key}
)は避けるべきです。これは$xがハッシュリファレンスでない場合に正しく致命的エラーを発生させますが,ブレスされたハッシュリファレンスのときにはアクセスが成功します。しかし,そのアクセスの成功はオブジェクトの実装に依存しています。
さて,それではis_hash_ref()
は何を調べればいいのでしょうか。回答の一つはParams::Util
が示しています。Version 0.35の時点では,P::U::_HASH
は(1)を,P::U::_HASHLIKE
は(2)と(3)をチェックします。しかし先に述べたように,(1)は高速ですがオーバーロードマジックを考慮しないので不完全であり,(2)はオブジェクトのカプセル化を壊すため使うべきではありません。このように考えると,is_hash_ref()
は(1)と(3)によるチェックを行うのが正しい実装ということになります。
したがって,is_hash_ref()
ではref()
とoverload::Method()
を使ってリファレンスの型を調べます。is_scalar_ref()
,is_array_ref()
,is_code_ref()
,is_glob_ref()
も同様です。
DEPENDENCIES
Perl 5.8.1 or later.
BUGS AND LIMITATIONS
No bugs have been reported.
Please report any bugs or feature requests to the author.
SEE ALSO
AUTHOR
Goro Fuji <gfuji(at)cpan.org>
LICENSE AND COPYRIGHT
Copyright (c) 2008, Goro Fuji <gfuji(at)cpan.org>. Some rights reserved.
This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.