File::Tempオブジェクトはファイルハンドルであり、同時にoverloadを使用すると文字列に見える、という妙なオブジェクトなんですね。なので、以下のコードは無用
my $expect = 'hogehoge'; my $out = File::Temp->new; diag $out; open my $fh, '>', $out; # ここ print $fh $expect; close $fh; my $contents < io $out; is $contents, $expect;

File::Temp->new()した段階ですでにFileHandleオブジェクトになっているはう。なのでこいつに直接書き込んじゃうのが吉
my $expect = 'hogehoge'; my $out = File::Temp->new; diag $out; print $out $expect; close $out; my $contents < io $out; is $contents, $expect;
で、undefined云々はどういうことかというと、File::Tempの問題というよりは受け手のIO::Allの問題。io $outってやると、$outはGLOBなので、ハンドルとして認識してしまうのです。でもclose $outしてるからハンドルはすでに使えないわけで・・・
それだけの問題なので、ここの直し方は簡単。$outを無理矢理文字列にしてしまえばOK
my $contents < io "$out"; is $contents, $expect;
そしてさらに、テンポラリファイルがたまってしまうなら、UNLINKオプションをつけちゃいましょう
my $out = File::Temp->new( UNLINK => 1);
このUNLINKオプションをつけておけば、File::Tempオブジェクトがスコープ外に達したときに自動的に一時ファイルが削除されます。closeしても平気だけど、スコープ外にでちゃうと操作できないのでそこだけ要注意