bonar note

京都のエンジニア bonar の技術的なことや技術的でない日常のブログです。

List::TableMark 0.01 を coderepos に入れました

前から少しずつ考えていた、リストをテーブル風に扱うモジュールのプロトタイプをcodereposに入れました。

http://coderepos.org/share/changeset/13035

なんでこんなものを作ったかといいますと、テーブル的なレイアウトを扱う局面ってすごくあって、HTMLのtableタグとかもそうですが、ul, li の構造でliの要素数が固定の場合とか、カレンダーの表示とか、「特定の要素数で折り返して且つ行の最後まで行く」という仕組みが欲しいなと思っていました。
# あと Class::InsideOut を使ってみたかった

SYNOPSIS 丸コピーですが、使い方的には以下のような感じです。

    my $list = List::TableMark−>new(col => 7);
    $list−>push(undef(), undef());
    $list−>push(1..31);
    $list−>finish();

    my $bar = "−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−\n";
    my $output = "";
    foreach my $num (@$list) {
        $output .= $bar if $num−>is_table_start;
        $output .= sprintf("week %d | ", $num−>row)
            if $num−>is_row_start;

        $output .= $num−>is_empty
            ? ’−−|’
            : sprintf("%2d|", ($num−>value || 0))
            ;
        $output .= "\n" if $num−>is_row_end;
        $output .= $bar if $num−>is_table_end;
    }
    print $output;

    # output
    # −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
    # week 1 | −−|−−| 1| 2| 3| 4| 5|
    # week 2 |  6| 7| 8| 9|10|11|12|
    # week 3 | 13|14|15|16|17|18|19|
    # week 4 | 20|21|22|23|24|25|26|
    # week 5 | 27|28|29|30|31|−−|−−|
    # −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

    # you can also push reference to the list
    my $fruit = List::TableMark−>new(col => 3);
    $fruit−>push(
        { name => ’banana’ color => ’yellow’ },
        { name => ’applecolor => ’red’    },
        { name => ’lemmon’ color => ’yellow’ },
        { name => ’grape’  color => ’purple’ },
    );
    $fruit−>finish(); # push undef value to rest of the table
    foreach my $data (@$list) {
        my $ref = $data−>value; # get pushed refernce
        if (!$ref−>is_empty) {
            print $ref−>{name} . ’ ’;
        }
        else {
            print "−−− ";
        }
        print "\n" if $ref−>is_line_end;
    }
    # output:
    # banana apple lemmon
    # grape −−− −−−

横幅を指定してlistを作成してそこにデータをpushしていくと、特定の区切りでマークが付く、って感じです。配列のリファレンスを bless しているので、@$list で中身(List::TableMark−::Element の配列)が取れます。

データを取り出した後に、$data->value とかやらなくてもスカラーコンテキストで評価された時点で元の値として評価される、っていうのがかっこいいかなと思ったのですが、元のオブジェクトを取り出しづらくなりそうだし、豪快なoverloadは僕の手に負えない可能性大なので見送りました。

$list->push されたデータは List::TableMark−::Element にマークとともに入れられて保存されます。取り出したあとは is_* 系のメソッドでフラグの確認ができるのですが、hashで一気にとれるようにもなっています(markhash())。これはテンプレートエンジンに渡す際に簡単に書けるようにそうしてみました。

    my (@loop);
    foreach my $data (@$list) {
        my %temp = $data->markhash();
        $temp{value} = $data->value;
        push @loop, \%temp;
    }
    $template->param(loop => \@loop);

結構探して確認したのですが、似たようなモジュールが既にあったら誰かツッコミお願いします!

今日一日他の方のコードを結構見ていたのですが、すごい勉強になりますね。特にテストの書き方とか僕はすごく未熟だなと、Test::More 全然使いこなせてないなと、いやむしろテスト書いてないなと反省しました>< perlcritic が入っていればそのチェックもするっていうのは素敵ですね、真似しよう。