TT-2.15 で list-vmethod-fallback がうまくいってなさそう
SQL::Translator がうまくインストールできないと思っていろいろ調べたら,TT-2.15 でなにやら Stash の挙動がおかしくなっているようでした。
- SQL-Translator の RT
- http://rt.cpan.org/Public/Bug/Display.html?id=20047
- ↑の TT での RT(コメントはついていない)
- http://rt.cpan.org/Public/Bug/Display.html?id=20123
- ちょっと違う部位だけど関連してそげな TT の RT
- http://rt.cpan.org/Public/Bug/Display.html?id=19827
具体的には,「Automagic Promotion of Scalar to List for Virtual Methods」で書かれている機能がオブジェクトに対してうまく働きません。
その挙動を確かめるスクリプトを純粋化してみたのがこちら。
#!/usr/bin/perl use strict; use warnings; use Template; my $tt = Template->new(); $tt->process(\*DATA, { tokens => \&tokens }) || die $tt->error(), "\n"; sub tokens { my ($type, $count) = @_; if ($type eq 'obj') { return ( ( DummyObject->new() ) x $count ); } elsif ($type eq 'hash') { return ( ( { } ) x $count ); } else { return ( ( 'str' ) x $count ); } } package DummyObject; use overload '""' => sub { return 'str'; }, 'eq' => sub { return 0; }, ; sub new { bless {}, shift } package main; __DATA__ 1: [% tokens('str', 2).join(', ') %] 2: [% tokens('str', 1).join(', ') %] 3: [% tokens('hash', 2).join(', ') %] 4: [% tokens('hash', 1).join(', ') %] 5: [% tokens('obj', 2).join(', ') %] 6: [% tokens('obj', 1).join(', ') %] 7: [% FOREACH item IN tokens('obj', 1) %][% item %][% END %]
別に overload する必要もないんですが,一応してみました。で,eq も override してるのは,これを定義しておかないと Pure Perl 版 Template::Stash が line 685 の
my $atroot = ($root eq $self);
というところでコケてしまうんで,場当たりハックしたまでです。
結果がこちら。
1: str, str 2: str 3: HASH(0x8d45e84), HASH(0x8d45e84) 4: 5: obj, obj 6: 7: obj
4 や 6 でも 2 と同じように単一の結果を出してほしかったのですが出力されません。FOREACH でまわした 7 ではきちんと疑似リスト化してます。
自分なりに原因を考えてみました。一例として Template::Stash の sub _dotop() で line 763 あたりから
# failed to call object method, so try some fallbacks if (UNIVERSAL::isa($root, 'HASH') ) { if( defined($value = $root->{ $item })) { return $value unless ref $value eq 'CODE'; ## RETURN @result = &$value(@$args); } elsif ($value = $HASH_OPS->{ $item }) { @result = &$value($root, @$args); } # さもなくばどうするの〜? }
このように,たとえばハッシュベースのオブジェクトで join 等のメソッドが見つからない場合,@result が undef になるんですね。このへん外枠のロジックから見てあんまりうまくないような気がします。
RT に投げるべきかなぁと思いつつ自信がない*1んで寝かせ中…