ishiducaの日記 このページをアンテナに追加 RSSフィード

2009-06-13

[][]localで小細工するメモ 18:43 localで小細工するメモ - ishiducaの日記 を含むブックマーク はてなブックマーク - localで小細工するメモ - ishiducaの日記 localで小細工するメモ - ishiducaの日記 のブックマークコメント

決まったファイル(この場合、error.log)を読み込んで処理する(この例だと、print)場合に、関数定義したとして、こんなスクリプトを書いたとする

print_file.pl

#!/usr/bin/perl -w
use strict;
my $log = 'error.log';

&print_file();
exit 0;

sub print_file{
	open my $fh, "<", $log or die "can not open $log";
	while( <$fh> ){
		print $_;
	}
	close $fh;
}

この例だと、$logに設定した error.log 以外は処理できないけど、一時的に別のファイルも処理したくなったとすると、このスクリプトだとうまくない。定義した print_file 関数で読み込むファイル名を引数に指定できるようにしておくのが現実的だけど、小細工したい時に local宣言でごまかせたのでメモ。

our宣言とlocal宣言をセットで

print_file_use_local.pl

#!/usr/bin/perl -w
use strict;
our $log = 'error.log'; #  my -> our

# 一時的な処理
{
	local $log = './archive/2009/06/error.log';
	&print_file();
}

&print_file();

exit 0;

sub print_file{
    ...
}

忘れがちなのが、「my $log = ...」を「our $log = ...」に直すところ。my のままだと、レキシカル変数はローカライズできないよって「Can't localize lexical variable $log at print_file_use_local.pl line xx」なエラーを吐く。

my宣言の罠

また、3行目の「our」と7行目の「local」を「my」に直すとエラーは吐かないけど、11行目で実行した際、7行目で指定した$logのままファイルを読み込んでしまう致命的な事態になってしまう。

print_file_use_my.pl

#!/usr/bin/perl -w
use strict;
my $log = 'error.log';

# 一時的な処理
{
	my $log = './archive/2009/06/error.log';
	&print_file();
}

# この時点で $log は error.log なんだけど
# ブロック内で宣言した ./archive/2009/06/error.log が
# print_file で保持されたままになっている
# これってクロージャってやつ?
&print_file();

exit 0;

sub print_file{
    ...
}

現実的なら、サブルーチンのprint_fileを直す方(引数にファイル名を使うようにする)がベターなんだろうか

sub print_file{
	# &print_file($log);
	my $log_file = shift;
	open my $fh, "<", $log_file or die "can not open $log_file";
	while( <$fh> ){
		print $_;
	}
	close $fh;	
}
トラックバック - http://perl.g.hatena.ne.jp/ishiduca/20090613

2009-05-11

[][][][]Re: package宣言をして名前空間を定義する 20:24 Re: package宣言をして名前空間を定義する  - ishiducaの日記 を含むブックマーク はてなブックマーク - Re: package宣言をして名前空間を定義する  - ishiducaの日記 Re: package宣言をして名前空間を定義する  - ishiducaの日記 のブックマークコメント

端折りすぎました。

package宣言をして名前空間を定義する(はじめてのモジュール その2)では、以下のコードの中で「our」を使っていたんですが、モジュールファイル内で作ったグローバル変数をスクリプト内で使うためのインポート/エクスポートの処理が書いてありませんでした。このままでは、eto.pl ではグローバル変数のエラーが返ってしまいます。kits さんがはてブで「ourによる変数名のパッケージ名省略が可能なのは、あくまで宣言したブロック(ファイル)の範囲内のみ」とご指摘くださいました。

ex: ishiduca.pm(モジュールファイル)このままだと、$Year は eto.pl では使えない

package ishiduca; # モジュールファイル名でpackage宣言する
use strict;
our( $Year ); # 明示的には$ishiduca::Year
$Year = 1919;
# 以下省略
1;

ex: eto.pl(モジュールを使用するスクリプト)

#!/usr/bin/perl -wl
use strict;
use ishiduca;

print $Year; # ishiduca.pm でour(グローバル変数)宣言されているので、
             # エラーは出ない
             # 明示的にはprint $ishiduca::Year;

端折った部分を加えるとこう

ishiduca.pm

package ishiduca;
use strict;
our( $Year );
$Year = 1919;

# 以下、端折った部分
our(@ISA, @EXPORT);

require Exporter;
@ISA = qw( Exporter );

@EXPORT = qw( $Year );

1;

もしくは、eto.pl で、明示的に $ishiduca::Year とする

トラックバック - http://perl.g.hatena.ne.jp/ishiduca/20090511