0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[Perl][翻訳] Exporter.pm の perldoc /日本語訳

Last updated at Posted at 2022-08-08

(凡例)

コア中のコアモジュールである Exporter の POD について、ウェブを眺めてみたところ整理された邦訳が存在しないようだったので、訳しました。オブジェクト指向 Perl では使いませんが、CPAN の資産を利用したりコードリーディングのためには、理解は必須だと思いますので。

  • Perl 5.36.0 に附属する Exporter 5.77 のドキュメントに準拠 (原文)。
  • 翻訳について生じる範囲の著作権は放棄 (CC0) します。
  • 直訳では意味が取りにくい部分を勝手に訳補した箇所は〔〕で示す。

名前

Exporter - モジュールのための、デフォルトの import メソッドの実装

概要

モジュール YourModule.pm で:

package YourModule;
use Exporter 'import';
our @EXPORT_OK = qw(munge frobnicate);  # 要求に応じてエクスポートするシンボル

または

package YourModule;
require Exporter;
our @ISA = qw(Exporter);  # Exporter の全メソッドを継承する
our @EXPORT_OK = qw(munge frobnicate);  # 要求に応じてエクスポートするシンボル

または

package YourModule;
use parent 'Exporter';  # Exporter の全メソッドを継承する
our @EXPORT_OK = qw(munge frobnicate);  # 要求に応じてエクスポートするシンボル

YourModule を use したい他のファイルでは:

use YourModule qw(frobnicate);      # リストされたシンボルをインポート
frobnicate ($left, $right)          # YourModule::frobnicate を呼ぶ

あなたがモダン Perl のコードで使いたいと思うかもしれない、これらのさらなる変種については、以下の "グッド・プラクティス" に目を通すとよい。

説明

Exporter モジュールは、あるモジュールがその関数や変数をユーザーの名前空間にエクスポートすることを可能にする、import メソッドを実装している。数多くのモジュールが、それ自身の import メソッドを実装せずに、Exporter モジュールを使う。なぜなら Exporter は、通常の事例にとって最適化された実装とともに、とてもフレキシブルなインターフェースを提供しているからだ。

モジュールの use 宣言を処理するとき、Perl は自動的にそのモジュールの import メソッドを呼ぶ。モジュールと use については、perlfuncperlmod がドキュメント化している。Exporter を理解するために、モジュールの概念、および use 宣言が働く仕方を理解することは重要である。

エクスポートのやり方

〔Exporter を利用する〕モジュールの側では、配列 @EXPORT および @EXPORT_OK は、デフォルトでユーザー名前空間にエクスポートされるシンボルのリストと、エクスポートするようにユーザーから要求できるシンボルのリストとを、それぞれ保持する。シンボルは、関数・スカラー変数・配列・ハッシュ・型グロブを意味できる。関数の前に置かれるアンパサンドがオプショナルであることを除いて、シンボルはフルネームで与えられねばならない。例えば

our @EXPORT    = qw(afunc $scalar @array);   # afunc は関数
our @EXPORT_OK = qw(&bfunc %hash *typeglob); # &bfunc では明示的なプレフィクス

もし関数名だけをエクスポートしているなら、アンパサンドは省略することが奨められる。こうすると、実行がより速いものになる。

何をエクスポートするかの選択

メソッド名をエクスポートしてはならない

適当な理由がなければ、他のどんなものもエクスポートしてはならない

エクスポートはモジュールユーザーの名前空間を汚染する。エクスポートしなければならないのなら、@EXPORT より @EXPORT_OK を好んで使おうとし、名前衝突のリスクを減らすために、短い、またはよく使われるシンボル名を避けよ。

一般的に言って、エクスポートされていないどんなものでも、YourModule::item_name (または $blessed_ref->method) 構文を使うことで、そのモジュールの外部からアクセス可能である。慣習では、名前の先頭にアンダースコアを足すことで、それらが '内部用' であってパブリックな利用には適さないということを、インフォーマルに伝えることができる。

(実際には、こうすればプライベートな関数をつくることも可能である:

my $subref = sub { ... };
$subref->(@args);            # 関数として呼び出す
$obj->$subref(@args);        # メソッドとして使う

もっともメソッドとしての利用にあっては、それでどうやって継承システムを機能させるのかは、あなた自身で解決しなければならない問題だが)

普遍的なルールとして、もしモジュールがオブジェクト指向であろうとしているのなら、何もエクスポートすべきではない。また、もしそれが関数のコレクションにすぎないのなら、@EXPORT は論外、@EXPORT_OK を心して用いるがよい。また、エクスポートリストでは、関数とメソッドの名前には、アンパサンド付きの名前よりは裸の単語を使うことが好ましい。

その他のモジュールデザインのガイドラインは、perlmod で見ることができる。

インポートのやり方

あなたのモジュールを use したがっているその他のファイルにおいては、あなたのモジュールをロードしてシンボルをインポートするのには、3つの基本的なやり方がある:

  • use YourModule;

これは、YourModule の @EXPORT から use 宣言がされた名前空間へ、すべてのシンボルをインポートする。

  • use YourModule ();

これは、perl にあなたのモジュールをロードさせて、シンボルは何もインポートしない。

  • use YourModule qw(...);

これは、呼び出し側によってリストされたシンボルだけを、その名前空間へインポートする。すべてのリストされたシンボルは、あなたが用意した @EXPORT@EXPORT_OK の中になければならず、さもなければエラーになる。Exporter の進んだエクスポート機能はこれと似たような仕方でアクセスされるが、その際にはシンボル名とは構文的に区別されたリストのエントリが利用される。

より進んだ機能を使おうとしない限り、以上がたぶん、Exporter を使うためにあなたが知る必要のあるすべてのことである。

進んだ機能

特殊なインポートリスト

インポートリストのエントリのどれかが「!」「:」「/」で始まっていれば、インポートする名前のリストに対する、一連の追加・除外を指定したリストとして扱われる。指定子は左から右へ処理され、次のどれかの形である:

[!]name         この名前だけ
[!]:DEFAULT     @EXPORT の全部の名前
[!]:tag         $EXPORT_TAGS{tag} 無名配列〔リファレンス〕の全部の名前
[!]/pattern/    @EXPORT  @EXPORT_OK の、マッチする全部の名前

〔[!] は、! が先行しうることを示す。〕先行する ! は、マッチした名前を、インポートする名前のリストから除外すべきことを示している。先頭にある指定子が除外なら、その前に :DEFAULT があるものとして扱われる。ただし、もしデフォルトセットとともに加えて余分な名前をインポートしたいというだけのことなら、依然として明示的に :DEFAULT を含めてやる必要がある。

例えば、Module.pm がこのように定義しているとする:

our @EXPORT      = qw(A1 A2 A3 A4 A5);
our @EXPORT_OK   = qw(B1 B2 B3 B4 B5);
our %EXPORT_TAGS = (T1 => [qw(A1 A2 B1 B2)], T2 => [qw(A1 A2 B3 B4)]);

@EXPORT@EXPORT_OK の中では、タグは使えないことに注意せよ。

EXPORT_TAGS に含まれる名前は、また @EXPORT@EXPORT_OK にも出現していなくてはならない。

この Module を利用するアプリケーションでは、次のように書ける:

use Module qw(:DEFAULT :T2 !B3 A3);

また他の例では:

use Socket qw(!/^[AP]F_/ !SOMAXCONN !SOL_SOCKET);
use POSIX  qw(:errno_h :termios_h !TCSADRAIN !/^EXIT/);

(// を使った) もっともよくあるパターンでは、/EXIT/ でなく /^EXIT/ 等と、冒頭を ^ でアンカーする必要がある、ということも銘記しよう。

BEGIN { $Exporter::Verbose=1 } と詠唱すれば、どう指定子が処理されているかや、実際に何がモジュールにインポートされているかを見ることができる。

Exporter の import メソッドを使わずにエクスポートする

Exporter には、Exporter の import メソッドを直接呼ぶことができない状況で使われる特殊なメソッド、'export_to_level' がある。export_to_level メソッドは、このようである:

MyPackage->export_to_level(
    $where_to_export, $package, @what_to_export
);

ここで $where_to_export は整数であり、コールスタックをどこまで遡ってシンボルをエクスポートするかを指示する。@what_to_export は配列であり、どのシンボルたちをエクスポートしたいかを指示する (通例これは @_ である)。引数 $package は、今のところ活用されていない。〔以下で見るように、import 内で @_ を置くならば、先頭にパッケージ名が渡ってきて辻褄が合う〕

例として、あるモジュール A を持っているとしよう。それにはすでに import 関数がある:

package A;

our @ISA = qw(Exporter);
our @EXPORT_OK = qw($b);

sub import
{
    $A::b = 1;     # さして役立ちもしない import メソッド
}

そして、パッケージ A を呼び出したモジュールにまで、シンボル $A::b をエクスポートしたい。Exporter が、継承メカニズムを通じて import メソッドに依存して動いている以上、このままでは Exporter::import() が呼ばれることはない。かわりに、次のように書く:

package A;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw($b);

sub import
{
    $A::b = 1;
    A->export_to_level(1, @_);
}

これは、カレントパッケージの一階層「上に」シンボルをエクスポートする――すなわち: パッケージ A を use したプログラム、ないしはモジュールに。

注意: export_to_level を呼ぶ以前に、いっさい @_ に変更を加えないように――さもなくば、あなたのパッケージを利用する人々に、まさに説明不能なことが起こるでしょう!

Exporter を継承せずにエクスポートする

あなたの @ISA に Exporter を含めることで、Exporter の import() メソッドは継承されるが、なおまた多分必要としない、継承ツリーをややこしくするような、他のさまざまなヘルパーメソッドも継承される。これを避けるのに、こうできる:

package YourModule;
use Exporter qw(import);

これで、Exporter 自身の import() メソッドが、YourModule にエクスポートされる。すべてが元通りに動く。あなたが Exporter を @YourModule::ISA に含める必要がないことを除いては。

注意: この機能は、perl 5.8.3 に伴ってリリースされた、Exporter の version 5.57 で導入された。

モジュールバージョンのチェック

Exporter モジュールは、あるモジュールから数字をインポートしようとする試みを、$module_name->VERSION($value) の呼び出しへと変換する。これは、使っているそのモジュールのバージョンが、要求するバージョンより大きいかまたは等しいことをバリデートするのに利用できる。

歴史的事情から、Exporter はただ VERSION に委譲するだけの require_version メソッドを提供している。もともと、UNIVERSAL::VERSION のまだ存在していなかった頃には、Exporter は require_version を呼んでいた。

UNIVERSAL::VERSION メソッドが $VERSION ナンバーを単純な数値として扱っているので、バージョン 1.10 は 1.9 より小さいとみなされるだろう。この理由から、例えば 1.09 のように、数字の少なくとも小数点以下 2 桁を確保しておくことが、強く推奨される。

未知のシンボルのマネージ

特定のシンボルがエクスポートされることを防ぎたい、という状況もありうる。典型的には、それが存在しないシステムもあるような関数や定数を、エクステンションが含んでいる場合がこれにあたる。

エクスポートできないシンボルの名前は @EXPORT_FAIL 配列にリストすること。

あるモジュールがこれらのシンボルのどれか一つでもインポートしようとするとき、エラーを発生させる前に Exporter は、状況をハンドルするための機会を〔エクスポートする側の〕モジュールに許す。Exporter は〔エクスポートする側のモジュールが自身で定義、または Exporter から継承する〕export_fail メソッドを、失敗したシンボルのリストで〔内部処理として次のコードのように〕呼び出す:

@failed_symbols = $module_name->export_fail(@failed_symbols);

ここで export_fail メソッドが空リストを返すなら、エラーは登録されず、要求されたすべてのシンボルはエクスポートされる。返されるリストが空でないなら、おのおののシンボルについてエラーが発生し、エクスポートは失敗する。Exporter は、リストを変更せずただ返すだけの、デフォルトの export_fail メソッドを提供している。

export_fail メソッドの使途としては、シンボルに即してより良いエラーメッセージを出すことや、遅延アーキテクチャチェック (デフォルトで @EXPORT_FAIL にシンボルを多めに入れておき、誰かが実際に使おうとして、高くつくチェックによってそれらがそのプラットフォームで実際に使用可能だと判明した暁には、そこから取り除く) の実行が挙げられる。

タグを扱うユーティリティ関数

%EXPORT_TAGS 内にリストされたシンボルはまた @EXPORT@EXPORT_OK のいずれかに現れていなければならないから、タグ付けられたシンボル集合の、@EXPORT ないし @EXPORT_OK への追加を簡易ならしめるように、二つのユーティリティ関数が提供されている:

our %EXPORT_TAGS = (foo => [qw(aa bb cc)], bar => [qw(aa cc dd)]);

Exporter::export_tags('foo');     # aa, bb と cc を @EXPORT に追加
Exporter::export_ok_tags('bar');  # aa, cc と dd を @EXPORT_OK に追加

タグではない名前については @EXPORT または @EXPORT_OK にそのまま追加されるが、ミススペルされたタグ名が通知なく @EXPORT@EXPORT_OK に追加されるのを避けるため、(-w があれば) 警告をトリガーするだろう。未来のバージョンでは、これは致命的エラーになる可能性がある。

合併タグの生成

%EXPORT_TAGS の中にさまざまなシンボルカテゴリが存在する場合、"use" 文を単純にするため、利便性をはかる ":all" を作っておくことが通例、有益である。

一番単純な作成法は:

our  %EXPORT_TAGS = (foo => [qw(aa bb cc)], bar => [qw(aa cc dd)]);

 # 重複を削って、他のすべての ":class" タグを ":all" クラスに足す
 {
   my %seen;

   push @{$EXPORT_TAGS{all}},
     grep {!$seen{$_}++} @{$EXPORT_TAGS{$_}} foreach keys %EXPORT_TAGS;
 }

CGI.pm は、自身のカテゴリのうちいくつか (本当に全部ではない) を含んだ ":all" タグを作る。一つの小さな変更だけで可能になる:

# 重複を削って、他のいくつかの ":class" タグを ":all" クラスに足す
{
  my %seen;

  push @{$EXPORT_TAGS{all}},
    grep {!$seen{$_}++} @{$EXPORT_TAGS{$_}}
      foreach qw/html2 html3 netscape form cgi internal/;
}

%EXPORT_TAGS のタグ名には ':' が先行しないことに注意せよ。

AUTOLOAD される定数

たくさんのモジュールが、めったに使われない値をコンパイルしメモリを浪費するのを避けようと、定数サブルーチンの AUTOLOAD を役立てている (定数サブルーチンの詳細については perlsub を見よ)。このような定数サブルーチンの呼び出しは、それが定数であることをコンパイル時にチェックできないので、最適化によってコンパイル時に除去されない。

コンパイル時にプロトタイプがわかるときでさえ、サブルーチンの実体はわからない (それはまだ AUTOLOAD されていなかった)。サブルーチンの呼び出しが定数値で安全に置き替えられることを検出するには、() プロトタイプとサブルーチンの実体の、両方ともが、コンパイル時に perl によって確かめられるのでなければならない。

一つの回避策として、定数を BEGIN ブロックの中で一度呼び出すという手がある:

package My ;

use Socket ;

foo( SO_LINGER );  ## SO_LINGER は最適化によって除去され「ない」; 実行時に呼ばれる
BEGIN { SO_LINGER }
foo( SO_LINGER );  ## SO_LINGER は最適化によってコンパイル時に除去される。

これは、のちに My パッケージにおいて SO_LINGER と出くわす以前に、SO_LINGERAUTOLOAD が生じるよう強制する。

もしあなたが AUTOLOAD するパッケージを書いているのであれば、他のパッケージによって明示的にインポートされる定数、またはあなたのパッケージが use されるときいつも使われるような定数については、AUTOLOAD を強制することを検討しよう。

グッド・プラクティス

@EXPORT_OK とその仲間たちの宣言

Exporterstrictwarnings の標準的プラグマの下で使うとき、パッケージ変数 @EXPORT_OK, @EXPORT, @ISA 等を宣言するには our キーワードが必要である。

our @ISA = qw(Exporter);
our @EXPORT_OK = qw(munge frobnicate);

5.6 未満の Perl との後方互換性が重視されるときは、かわりに use vars ステートメントが書かれなければならない。

use vars qw(@ISA @EXPORT_OK);
@ISA = qw(Exporter);
@EXPORT_OK = qw(munge frobnicate);

安全に遊ぼう

require Exporter といった実行時ステートメントの使用や、パッケージ変数の代入については、警戒しておくべきことがいくつかある。意識しないプログラマーにとって、それらは非常に神機霊妙なものでありうる。これは例えば、相互再帰的モジュールにおいて起こりうることである。相互再帰的モジュールでは、関連するコンストラクションが実行されるタイミングによって、弊害が出る。

そうしたことを全然考えないで済ます理想的な方法は、BEGIN ブロックと単純な import メソッドを使うことである。そうすると、"概要" に掲げたコードの最初のものは、次のようにして書き直されるだろう:

package YourModule;

use strict;
use warnings;

use Exporter 'import';
BEGIN {
  our @EXPORT_OK = qw(munge frobnicate);  # 要求に応じてエクスポートするシンボル
}

あるいは、Exporter から継承する必要があるのなら:

package YourModule;

use strict;
use warnings;

BEGIN {
  require Exporter;
  our @ISA = qw(Exporter);  # Exporter の全メソッドを継承する
  our @EXPORT_OK = qw(munge frobnicate);  # 要求に応じてエクスポートするシンボル
}

この BEGIN は、Exporter.pm のロードと @ISA および @EXPORT_OK への代入とが、use がするように直ちに生じることを保証して、物事がどうもよじれてしまったり、または単に明白におかしかったりする余地を残さない。

Exporter のロード、および継承という観点では、baseparent といったモジュールを利用するという代案もある。

use base qw(Exporter);
# or
use parent qw(Exporter);

これらのステートメントは、BEGIN { require Exporter; our @ISA = qw(Exporter); } の置き替えとして好ましく、おなじコンパイル時作用を保っている。基本的な違いは、base のコードは fields プラグマの宣言と一緒にうまくはたらく一方で、parent は、ただ IS-A 関係を確立するだけのより古い base のコードを効率化したバージョンである、ということだ。

さらなる違いについては、base および parent のドキュメンテーションとコードを参照せよ。

こうした実行時 vs. コンパイル時の罠に対する、また別の根治法に、Exporter::Easy がある。これは、すべてのボイラープレート・コードを use 文の中で一発で可能にしてしまう、Exporter のラッパーである。

use Exporter::Easy (
    OK => [ qw(munge frobnicate) ],
);
# @ISA は自動的にセットアップされる
# すべての代入はコンパイル時に起こる

エクスポートすべきでないもの

"何をエクスポートするかの選択" で、エクスポートしないよう、これらはすでに警告されている:

  • メソッド名 (なぜならそうしたいと思わないだろうし、あなたがしたいと思うことをそれはしないだろうから)
  • デフォルトでは何も (なぜならユーザーをびっくりさせたいとは思わないだろうから……悪い意味で)
  • 必要のないものは何も (なぜなら less is more だから)

一つこのリストに加えるとすれば、変数名をエクスポートしてはならない。なるほど Exporter はそうすることを許可しているが、だからといって、そのことがそうすべきであるということを直ちに含意するわけではない。

@EXPORT_OK = qw($svar @avar %hvar); # するな!

変数のエクスポートは、良い考えではない。それらは見えないところで変更されうるし、追跡し修正することが困難をきわめるほどの遠くから、恐ろしい影響を招き入れる。信じてくれ: そうする価値はない。

クラス全体に通じる設定を set/get する能力を提供したいのなら、サブルーチンまたはクラスメソッドとして、かわりにアクセサを提供するのが最善である。

関連項目

Exporter は、シンボルをエクスポートする能力を持った唯一のモジュールでは断じてない。CPAN には、そういうものが山ほど見つかる。それらのいくつかは、より軽量である。いくつかは、改善された API と機能とを提供している。あなたの必要に適合するものを選ぶとよい。以下は、そうしたモジュールたちのサンプルリストである。

Exporter::Easy
Exporter::Lite
Exporter::Renaming
Exporter::Tidy
Sub::Exporter / Sub::Installer
Perl6::Export / Perl6::Export::Attrs

ライセンス

This library is free software. You can redistribute it and/or modify it under the same terms as Perl itself.

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?