Perl Hackers Hub

第40回 Perl開発への動的な型制約の導入(3)

この記事を読むのに必要な時間:およそ 4 分

(1)こちら⁠2)こちらから。

動的な型制約の応用例

前節までで,Perlで動的な型制約を導入する方法の基本は紹介し終えました。本節では,動的な型制約をアプリケーションで応用した例を紹介します。

アプリケーションの仕様を型として定義する

アプリケーションには,満たすべき仕様があります。たとえばユーザー名は3文字以上100文字以内である必要がある,ブログの状態は公開か非公開のどちらかであるなどです。Webアプリケーションとしてユーザーから入力を受け付けるときも,開発者がコマンドラインを使いデータを入れるときも,どんなときでも仕様を満たさない不整合なデータを作りたくありません。そのためには,たとえばデータベースレベルで制限をかけるなど,さまざまな方法が考えられます。ただ,簡単な仕様なら,これまで紹介した動的な型制約を利用して実現できます。

リスト3は,ブログアプリケーションの仕様を型として定義し,制約をかけることでチェックしている例です。(1)でブログのタイトルは3文字以上100文字以内という仕様を型として定義しています。(2)はブログの状態は公開を表すpublicか非公開を表すprivateのどちらかであると定義しています。(3)はブログデータを更新するメソッドで,定義したBlog::TitleやBlog::Statusを利用して引数に制約をかけています。これで,update_blogに変なデータを渡したとしても,仕様を満たさないデータが作られることはありません。

リスト3 仕様を型として定義する

package Blog;

use Smart::Args;
use Mouse::Util::TypeConstraints;

subtype 'Blog::Title',                           
    => as 'Str'                                  
    => where {                                   
        3 <= length($_) && length($_) <= 100;    
    }                                            ┣(1)
    => message {                                 
        "$_ is not valid blog title";            
    };                                           

enum 'Blog::Status' => [qw(public private)];  ━(2)

sub update_blog {                                
    args my $class => 'ClassName',               
         my $blog_id => 'Int',                   
         my $title => 'Blog::Title',             ┣(3)
         my $status => 'Blog::Status';           
    # 渡されたデータでのブログデータの更新処理   
    ...                                          
}                                                

この例のように,定義した型とSmart::Argsを使ってロジックの関数の引数に型制約をかけておけば,単純な仕様であれば引数を間違えて不整合なデータを作ってしまうことを防げます。もちろんユーザーの入力を受け付ける場合,そのまま関数に渡すとユーザーにとって意味のないSmart::Argsのエラーが表示されるため,ユーザーを混乱させてしまいます。そのため使いやすさの観点からは,関数に渡す前にユーザーの入力が正しいかどうかをチェックし,誤っていた場合は適切なフィードバックを返すということを別に行う必要があります。

型制約でユーザーの入力を制限する

先ほど,使いやすさの観点からは,関数に渡す前にユーザーの入力が正しいかどうかをチェックし,誤っていた場合は適切なフィードバックを返すということを別に行う必要があると説明しました。もし返すべきフィードバックが単純なものであれば,型制約を用いてチェックする方法もあります。ユーザーから受け取った入力が型制約を満たすかをチェックし,満たさない場合にフィードバックを返すという方法です。

型制約を満たすかどうかを真偽値で取得できれば,このようなチェックを行えるはずです。この方法を実現するには,Mouse::Util::TypeConstraintsを利用します。Mouse::Util::TypeConstraintsにはfind_type_constraintという型を取得するユーティリティがあり,これを用いると型のオブジェクトを取得できます。さらにそのオブジェクトからcheckメソッドを呼ぶと,型制約を満たすかを真偽値で返してくれます。

次のコードは,前項で定義したBlog::Title型とfind_type_constraintを利用して,ユーザーの入力をチェックする例です。

use Mouse::Util::TypeConstraints;
my $input = ...;

my $is_valid = find_type_constraint('Blog::Title')-
>check($input);  ━(1)
if (!$is_valid) {
    # ユーザーにエラーメッセージを返す
}

(1)のように呼び出せば,$inputBlog::Title型を満たすなら真が,満たさないなら偽が$is_validに代入されます。偽の場合にユーザーにフィードバックを返せば,最低限のユーザー入力のチェックを行えます。

著者プロフィール

柴崎優季(しばざきゆうき)

1989年福井県生まれ。株式会社はてな所属。

Webアプリケーションエンジニアとして,はてなブログなどのWebサービスの開発に携わってきた。

Twitter:@shiba_yu36
Blog:http://blog.shibayu36.org/

コメント

コメントの記入