diff options
Diffstat (limited to 'activesupport/lib/active_support/core_ext/hash')
-rw-r--r-- | activesupport/lib/active_support/core_ext/hash/conversions.rb | 149 |
1 files changed, 13 insertions, 136 deletions
diff --git a/activesupport/lib/active_support/core_ext/hash/conversions.rb b/activesupport/lib/active_support/core_ext/hash/conversions.rb index c882434f78..14e5d2f8ac 100644 --- a/activesupport/lib/active_support/core_ext/hash/conversions.rb +++ b/activesupport/lib/active_support/core_ext/hash/conversions.rb @@ -1,3 +1,4 @@ +require 'active_support/xml_mini' require 'active_support/time' require 'active_support/core_ext/array/wrap' require 'active_support/core_ext/hash/reverse_merge' @@ -5,79 +6,6 @@ require 'active_support/core_ext/object/blank' require 'active_support/core_ext/string/inflections' class Hash - # This module exists to decorate files deserialized using Hash.from_xml with - # the <tt>original_filename</tt> and <tt>content_type</tt> methods. - module FileLike #:nodoc: - attr_writer :original_filename, :content_type - - def original_filename - @original_filename || 'untitled' - end - - def content_type - @content_type || 'application/octet-stream' - end - end - - XML_TYPE_NAMES = { - "Symbol" => "symbol", - "Fixnum" => "integer", - "Bignum" => "integer", - "BigDecimal" => "decimal", - "Float" => "float", - "TrueClass" => "boolean", - "FalseClass" => "boolean", - "Date" => "date", - "DateTime" => "datetime", - "Time" => "datetime" - } unless defined?(XML_TYPE_NAMES) - - XML_FORMATTING = { - "symbol" => Proc.new { |symbol| symbol.to_s }, - "date" => Proc.new { |date| date.to_s(:db) }, - "datetime" => Proc.new { |time| time.xmlschema }, - "binary" => Proc.new { |binary| ActiveSupport::Base64.encode64(binary) }, - "yaml" => Proc.new { |yaml| yaml.to_yaml } - } unless defined?(XML_FORMATTING) - - # TODO: use Time.xmlschema instead of Time.parse; - # use regexp instead of Date.parse - unless defined?(XML_PARSING) - XML_PARSING = { - "symbol" => Proc.new { |symbol| symbol.to_sym }, - "date" => Proc.new { |date| ::Date.parse(date) }, - "datetime" => Proc.new { |time| ::Time.parse(time).utc rescue ::DateTime.parse(time).utc }, - "integer" => Proc.new { |integer| integer.to_i }, - "float" => Proc.new { |float| float.to_f }, - "decimal" => Proc.new { |number| BigDecimal(number) }, - "boolean" => Proc.new { |boolean| %w(1 true).include?(boolean.strip) }, - "string" => Proc.new { |string| string.to_s }, - "yaml" => Proc.new { |yaml| YAML::load(yaml) rescue yaml }, - "base64Binary" => Proc.new { |bin| ActiveSupport::Base64.decode64(bin) }, - "binary" => Proc.new do |bin, entity| - case entity['encoding'] - when 'base64' - ActiveSupport::Base64.decode64(bin) - # TODO: Add support for other encodings - else - bin - end - end, - "file" => Proc.new do |file, entity| - f = StringIO.new(ActiveSupport::Base64.decode64(file)) - f.extend(FileLike) - f.original_filename = entity['name'] - f.content_type = entity['content_type'] - f - end - } - - XML_PARSING.update( - "double" => XML_PARSING["float"], - "dateTime" => XML_PARSING["datetime"] - ) - end - # Returns a string containing an XML representation of its receiver: # # {"foo" => 1, "bar" => 2}.to_xml @@ -130,62 +58,19 @@ class Hash require 'builder' unless defined?(Builder) options = options.dup - options[:indent] ||= 2 - options.reverse_merge!({ :builder => Builder::XmlMarkup.new(:indent => options[:indent]), - :root => "hash" }) - options[:builder].instruct! unless options.delete(:skip_instruct) - root = rename_key(options[:root].to_s, options) + options[:indent] ||= 2 + options[:root] ||= "hash" + options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent]) - options[:builder].__send__(:method_missing, root) do - each do |key, value| - case value - when ::Hash - value.to_xml(options.merge({ :root => key, :skip_instruct => true })) - when ::Array - value.to_xml(options.merge({ :root => key, :children => key.to_s.singularize, :skip_instruct => true})) - when ::Method, ::Proc - # If the Method or Proc takes two arguments, then - # pass the suggested child element name. This is - # used if the Method or Proc will be operating over - # multiple records and needs to create an containing - # element that will contain the objects being - # serialized. - if 1 == value.arity - value.call(options.merge({ :root => key, :skip_instruct => true })) - else - value.call(options.merge({ :root => key, :skip_instruct => true }), key.to_s.singularize) - end - else - if value.respond_to?(:to_xml) - value.to_xml(options.merge({ :root => key, :skip_instruct => true })) - else - type_name = XML_TYPE_NAMES[value.class.name] + builder = options[:builder] + builder.instruct! unless options.delete(:skip_instruct) - key = rename_key(key.to_s, options) - - attributes = options[:skip_types] || value.nil? || type_name.nil? ? { } : { :type => type_name } - if value.nil? - attributes[:nil] = true - end + root = ActiveSupport::XmlMini.rename_key(options[:root].to_s, options) - options[:builder].tag!(key, - XML_FORMATTING[type_name] ? XML_FORMATTING[type_name].call(value) : value, - attributes - ) - end - end - end - - yield options[:builder] if block_given? + builder.__send__(:method_missing, root) do + each { |key, value| ActiveSupport::XmlMini.to_tag(key, value, options) } + yield builder if block_given? end - - 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 class << self @@ -213,12 +98,8 @@ class Hash end elsif value.has_key?("__content__") content = value["__content__"] - if parser = XML_PARSING[value["type"]] - if parser.arity == 2 - XML_PARSING[value["type"]].call(content, value) - else - XML_PARSING[value["type"]].call(content) - end + if parser = ActiveSupport::XmlMini::PARSING[value["type"]] + parser.arity == 1 ? parser.call(content) : parser.call(content, value) else content end @@ -244,11 +125,7 @@ class Hash end when 'Array' value.map! { |i| typecast_xml_value(i) } - case value.length - when 0 then nil - when 1 then value.first - else value - end + value.length > 1 ? value : value.first when 'String' value else |