Permalink
Browse files

Added a :camelize option to ActiveRecord and Hash to_xml serializatio…

…n and from_xml deserialization

Signed-off-by: Michael Koziarski <michael@koziarski.com>
  • Loading branch information...
Bruce Krysiak authored and NZKoz committed Dec 9, 2008
1 parent 96b815d commit aa5cdb0d47fb5484bfdde8244df7efeb2175bf3a
@@ -23,11 +23,12 @@ module Serialization
# </topic>
#
# This behavior can be controlled with <tt>:only</tt>, <tt>:except</tt>,
# <tt>:skip_instruct</tt>, <tt>:skip_types</tt> and <tt>:dasherize</tt>.
# <tt>:skip_instruct</tt>, <tt>:skip_types</tt>, <tt>:dasherize</tt> and <tt>:camelize</tt> .
# The <tt>:only</tt> and <tt>:except</tt> options are the same as for the
# +attributes+ method. The default is to dasherize all column names, but you
# can disable this setting <tt>:dasherize</tt> to +false+. To not have the
# column type included in the XML output set <tt>:skip_types</tt> to +true+.
# can disable this setting <tt>:dasherize</tt> to +false+. Setting <tt>:camelize</tt>
# to +true+ will camelize all column names - this also overrides <tt>:dasherize</tt>.
# To not have the column type included in the XML output set <tt>:skip_types</tt> to +true+.
#
# For instance:
#
@@ -178,13 +179,22 @@ def builder
def root
root = (options[:root] || @record.class.to_s.underscore).to_s
dasherize? ? root.dasherize : root
reformat_name(root)
end
def dasherize?
!options.has_key?(:dasherize) || options[:dasherize]
end
def camelize?
options.has_key?(:camelize) && options[:camelize]
end
def reformat_name(name)
name = name.camelize if camelize?
dasherize? ? name.dasherize : name
end
def serializable_attributes
serializable_attribute_names.collect { |name| Attribute.new(name, @record) }
end
@@ -212,16 +222,15 @@ def add_procs
def add_tag(attribute)
builder.tag!(
dasherize? ? attribute.name.dasherize : attribute.name,
reformat_name(attribute.name),
attribute.value.to_s,
attribute.decorations(!options[:skip_types])
)
end
def add_associations(association, records, opts)
if records.is_a?(Enumerable)
tag = association.to_s
tag = tag.dasherize if dasherize?
tag = reformat_name(association.to_s)
if records.empty?
builder.tag!(tag, :type => :array)
else
@@ -31,6 +31,13 @@ def test_should_allow_undasherized_tags
assert_match %r{<created_at}, @xml
end
def test_should_allow_camelized_tags
@xml = Contact.new.to_xml :root => 'xml_contact', :camelize => true
assert_match %r{^<XmlContact>}, @xml
assert_match %r{</XmlContact>$}, @xml
assert_match %r{<CreatedAt}, @xml
end
def test_should_include_yielded_additions
@xml = Contact.new.to_xml do |xml|
xml.creator "David"
@@ -94,8 +94,7 @@ def to_xml(options = {})
options.reverse_merge!({ :builder => Builder::XmlMarkup.new(:indent => options[:indent]),
:root => "hash" })
options[:builder].instruct! unless options.delete(:skip_instruct)
dasherize = !options.has_key?(:dasherize) || options[:dasherize]
root = dasherize ? options[:root].to_s.dasherize : options[:root].to_s
root = rename_key(options[:root].to_s, options)
options[:builder].__send__(:method_missing, root) do
each do |key, value|
@@ -122,7 +121,7 @@ def to_xml(options = {})
else
type_name = XML_TYPE_NAMES[value.class.name]
key = dasherize ? key.to_s.dasherize : key.to_s
key = rename_key(key.to_s, options)
attributes = options[:skip_types] || value.nil? || type_name.nil? ? { } : { :type => type_name }
if value.nil?
@@ -142,9 +141,16 @@ def to_xml(options = {})
end
def rename_key(key, options = {})
camelize = options.has_key?(:camelize) && options[:camelize]
dasherize = !options.has_key?(:dasherize) || options[:dasherize]
key = key.camelize if camelize
dasherize ? key.dasherize : key
end
module ClassMethods
def from_xml(xml)
typecast_xml_value(undasherize_keys(XmlMini.parse(xml)))
typecast_xml_value(unrename_keys(XmlMini.parse(xml)))
end
private
@@ -210,15 +216,15 @@ def typecast_xml_value(value)
end
end
def undasherize_keys(params)
def unrename_keys(params)
case params.class.to_s
when "Hash"
params.inject({}) do |h,(k,v)|
h[k.to_s.tr("-", "_")] = undasherize_keys(v)
h[k.to_s.underscore.tr("-", "_")] = unrename_keys(v)
h
end
when "Array"
params.map { |v| undasherize_keys(v) }
params.map { |v| unrename_keys(v) }
else
params
end
@@ -403,6 +403,13 @@ def test_one_level_dasherize_true
assert xml.include?(%(<name>David</name>))
end
def test_one_level_camelize_true
xml = { :name => "David", :street_name => "Paulina" }.to_xml(@xml_options.merge(:camelize => true))
assert_equal "<Person>", xml.first(8)
assert xml.include?(%(<StreetName>Paulina</StreetName>))
assert xml.include?(%(<Name>David</Name>))
end
def test_one_level_with_types
xml = { :name => "David", :street => "Paulina", :age => 26, :age_in_millis => 820497600000, :moved_on => Date.new(2005, 11, 15), :resident => :yes }.to_xml(@xml_options)
assert_equal "<person>", xml.first(8)

5 comments on commit aa5cdb0

@mdchaney

This comment has been minimized.

mdchaney replied Apr 8, 2009

Um, do you know how much code you broke by forcing “dasherize” upon us? I (and plenty of others) are using xml docs that are posted to an action, and taking advantage of the fact that the doc is busted out into a Hash that is added to params.

I have to either figure out how to persuade rails to set :dasherize to false, or go through a couple hundred lines of code and dasherize what I have. Either way, my code will only work on the latest version of rails.

This is a major change, and the default should always be to continue to do whatever was done historically, unless that historic functionality is broken.

@mdchaney

This comment has been minimized.

mdchaney replied Apr 8, 2009

My bad, it’s not “dasherize”. The issue is line 223 of hash/conversions.rb – adding “underscore”. Same problem, though, and a major change in functionality.

@NZKoz

This comment has been minimized.

Member

NZKoz replied Apr 9, 2009

Sounds like a bug, please file a ticket on lighthouse and assign it to me, ideally with a test case for what’s broken.

@NZKoz

This comment has been minimized.

Member

NZKoz replied Apr 9, 2009

We can push out a point release to address this.

@kvnsmth

This comment has been minimized.

kvnsmth replied May 4, 2009

Michael,
I created a patch for Hash#from_xml not working with all caps keys due to this commit and assigned it to you. https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/2604

Please sign in to comment.