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