HTML::Shakan で choices が消えて困ってるの巻

[追記:2010-07-17] さっそく対応してもらいましたので、HTML::Shakan 0.06 からこの記事のテストは通るようになりました


はい、なんかタイトルで言い切った感がありますけど、だらだらと説明しちゃいますよ!

HTML::Shakan とは

id:tokuhirom さん作で Django のフォームっぽい感じの素敵な form generator / validator という感じのものです。
詳しくは日本語のドキュメント付属してるから、そっちを読むと良いよ。

どういう時に困るか

HTML::Shakan の SYNOPSIS にあるように、毎回 form を定義するような使い方をするならば困らないのですが、HTML::Shakan::Declare で form を作って、使うときは get して使いまわすような場合に困ったことになります。

とかいってもよく伝わらないでしょうから、テストケースを書きました。

{
    package My::Form;
    use HTML::Shakan::Declare;
    form 'my_form' => (
        ChoiceField(
            name    => 'foo',
            widget  => 'select',
            choices => [qw/1 one 2 two 3 three/],
        ),
        ChoiceField(
            name    => 'bar',
            widget  => 'radio',
            choices => [qw/1 one 2 two 3 three/],
        ),
    );
}

{
    package main;
    use strict;
    use warnings;
    use CGI;
    use Test::More;

    is form('my_form')->render(), form('my_form')->render();

    sub form {
        my $name = shift;
        return My::Form->get(
            $name => (
                request => CGI->new(),
            ),
        );
    }
    done_testing;
}

現状の HEAD ですとこのテストはこけてしまいます。

なぜ消えたし

HTML::Shakan::Widgets::Simple の中で choices を消すような操作をしているからですね。
widget_select() と widget_radio() がそれにあたります。

結局どうすれば

そもそも Widget は差し替え可能な作りになっているので、そこを差し替えれば良いのですが、Widget で form の定義が書き換えられて嬉しいケースっていうのが特に思い浮かばなかったので、僕は以下のような感じで凌いでいます。*1

diff --git a/lib/HTML/Shakan/Declare.pm b/lib/HTML/Shakan/Declare.pm
index 3edf8ac..45249dd 100644
--- a/lib/HTML/Shakan/Declare.pm
+++ b/lib/HTML/Shakan/Declare.pm
@@ -3,6 +3,7 @@ use strict;
 use warnings;
 use base 'Exporter';
 use HTML::Shakan ();
+use Storable qw/dclone/;
 
 our @EXPORT = qw(form get);
 
@@ -23,7 +24,7 @@ sub get {
     my ($class, $name, %args) = @_;
     $class = ref $class || $class;
     return HTML::Shakan->new(
-        fields => $FORMS->{$class}->{$name},
+        fields => dclone $FORMS->{$class}->{$name},
         %args,
     );
 }

というわけで

良かったら取り込んでもらえると嬉しいです > id:tokuhirom さん
なんか誤解していたり、普通こうやるよね!みたいなのあったら教えてください!

*1:実際は mokey patch ですよ