Sometimes you *don't* want circular checking
I use the nifty Data::Rmap to "flatten" DateTime objects into strings so they can be exported to JSON and handled outside Perl. But due to circular checking in Data::Rmap, this:
$ perl -MData::Rmap=:all -MData::Dump \
-e'$d = DateTime->now; $doc = [$d, $d];
rmap_ref { $_ = $_->ymd if UNIVERSAL::isa($_, "DateTime") } $doc;
dd $doc'
produces something like this:
["2010-10-01", ...unconverted DateTime object...]
For now I work around this by defeating Data::Rmap's circular checking, though I wonder if there's a better way.
$ perl -MData::Rmap=:all -MData::Dump \
-e'$d = DateTime->now; $doc = [$d, $d];
rmap_ref { $_[0]{seen} = {}; $_ = $_->ymd if UNIVERSAL::isa($_, "DateTime") } $doc;
dd $doc'
will correctly produce:
["2010-10-01", "2010-10-01"]
I've had to deal with this before (because I always use DateTime objects) and I think the best method is to use the JSON module to jsut do the conversion for you. Here is your example:
perl -MDateTime -MJSON=2 -e '$d=DateTime->now;$doc=[$d,$d];{local *DateTime::TO_JSON=sub{$_[0]->ymd};print JSON->new->convert_blessed->encode($doc);}'
And in a more readable multi-line:
use DateTime;
use JSON 2;
my $now = DateTime->now;
my $doc = [$now, $now];
my $encoder = JSON->new->convert_blessed;
{
# Add TO_JSON to DateTime for encoding
local *DateTime::TO_JSON = sub { $_[0]->ymd };
print $encoder->encode($doc);
}
@somethingdoug: Thanks for the comment. Maybe in this case JSON is suitable since I wanted to export to JSON anyway (though FYI, I ended up using PHP::Serialization for this project :). But I still something like Data::Rmap is the more general solution.
And the reason JSON works in this case is precisely because it doesn't do circular checking (because JSON can't handle circulars anyway).
$ perl -MJSON=2 -MData::Dump -e'$a=[1,2]; $a->[-1]=$a; $e=JSON->new->convert_blessed; dd $e->encode($a)'
Results in:
json text or perl structure exceeds maximum nesting level (max_depth set too low?) at (eval 5) line 153.