┌──────────────────┐
│Perl入門 〜構造化プログラミング編〜 │
│(5)モジュール            │
│2005/11/06             │
└──────────────────┘

[▲Perl Home▲]


●モジュールとは

 ◆モジュールの記述
 
  ・自分で簡単なコードを書いていてもわかると思いますが、同じようなコーディン
   グを何度も目にします。そして多人数でコードを作成する場合、他人もコードを
   使いたい、又は自分のコードを他人に使って欲しい場合があります。
  
  ・Perlでは上記のような「コード共有」を実現する仕組みがあります。それが「モ
   ジュール」です。
  
  ・まず、始めに利用されるコード...「モジュールの記述」を眺め、次に利用法へ
   話を移していきたいと思います。
  
  ・最初にモジュールの記述例です。モジュールを記述する場合、拡張子は「.pm」
   とします。また慣習として、ファイル名はモジュール名と同一にします。下記の
   場合であれば「ModuleSample.pm」とするのが普通でしょう。
  
    ┌──────────────────────────────────┐
     #!/usr/local/bin/perl -w
     package ModuleSample;
    
     use Exporter;
     use strict;
    
     our @ISA = ('Exporter');
     our @EXPORT = (
       'ModSub1', # モジュール関数1
       'ModSub2'  # モジュール関数2
     );
    
     #===================================================================
     sub ModSub1 {
       print "ModSub1を実行しました\n";
     }
    
     #-------------------------------------------------------------------
     sub ModSub2 {
       print "ModSub2を実行しました\n";
     }
    
     #-------------------------------------------------------------------
    
     1; # モジュールの最後には必ず1を付けます
    └──────────────────────────────────┘
  
  ・つまりモジュール記述の基本形は
    +----------------------------------------+
    | package モジュール名;         |
    |                    |
    | use Exporter;             |
    |                    |
    | our @ISA = ('Exporter');       |
    | our @EXPORT = (サブルーチン名リスト); |
    |                    |
    | ...サブルーチンの記述...       |
    |                    |
    | 1; # 1で終わる            |
    +----------------------------------------+
   になります。理屈ぬきでこの形を覚えているだけでも問題ありませんが、意味合
   いに興味のある方は、下の文章を読んでみて下さい。

  ・package宣言文の後に、モジュールの名前を付けます。これは関数名や変数名の
   名前空間に相当する部分なので、標準Moduleや既存のModuleと被らないように配
   慮します。
  
  ・その後「Exporter」モジュールの使用を宣言します。このモジュールは、自分が
   書いた関数を他のコードで利用できるように...他のコードがimportする...環境
   を提供します。
  
  ・従ってExporterモジュールは、他のコードでもimportで利用されるため、@ISA配
   列の要素として入れておく必要があります。@ISA配列にour関数でスコープ規定
   をしていますが、このourは「効果」として(*1)、変数をグローバル化します。
   つまり@ISAの値は呼び出し側の他のコードでも共有されることになります。
  
  ・@EXPORTリストの中身は、他のコードが作成モジュールを呼び出した際に利用で
   きるサブルーチンのリストです。@EXPORTの要素は、モジュールを呼び出せば何
   の宣言も無しに使うことができます。明示的に利用サブルーチンを宣言させたい
   場合は@EXPORT_OKを利用します。(*2)


 ◆モジュールを利用する
 
  ・モジュールを利用する側では、下記のように宣言をした後、モジュールに内包さ
   れるサブルーチンを利用します。
   
    ┌──────────────────────────────────┐
     #!/usr/local/bin/perl -w
    
     use lib "./mymod";
     use strict;
    
     use ModuleSample;
    
     ModSub1();
     ModSub2();
    
     # EOF
     ──────────────────────────────────
     [実行結果]
     ModSub1を実行しました
     ModSub2を実行しました
    └──────────────────────────────────┘

  ・use libは、ライブラリ/モジュールの参照パスを追加するコマンドです。通常で
   は、Perlコンパイラは@INCを参照パスリストとして使用(*3)しますが、use lib
   はコンパイル時に@INCへ参照パスを追加します。プログラム終了後は自動的に
   @INCから削除されます。
  
  ・上記のサンプルコードでは、./mymod ディレクトリを参照パスに追加しているこ
   とになります。もちろん、先ほど作成したModuleSample.pmは ./mymod ディレク
   トリに置かれている前提です。
  
  ・モジュールの使用宣言が、use ModuleSample; の行です。
  
  ・後は、モジュール内で作成したサブルーチンを使用するだけです。モジュール内
   でExporterを使用し、@EXPORTリストに入れてあるサブルーチンは、名前修飾無
   しにそのまま使用することができます。
  
  ・これの意味するところとして、Expoterを経由して、モジュール内のサブルーチ
   ンを使用するということは、同名のサブルーチンをオーバーライトすることにな
   ります。
  
  ・もし複数のモジュールを使用する中で名前空間の管理が曖昧になってしまう場合
   は、作成側モジュールでExpoter/@EXPORTを使用せず記述し、呼び出し側ではモ
   ジュール名を付加したたサブルーチン名を使用します。
   
    [モジュール側 : Exporter未使用]
    ┌──────────────────────────────────┐
     #!/usr/local/bin/perl -w
     package ModuleSample;
     use strict;
    
     #===================================================================
     sub ModSub1 {
       print "ModSub1を実行しました\n";
     }
    
     #-------------------------------------------------------------------
     sub ModSub2 {
       print "ModSub2を実行しました\n";
     }
    
     #-------------------------------------------------------------------
    
     1; # モジュールの最後には必ず1を付けます
    └──────────────────────────────────┘
   
    [呼び出し側 : モジュール(パッケージ)名修飾]
    ┌──────────────────────────────────┐
     #!/usr/local/bin/perl -w
    
     use lib "./mymod";
     use strict;
    
     use ModuleSample;
    
     ModuleSample::ModSub1();
     ModuleSample::ModSub2();
    
     # EOF
     ──────────────────────────────────
     [実行結果]
     ModSub1を実行しました
     ModSub2を実行しました
    └──────────────────────────────────┘
  

 ◆標準モジュールを利用する
 
  ・Perlの良い点の一つですが、通常必要とされることが多い機能は、既に標準モジ
   ュールとして準備されています。例えばCGIの入力を処理するためのサブルーチ
   ン郡を供給する「CGI.pm」や、ファイルハンドルをオブジェクトとして使用する
   「FileHandle.pm」等があります。もちろん他にいろいろ。
  
  ・Perlコンパイラセット(今回の場合はWindows用ActivePerlを想定)をインストー
   ルした際に利用できる標準的なモジュールについては、格納パスが@INCリストに
   登録されているので、「use lib」を記述する必要はありません。そのまま
    use モジュール名;
   で利用できるケースがほとんどです。
  
  ・サブルーチンの利用については、各モジュールにより異なる点が多いので、付属
   のドキュメントを読むようにして下さい。
  
  ・尚、今のところ本講座ではPerlの構造化コーディングについて説明していますが
   これが一段落した後は、CGIを利用したWEBプログラミングについて説明を行う予
   定です。そのときはいろいろな標準モジュールを利用した効率的なPerlプログラ
   ミングを披露することになるでしょう。
  
  
 ◆モジュールとパッケージ

  ・さて「モジュールを使う」と言いながら、実際記述しているキーワードは
   packageだったりすることにそろそろ違和感を感じ始めているかもしれません。
   そろそろこれらの関係をクリアにしたいと思います。
 
  ・モジュールは利用する側から見たコード全体を指す言葉です。そしてpackageは
   モジュール内部の名前(パッケージ)空間を示す言葉です。
  
  ・よって
     ファイル名 「AAA.pm」
   の中で
     package宣言「package ModuleSample;」
   と記述した場合、コードを利用する側では下記のように記述します。

    [呼び出し側 : モジュール(パッケージ)名修飾]
    ┌──────────────────────────────────┐
     #!/usr/local/bin/perl -w
    
     use lib "./mymod";
     use strict;
    
     use AAA; # ファイル名で決まる
    
     ModuleSample::ModSub1(); # package名で決まる
     ModuleSample::ModSub2();
    
     # EOF
     ──────────────────────────────────
     [実行結果]
     ModSub1を実行しました
     ModSub2を実行しました
    └──────────────────────────────────┘

  ・もちろん、Exporterがモジュール本体側で使用されている場合、利用するサブル
   ーチンをpackage名で修飾する必要はありません。
  
  ・今回はモジュールとパッケージの違いを説明するために、敢えてファイル名と
   package名を変えましたが、慣習としてファイル名とpackage名は通常同じものを
   与えます。
  
  ・この結果、モジュールとpackageが混ざった状態で説明が進んでしまうケースが
   頻発しますが、通常は「モジュール名とpackage名は同じ」という前提があるこ
   とを意識するようにして下さい。


●もう一度変数のスコープ

 ◆変数のスコープの種類
 
  ・名前空間(package)についての知識を得たところで、もう一度変数のスコープに
   ついて整理することにしたいと思います。以前のレポート「(4)引数/戻り値」で
   は変数のスコープとして
    グローバル変数 : コード全体で有効
    ブロック変数  : ブロック内で有効
   があると説明しましたが、厳密には異なります。
  
  ・実際のところ、Perlには
    パッケージスコープ変数 : package内で有効
    レキシカルスコープ変数 : 取り囲むスコープの中で有効
   の2種類しかありません。
  

 ◆グローバル変数

  ・すると、上記を見て「足りない...」と思うのはグローバル変数でしょう。今ま
   でグローバル変数と言っていたのは、あくまで単一のファイルスコープを持つも
   のでした。つまりパッケージスコープ変数です。
  
  ・では、複数ファイル間で共有する変数...グローバル変数を使う場合ですが、今
   回のテキストの最初に説明した、@ISAや@EXPORTをモジュールの呼び出し元と共
   有するために使った手法同様になります。そう「our」を使用すれば良いのです。
  
  ・少し整理すると
    ブロック内のみで有効とする : ブロック内でmyを使用
    ファイル/パッケージで有効 : ブロック外でmyを使用
    グローバルで有効      : ourを使用
   となります。
  
  ・上記は
    + 一つのファイルには一つのpackage宣言
    + package変数を単独で呼び出すことはやらない
   という、プログラミングマナーに則っているという前提で書いています。ある意
   味、厳密にはまだスコープの説明には抜けがあります。
  
  ・このあたりについては、もう少しモジュールを使用した複数人/ファイルでのコ
   ーディングに慣れてから考えた方が良いでしょう。(*4)
   

  ・大体この程度でPerl構造化プログラミングの基本は理解できた状態になったと思
   います。この後は「robustなコーディング」をテーマにして仕上げへ進んで行き
   たいと思います。
   


(*1)実際のところはmyと似たような動きです。宣言された位置からスコープの最後まで
  においてグローバルであることを宣言...同名のローカル変数をマスクします。

(*2)このあたりの詳細な記述については他のPerl本やドキュメントを参照して下さい。

(*3)@INCは、perl -Vで内容を確認することができます。もちろんグローバルのリスト
  として、コードから内容を表示させることもできます。

(*4)私自身はコーディングマナーとして、なるべくpackage変数へダイレクトにアクセ
  スすべきではないと考えているからです。

[▲Perl Home▲]

Copyright(c)2005 Monpe
All Rights Reserved