require'time'require'base64'require'bigdecimal'require'active_support/core_ext/module/delegation'require'active_support/core_ext/string/inflections'require'active_support/core_ext/date_time/calculations'moduleActiveSupport# = XmlMini## To use the much faster libxml parser:# gem 'libxml-ruby', '=0.9.7'# XmlMini.backend = 'LibXML'moduleXmlMiniextendself# This module decorates files deserialized using Hash.from_xml with# the <tt>original_filename</tt> and <tt>content_type</tt> methods.moduleFileLike#:nodoc:attr_writer:original_filename,:content_typedeforiginal_filename@original_filename||'untitled'enddefcontent_type@content_type||'application/octet-stream'endendDEFAULT_ENCODINGS={"binary"=>"base64"}unlessdefined?(DEFAULT_ENCODINGS)TYPE_NAMES={"Symbol"=>"symbol","Fixnum"=>"integer","Bignum"=>"integer","BigDecimal"=>"decimal","Float"=>"float","TrueClass"=>"boolean","FalseClass"=>"boolean","Date"=>"date","DateTime"=>"dateTime","Time"=>"dateTime","Array"=>"array","Hash"=>"hash"}unlessdefined?(TYPE_NAMES)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|::Base64.encode64(binary)},"yaml"=>Proc.new{|yaml|yaml.to_yaml}}unlessdefined?(FORMATTING)# TODO use regexp instead of Date.parseunlessdefined?(PARSING)PARSING={"symbol"=>Proc.new{|symbol|symbol.to_s.to_sym},"date"=>Proc.new{|date|::Date.parse(date)},"datetime"=>Proc.new{|time|Time.xmlschema(time).utcrescue::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.to_s.strip)},"string"=>Proc.new{|string|string.to_s},"yaml"=>Proc.new{|yaml|YAML::load(yaml)rescueyaml},"base64Binary"=>Proc.new{|bin|::Base64.decode64(bin)},"binary"=>Proc.new{|bin,entity|_parse_binary(bin,entity)},"file"=>Proc.new{|file,entity|_parse_file(file,entity)}}PARSING.update("double"=>PARSING["float"],"dateTime"=>PARSING["datetime"])enddelegate:parse,:to=>:backenddefbackendcurrent_thread_backend||@backendenddefbackend=(name)backend=name&&cast_backend_name_to_module(name)self.current_thread_backend=backendifcurrent_thread_backend@backend=backendenddefwith_backend(name)old_backend=current_thread_backendself.current_thread_backend=name&&cast_backend_name_to_module(name)yieldensureself.current_thread_backend=old_backendenddefto_tag(key,value,options)type_name=options.delete(:type)merged_options=options.merge(:root=>key,:skip_instruct=>true)ifvalue.is_a?(::Method)||value.is_a?(::Proc)ifvalue.arity==1value.call(merged_options)elsevalue.call(merged_options,key.to_s.singularize)endelsifvalue.respond_to?(:to_xml)value.to_xml(merged_options)elsetype_name||=TYPE_NAMES[value.class.name]type_name||=value.class.nameifvalue&&!value.respond_to?(:to_str)type_name=type_name.to_siftype_nametype_name="dateTime"iftype_name=="datetime"key=rename_key(key.to_s,options)attributes=options[:skip_types]||type_name.nil??{}:{:type=>type_name}attributes[:nil]=trueifvalue.nil?encoding=options[:encoding]||DEFAULT_ENCODINGS[type_name]attributes[:encoding]=encodingifencodingformatted_value=FORMATTING[type_name]&&!value.nil??FORMATTING[type_name].call(value):valueoptions[:builder].tag!(key,formatted_value,attributes)endenddefrename_key(key,options={})camelize=options[:camelize]dasherize=!options.has_key?(:dasherize)||options[:dasherize]ifcamelizekey=true==camelize?key.camelize:key.camelize(camelize)endkey=_dasherize(key)ifdasherizekeyendprotecteddef_dasherize(key)# $2 must be a non-greedy regex for this to workleft,middle,right=/\A(_*)(.*?)(_*)\Z/.match(key.strip)[1,3]"#{left}#{middle.tr('_ ','--')}#{right}"end# TODO: Add support for other encodingsdef_parse_binary(bin,entity)#:nodoc:caseentity['encoding']when'base64'::Base64.decode64(bin)elsebinendenddef_parse_file(file,entity)f=StringIO.new(::Base64.decode64(file))f.extend(FileLike)f.original_filename=entity['name']f.content_type=entity['content_type']fendprivatedefcurrent_thread_backendThread.current[:xml_mini_backend]enddefcurrent_thread_backend=(name)Thread.current[:xml_mini_backend]=name&&cast_backend_name_to_module(name)enddefcast_backend_name_to_module(name)ifname.is_a?(Module)nameelserequire"active_support/xml_mini/#{name.downcase}"ActiveSupport.const_get("XmlMini_#{name}")endendendXmlMini.backend='REXML'end