blog20100901

2013/08/20 - プログラミング言語 Perl にまつわる etc. - Perl monger
参考 : perldoc, perldoc.jp, search.cpan.org, perldoc.perl.org ...
「 初めての Perl 第 6 版 」(オライリー・ジャパン発行 ISBN978-4-87311-567-2) 」
「 続・初めての Perl 改訂版 」(オライリー・ジャパン発行 ISBN4-87311-305-9) 」
「 Effective Perl 第 2 版 」(翔泳社発行 ISBN978-4-7981-3981-4) 」 ... etc,.

Perl Perl_6

Perl モジュール Exporter 03 %EXPORT_TAGS タグ (d092)

Perl モジュール Exporter 03 %EXPORT_TAGS タグ (d092)

目次 - Perl Index


Theme



Perl について、復習を兼ねて断片的な情報を掲載して行く連載その d092 回。

Perl で、サブルーチンを呼び出し元にエクスポートするためのモジュール「 Exporter 」を確認する。

今回は、配列「 @EXPORT 」と「@EXPORT_OK 」に登録した複数のシンボルをまとめて指定可能な「 タグ 」という機能と、そのためのハッシュ「 %EXPORT_TAGS 」を確認します。


エクスポートするシンボル



(d091) で確認したとおり、モジュール「 Exporter 」で何か ( 主にサブルーチン ) をエクスポートする場合は、専用の配列「 @EXPORT 」または「 @EXPORT_OK 」にシンボルをセットします。


our @EXPORT = qw( func1 func2 func3 );

# or

our @EXPORT_OK = qw( func1 func2 func3 );



なお、デフォルトでシンボルをエクスポートする @EXPORT は、エクスポート先の名前空間を暗黙に汚染するので通常使うべきではないとされています。

どうしても何かをエクスポートしたい場合は、明示的にシンボルを要求する @EXPORT_OK が推奨されています。


ハッシュ「 %EXPORT_TAGS 」



( あまり良いことではないはずですが ) エクスポートするシンボルが数多く存在する場合、複数のタグをカテゴリに分けた「 タグ 」として登録することができます。

タグの登録には、Exporter であらかじめ用意されている特別なハッシュ「 %EXPORT_TAGS 」を使います。

%EXPORT_TAGS では、ハッシュ key にタグの名前を、value にはタグにまとめたい複数のシンボルを無名配列リファレンス (d011) で指定します。

なお、タグ用のハッシュ %EXPORT_TAGS に登録するシンボルは先んじて @EXPORT または @EXPORT_OK に登録してある必要があります。


our $EXPORT = qw( func1 func2 );
our $EXPORT_OK = qw( func_a func_b );

# タグ num とタグ alp を作成
our %EXPORT_TAGS = ( num => [qw(func1 func2)], alp => [qw(func_a func_b)] );



タグの利用は、use 行のシンボルリストに「 :tag_name 」で指定します。


# in users_program

# タグでシンボルを要求
use YourModule qw( :num :alp );



なお、以前 (0xc9) 等で確認したモジュール「 CGI 」の関数セットはこの %EXPORT_TAGS を利用しています。


タグを利用する



モジュールを利用するプログラム側で「 %EXPORT_TAGS 」に登録したタグを利用します。

動作確認のためのモジュールは、単純に文字列を返すサブルーチンを持った次のコードを使います。


package YourModule;

use strict;
use warnings;

# Exporter を継承
use parent qw(Exporter);

# シンボルをセット
our @EXPORT_OK = qw(func1 func2 func_a func_b);

# タグを設定
our %EXPORT_TAGS = ( num => [qw(func1 func2)], alp => [qw(func_a func_b)] );

sub func1 {
'func one';
}
sub func2 {
'func two';
}

sub func_a {
'func A';
}
sub func_b {
'func B';
}

1;



これを、ユーザ側のプログラムで次のように使えば、タグに登録された各シンボル ( サブルーチン ) を自身の名前空間にインポートできます。


#!/usr/bin/perl

use strict;
use warnings;

# タグでシンボルを要求
use YourModule qw( :num :alp );

# YourModule のサブルーチンを利用する

print func1(), "\n";
print func2(), "\n";
print func_a(), "\n";
print func_b(), "\n";

__END__
# output
func one
func two
func A
func B




すべてのタグを結合するタグ「 :all 」を生成する



Generating Combined Tags で解説されている、すべてのタグのシンボルを持ったタグ「 :all 」の生成方法を確認します。

タグ「 :all 」の生成は次のコードで行えます。


# シンボルをセット
our @EXPORT_OK = qw(func1 func2 func_a func_b);

# タグを設定
our %EXPORT_TAGS = ( num => [qw(func1 func2)], alp => [qw(func_a func_b)] );
{
# 一度見た (seen) シンボルを記憶するハッシュ
my %seen;

# all をハッシュ key にして配列としてデリファレンス
push @{$EXPORT_TAGS{all}},

# まだ見ていないシンボル (!$seen{$_}) のみを all の配列に push
grep {!$seen{$_}++} @{$EXPORT_TAGS{$_}} for keys %EXPORT_TAGS;
}



この処理では、まず 11 行目で %EXPORT_TAGS の key に「 all 」をセットして、その value を配列としてデリファレンスしています ( @{ } (d013) )。

これにより、内部的には次のような状態 ( all の無名配列リファレンスにシンボルの push 待ち ) になります。


$EXPORT_TAGS{all} = [qw( ... Wait for symbols pushing ... )];

# equivalent to

%EXPORT_TAGS = ( all => [qw( ... )], other => ... );



それから、push (0x22) の第 2 引数として grep (d036) による選別処理を行います ( 14 行目 )。

選別処理では、まずあらかじめ登録しておいた %EXPORT_TAGS の key ( つまり登録済みのタグのシンボル ) を取り出して、それを配列としてデリファレンス ( @{$EXPORT_TAGS{$_}} ) します。

前項で確認したとおり、%EXPORT_TAGS の各 value は無名の配列リファレンスから成るので、デリファレンスによって各タグ ( key ) に指定したシンボルのリストが得られます。

これをさらに grep の引数のリストとして扱い、記憶用のハッシュ %seen の key として順次セットします ( $seen{$_} )。

grep のブロック内では、リストから得られたシンボルを既に見たか ( seen ) 否かをチェックします。

ここで、論理否定演算子「 ! 」(0x0d) を使っていますが、これはそのシンボルを「 まだ見ていない 」( !$seen{$_} ) 場合に評価を 真 とするためのものです。

シンボルを「 まだ見ていない 」場合で評価が 真 となったシンボルは、grep によって push に渡され、配列「 @{$EXPORT_TAGS{all}} 」に追加されます。

また、grep のブロックでは「 一度見たシンボル 」を後置の「 ++ 」(0x84) によって記憶します。

これにより、仮に複数のタグに登録された同一のシンボルがあった場合は、「 一度見た 」= 「 $seen{$_} の値が 真 」-> 「 ! によって論理否定 」= 「 grep が 偽 と判定 」するので、2 度目以降のそのシンボルは push に渡されることはなくなり、タグ「 all 」のシンボルは重複することがありません。

この一連の処理により、モジュールのユーザ側のプログラムではタグ「 :all 」の指定により、すべてのシンボルのインポートを行うことが可能になります。


# in users_program

# 1 つのタグですべてのシンボルを要求
use YourModule qw( :all );




NEXT



モジュール「 Exporter 」には、この他にもいくつかの機能が用意されています。興味があれば Perl モジュール Exporter 01 ドキュメント [翻訳] (d090) を参照してみてください。

次回は、自作のライブラリの配布を検討する際に、必要なファイルをまとめた「 ディストリビューション 」( distribution ) の書き方を確認します。


参考情報は書籍「 続・初めての Perl 改訂版 」, 「 Effective Perl 第 2 版 」を中心に perldoc, Wikipedia および各 Web サイト。それと詳しい先輩。

目次 - Perl Index



































同じカテゴリー(Perl)の記事
 Perl mp2 翻訳 Web コンテンツ圧縮の FAQ (d228) (2023-10-11 23:49)
 Perl mp2 翻訳 既知のブラウザのバグの回避策をいくつか (d227) (2023-05-26 15:41)
 Perl mp2 翻訳 Perl と Apache でのキュートなトリック (d226) (2023-05-19 17:05)
 Perl mp2 翻訳 テンプレートシステムの選択 (d225) (2022-08-15 22:23)
 Perl mp2 翻訳 大規模 E コマースサイトの構築 (d224) (2022-06-15 20:43)
 Perl mp2 翻訳 チュートリアル (d223) (2022-06-15 20:42)
上の画像に書かれている文字を入力して下さい
 
<ご注意>
書き込まれた内容は公開され、ブログの持ち主だけが削除できます。

Llama
リャマ
TI-DA
てぃーだブログ
プロフィール
セラ (perlackline)
セラ (perlackline)
QRコード
QRCODE
オーナーへメッセージ

PAGE TOP ▲