patch to Hash#to_xml re lighthouse ticket #2521

Folks

I've just uploaded a patch which fixes the problem described in ticket
#2521. Some of us are having problems integrating ActiveResource with
non-Rails systems because the default behaviour of ActiveResource#save
is to use the default behaviour of Hash#to_xml. The current
documentation states that the default value of :dasherize is false,
but in fact it's true. Therefore when we save our resources all
underscores in attribute names are converted into dashes in XML
element names, which causes a problem if the receiving application
expects to see underscores in element names. There is no way to change
this behaviour because ActiveResource#save doesn't have the right
options.

Rather than change ActiveResource#save to feed in :dasherize=>false
to the options to Hash#to_xml, which would be a quick bodge, I've gone
to the source of the problem by changing Hash#rename_key, which is
called by Hash#to_xml. Hash#rename_key now respects class attributes
on Hash which determine the default behaviour of both :dasherize
and :camelize.

The reason for doing it like this, rather than simply changing the
default for :dasherize inside Hash#rename_key is that many other tests
in the Rails test suite expect the default value of :dasherize in
Hash#to_xml to be true. This probably happened because incoming XML
with dashes in element names must be converted to underscores in Rails
attribute names, and for some reason people have assumed that the
converse is also true; that underscores in Rails attribute names must
be converted into dashes in XML element names. Certainly all the tests
assume this is the case and for Rails<->Rails this is fine, but for
Rails<->Non-Rails it isn't. The default behaviour should be to leave
underscores in Rails attribute names as underscores in XML element
names, unless instructed otherwise. This would not alter the behaviour
of Rails<->Rails REST interactions because dashes in XML element names
always become underscores in Rails attribute names, but it would make
life easier for those of us who have to integrate Rails<->Non-Rails.

However many tests, and probably lots of code, assume that :dasherize
defaults to true. So I've added the class attribute
Hash.dasherize_xml, and set it to true by default, but now people can
change it to false if they need to. Since Hash#rename_key also
responds to the :camelize option, I've added the class attribute
Hash.camelize_xml, and defaulted it to false because that's how
existing code works. The net result is that existing code, and all
tests run fine, but people have the option to change the default
values of :dasherize and :camelize if they need to, and also at some
point in the future it's very easy to set the Rails default
for :dasherize to false which is what it should be.

The current tests do not test for default values for either :dasherize
or :camelize and they made assumptions about the default values of the
other. So while testing :dasherize it was assumed that the default
for :camelize was false, and while testing :camelize it was assumed
that the default value of :dasherize was false. But :camelize takes
precedence over :dasherize, (no test for that either), so the
incorrect assumption was not picked up.

I've changed the tests so that :camelize is held to false while
testing :dasherize and that :dasherize is held to false while
testing :camelize. I've also added tests for the defaults and a test
for :camelize=>true and :dasherize=>true together so the order of
precedence is now defined in a test.

I've updated the documentation on ActiveResource#to_xml so that it now
correctly describes the default value of :dasherize as true and
informs people how to change the default if they need to. I've also
added a mention of :camelize, which was undocumented in
ActiveResource#to_xml.

Summary: This patch will not upset any existing code, but it does give
people using REST to integrate Rails with non-Rails applications the
ability to fix the problem with underscores in attribute names being
converted to dashes in XML element names when the resource is saved.

Possible Enhancements: Thinking about it some more, it would be nice
to have the option to apply XSLT to the XML going back and forth on
ActiveResource. That would add more flexibility when integrating with
non-Rails applications. Comments please.