class ActiveSupport::XMLConverter

:nodoc:

def become_array?(value)

def become_array?(value)
  value['type'] == 'array'
end

def become_content?(value)

def become_content?(value)
  value['type'] == 'file' || (value['__content__'] && (value.keys.size == 1 || value['__content__'].present?))
end

def become_empty_string?(value)

def become_empty_string?(value)
  # { "string" => true }
  # No tests fail when the second term is removed.
  value['type'] == 'string' && value['nil'] != 'true'
end

def become_hash?(value)

def become_hash?(value)
  !nothing?(value) && !garbage?(value)
end

def deep_to_h(value)

def deep_to_h(value)
  case value
    when Hash
      process_hash(value)
    when Array
      process_array(value)
    when String
      value
    else
      raise "can't typecast #{value.class.name} - #{value.inspect}"
  end
end

def garbage?(value)

def garbage?(value)
  # If the type is the only element which makes it then
  # this still makes the value nil, except if type is
  # an XML node(where type['value'] is a Hash)
  value['type'] && !value['type'].is_a?(::Hash) && value.size == 1
end

def initialize(xml, disallowed_types = nil)

def initialize(xml, disallowed_types = nil)
  @xml = normalize_keys(XmlMini.parse(xml))
  @disallowed_types = disallowed_types || DISALLOWED_TYPES
end

def normalize_keys(params)

def normalize_keys(params)
  case params
    when Hash
      Hash[params.map { |k,v| [k.to_s.tr('-', '_'), normalize_keys(v)] } ]
    when Array
      params.map { |v| normalize_keys(v) }
    else
      params
  end
end

def nothing?(value)

def nothing?(value)
  # blank or nil parsed values are represented by nil
  value.blank? || value['nil'] == 'true'
end

def process_array(value)

def process_array(value)
  value.map! { |i| deep_to_h(i) }
  value.length > 1 ? value : value.first
end

def process_content(value)

def process_content(value)
  content = value['__content__']
  if parser = ActiveSupport::XmlMini::PARSING[value['type']]
    parser.arity == 1 ? parser.call(content) : parser.call(content, value)
  else
    content
  end
end

def process_hash(value)

def process_hash(value)
  if value.include?('type') && !value['type'].is_a?(Hash) && @disallowed_types.include?(value['type'])
    raise DisallowedType, value['type']
  end
  if become_array?(value)
    _, entries = Array.wrap(value.detect { |k,v| not v.is_a?(String) })
    if entries.nil? || value['__content__'].try(:empty?)
      []
    else
      case entries
      when Array
        entries.collect { |v| deep_to_h(v) }
      when Hash
        [deep_to_h(entries)]
      else
        raise "can't typecast #{entries.inspect}"
      end
    end
  elsif become_content?(value)
    process_content(value)
  elsif become_empty_string?(value)
    ''
  elsif become_hash?(value)
    xml_value = Hash[value.map { |k,v| [k, deep_to_h(v)] }]
    # Turn { files: { file: #<StringIO> } } into { files: #<StringIO> } so it is compatible with
    # how multipart uploaded files from HTML appear
    xml_value['file'].is_a?(StringIO) ? xml_value['file'] : xml_value
  end
end

def to_h

def to_h
  deep_to_h(@xml)
end