サンプルコードをコピーすれば、そのままPerlで実行して、試すことができます。(旧詳細目次,旧カテゴリ別目次)
デバッガで、サンプルコードをたどれば理解が深まります。 (デバッガの使い方)
2009-02-21
Test::More 真偽値、数値や文字列の比較を行う関数
前回はTest::Moreの役割や関数について少し述べました。
今回は実際に自動試験をおこうなための関数について解説します。
真偽値、数値や文字列の試験のための関数一覧
真偽値、数値、文字列、オブジェクトの中身などを試験するには、以下の関数を使用します。
関数 | 解説 |
ok | Test::Simpleと同じもの。真偽値の確認に使用 |
is | eqを使っての文字列が等しいことを確認。整数の数値比較はこれでもOK |
isnt | neを使って文字列が等しくないことを確認。整数の数値比較はこれでもOK |
like | 文字列が正規表現にマッチすることを確認 |
unlike | 文字列が正規表現にマッチしないことを確認 |
cmp_ok | ==, <, >, <=, >=, gt, lt, などPerlの演算子を指定して比較 |
is_deeply | 配列の配列など複雑なデータ構造の比較に用いる |
関数の解説
1. ok
okは、Test::Simpleのokとまったく同じです。
2009-02-20
Test::More 自動試験をさらに便利にする
入門的な自動試験のためのモジュールであるTest::Simpleについては解説しました。今回は、Perlの自動試験を行うためのスタンダードにあたるTest::Moreというモジュールについて解説します。
Test::Moreの便利なところ
Test::Simpleは、ok関数という自動試験のための関数がありますが、これの不便なところは、どんな理由で試験が失敗したかということがわからないことです。
Test::Moreを使えば、どのような理由で試験に失敗したのかということまでわかります。
また配列の配列やハッシュの配列などの複雑なデータ構造を試験することもできます。
Test::Moreの関数
Test::Moreの関数の一覧です。
1. 真偽値、数値や文字列の試験のための関数
関数 | 解説 |
ok | Test::Simpleと同じもの。真偽値の確認に使用 |
is | eqを使っての文字列が等しいことを確認。整数の数値比較はこれでもOK |
isnt | neを使って文字列が等しくないことを確認。整数の数値比較はこれでもOK |
like | 文字列が正規表現にマッチすることを確認 |
unlike | 文字列が正規表現にマッチしないことを確認 |
cmp_ok | ==, <, >, <=, >=, gt, lt, などPerlの演算子を指定して比較 |
is_deeply | 配列の配列など複雑なデータ構造の比較に用いる |
2.モジュールの読み込み、クラスの定義などを試験するための関数
関数 | 解説 |
can_ok | クラスがあるメソッドを持つかどうかの確認 |
isa_ok | オブジェクトが継承しているクラスの確認、リファレンスの種類の確認 |
use_ok | モジュールがuseできることを確認 |
require_ok | モジュールがrequireできることを確認 |
3.自動試験の内容の補足するための関数
関数 | 解説 |
diag | 試験が失敗した内容を詳しく伝えたいときに使う |
note | デバッグ用に値を確認したい場合に使う |
explain | 配列の配列など複雑なデータ構造の内容を表示 |
SKIP:(ラベル) | 環境依存するコードをスキップするために使用 |
TODO:(ラベル) | しなければならない試験を記述するために使用 |
Test::Moreの記述
Test::Moreを使用するには、Test::Simpleと同じようにテストの数を指定する必要があります。'no_plan'としてテストの数を指定しないこともできます。
use Test::More tests => 23;
あるいは
use Test::More 'no_plan';
次回は各関数について解説します。
no_planについて
no_planは、「テストを弱くするのでなるべく避けてください」とドキュメントにあるのですが、何が弱くなるのかよくわからない。
「no_planはTest::Harnessの新しい機能なので、Test::Harnessが古い場合は、すべてのテストが失敗します」と書いてありますが、そういう状況は存在するのかなぁ? よくわからない。
(テスト数を指定すると、新しいテストを追加したときに、テスト数の記述を増やすのを忘れて、テスト成功なんてことがよくあるので、できればno_planで済ませたい。)
サイト案内
2009-02-19
「メソッドチェーンはわかりにくい」といった話の続き
メソッドチェーンはややこしいと思うという記事を書いたらcharsbarさんが メソッドチェーンの話という記事を書いてくださったので、紹介しておきます。
もしからしたら私が慣れていないだけで、メソッドチェーンは読みやすいという人のほうが多いのかもしれません。
でも今の私が思っていること
前回のサンプルの
my $loader = Loader->new; my $book = $loader->load( 'Book' )->build
このコード。
どのように書いてほしいかというと、
my $loader = Loader->new; $loader->load( 'Book' ); my $book = $loader->build
と書いてほしいです。
こう書けば、loadが何をしているのかが、コードから推測できます。buildが$loaderから呼ばれたことがコードを読んでわかります。
でも、一番素直に書けるのが良いと思ってます。loadとbuildを順番に呼び出すメソッドがあるなら、、load_build を使うのが一番良いと思います。
my $book = Loader->new->load_build( 'Book' );
こういう風に記述できる選択肢があるのに、
my $book = Loader->new->load( 'Book' )->build
という記述をあえてする必要はないのじゃないでしょうか?
newというメソッドは自分自身を返すことが自明です。だから、メソッドチェーンでつなげても誤解は起きません。けれど、loadが自分自身を返すというのは、自明ではないです。
ゲッターのチェーンとセッターのチェーン
ゲッターのチェーンは使ってもよいと思っています。
my $query_string = $page->url->query_string
は、「ページのURLのクエリ文字列を取り出す。」と読めます。
でもセッターのチェーンは避けたほうが良いと思います。
$book->author( 'a' )->name( 'b' )->to_string;
以下と比較して、記述は非常に良く似ているのに、意味はまったく違います。
$book->author->name->to_string;
めんどうでも、
$book->author( 'a' ) $book->name( 'b' ) $book->to_string;
と書いたほうが、可読性が高いと思います。
個人的には英語として自然に読めるかよりも、プログラムとしてわかりやすいかどうかのほうが大事だと思っています。
追記
もう一度charsbarさんから返答がありました。
気分を害したのでしたらすみませんでした。Mojoのコードをもう少し読んでみます。
2009-02-18
メタプログラミングとは
最新版のSimo( バージョン 0.0601 )では、アクセッサをメタプログラミングという手法を使って記述しました。( Mojo::Base(ソースコード) が参考になりました。 )
メタプログラミングという手法を覚えたので、メタプログラミングとは何かということを解説しておきます。
メタプログラミングとは
メタプログラミングとはソースコードを生成するプログラミングのことです。メタプログラミングによって生成したソースコードは、eval関数で実行することができます。
メタプログラミングとは、「プログラムの実行時にソースコードを記述し、記述したソースコードを実行する手法」といえます。
簡単なメタプログラミング
「print $num」というソースコードを作成して、evalで実行しています。1と表示されます。
use strict; use warnings; my $num = 1; my $src = 'print $num'; # メタプログラミング( ソースコードの記述 ) eval $src; # eval で記述したソースコードを実行 __END__
条件分岐の伴うメタプログラミング
sub func{ return 'Windows'; }
Windowsでない場合は、
sub func{ return 'Not Windowss'; }
という関数を定義するメタプログラミングをしてみます。
することは、関数の定義を文字列で作成して、evalで実行するだけです。
qq//はダブルクォート演算子で、ダブルクォートが使用できること以外はダブルクォートと同じです。.= は、現在の文字列にさらに文字列を結合する場合に使います。
use strict; use warnings; my $func; # メタプログラミング( OSに応じた func関数の定義を作成 ) $func .= qq/sub func{\n/; if( $^O eq 'MSWin32' ){ $func .= qq/ return 'Windows';\n/; } else{ $func .= qq/ return 'Not Windows';\n/; } $func .= qq/}\n/; eval $func; # 関数が定義される。 print func(), "\n"; # 実行してみる __END__
このようにメタプログラミングを使用すると関数自体を実行時に定義することもできます。
この記事への指摘
その1
弾さんから指摘を受けたのでポイントを掲載しておきます。
perl,javascript and more - evalは最後の武器
evalだけがメタプログラミングの技法ではないし、またevalはその威力ゆえ最後の選択肢とすべきだ。
→ これはそのとおりで、ほかにC言語のプリプロセッサの処理なども一種のメタプログラミングといえます。
( evalの評価は、無名サブルーチンへのリファレンスと比べて )30倍の速度差が出ている。
→これもそのとおりで、文字列をコンパイルして実行するため、evalは遅いです。
その2
宮川さんが弾さん意見にはだいたい同意はするけれど、evalを毎回ループしてベンチマークとるのはおかしいという指摘。
実際のメタプログラミングの手法を考えると、まずこういう風に subref を eval をつかったほうほうとそうでない純粋な無名関数とでbenchmarkの外側で定義して実行時コストを比較すべき。
eval自体は遅いけれど、サブルーチンを定義する最初の一回が遅いだけで、その後は速度的には同じになるということを示すベンチマークテスト。
その3
ひがさんが、メタプログラミングの良いところと悪いところについて語る。
高位ロジックが、高度であればあるほど、最終的に何が起こるのかが、わからなくなってしまうことです。黒魔術的といいましょうか。
だから、メタプログラミングは、結果が予想できる範囲にとどめておいたほうが良い。強力なため、乱用は厳禁ということです。
メタプログラミングは複雑になると、デバッグをするのもコードを読むのも大変。
サイト案内
2009-02-17
メソッドチェーンは非常にややこしいと思う。
以下のようなメソッドチェーンは読むのが困難だ。
my $loader = Loader->new; my $book = $loader->load( 'Book' )->build
loadメソッドが自分自身( $loader )を返却して、そこからbuildが呼ばれたのか、他のオブジェクトが返却され、そこからbuildがよばれたのかがわからない。
2009-02-16
ファイル名を実行環境のOSでのファイル名に変換する。
OSに依存しないファイル名を作成するには、File::Spec->catfile を使えばよいのでした。
今回は、あるファイル表現を実行環境のOSのファイル名に変換する方法を解説します。
設定ファイルなどでファイル名を指定するときは、Unixでのファイル表現を使う場合が多いです。
# Unixでのファイル表現 dir1/dir2/file.txt
Windows上でこのUnixのファイル表現ををWindowsのファイル表現に変換したいとします。以下のようにするのが簡単です。
File::Specの、splitdirメソッドで、$unix_pathを個別の部分に分解します。それを、catfileメソッドでつなげます。catfileは、分解されたファイル名を\で結合してくれます。
use File::Spec; my $unix_path = 'dir1/dir2/file.txt'; my $windows_path = File::Spec->catfile( File::Spec->splitdir( $unix_path ) );
実行可能なサンプル
use strict; use warnings; use File::Spec; my $unix_path = 'dir1/dir2/file.txt'; my $windows_path = File::Spec->catfile( File::Spec->splitdir( $unix_path ) ); print "1. ウインドウズのファイルパスに変換\n"; print $windows_path, "\n"; __END__
Windowsでの出力結果
1. ウインドウズのファイルパスに変換 dir1\dir2\file.txt