Subject: | XML::Twig::Elt->set_atts() destroys any existing attributes; set_att() fails silently on hashref |
From the documentation, one would think that the only difference between
set_att() and set_atts() is that the latter accepts hash references and
the former doesn't (and in fact, you'd think that set_atts() wouldn't
accept a list, even though it does). I saw no indication of any time
one might want to use set_att() instead of set_atts()... but a subtle
difference just bit me: set_atts() apparently destroys all existing
attributes on the element before adding the new ones.
This led to a sanity-questioning moment for me, since I found this by
inspecting output from my own project by eye, but the unit test covering
the code that generated the missing attribute passed. Fortunately, the
project is still relatively small and well-organized, so it didn't take
me too long to find the completely unrelated method that was causing the
damage.
While I was writing the Test::More entry that catches the issue, I
discovered a secondary issue with set_att(): namely that it fails in
absolute silence if handed a hashref. It doesn't throw an exception, it
doesn't spit out a warning, it just silently fails to change anything at
all. The attached file catches both issues.
These two interfaces are close enough in name that one would expect them
to either behave in the same way or fail noisily if they were switched
-- it's just too easy to add or a remove an 's' when typing. I would
ask that set_att() please either be updated to accept hashrefs, or croak
if fed one.
Subject: | test_set_atts.t |
#
# Check for XML::Twig::Elt->set_atts destroying existing attributes
#
use warnings; use strict;
use Test::More tests => 9;
BEGIN { use_ok('XML::Twig') };
my $twig = XML::Twig->new(
output_encoding => 'utf-8',
pretty_print => 'record'
);
my $sky;
my $xml = <<END;
<root>
<sky sun="yellow" cloud="white" />
</root>
END
my %atthash = ('color' => 'purple');
$twig->parse($xml);
$sky = $twig->root->first_child('sky');
$sky->set_att('color' => 'blue');
is($sky->att('sun'),'yellow',
'set_att(key => value) preserves previous attributes');
is($sky->att('color'),'blue','set_att(key => value) sets new attribute');
$twig->parse($xml);
$sky = $twig->root->first_child('sky');
$sky->set_att(\%atthash);
is($sky->att('sun'),'yellow',
'set_att(\%hash) preserves previous attributes');
is($sky->att('color'),'blue','set_att(\%hash) sets new attribute');
$twig->parse($xml);
$sky = $twig->root->first_child('sky');
$sky->set_atts('color' => 'cerulean');
is($sky->att('sun'),'yellow',
'set_atts(key => value) preserves previous attributes');
is($sky->att('color'),'cerulean','set_atts(key => value) sets new attribute');
$twig->parse($xml);
$sky = $twig->root->first_child('sky');
$sky->set_atts(\%atthash);
is($sky->att('sun'),'yellow','set_atts(\%hash) preserves previous attributes');
is($sky->att('color'),'purple','set_atts(\%hash) sets new attribute');
__DATA__