diff options
Diffstat (limited to 'lib/soap/mapping/rubytypeFactory.rb')
-rw-r--r-- | lib/soap/mapping/rubytypeFactory.rb | 377 |
1 files changed, 200 insertions, 177 deletions
diff --git a/lib/soap/mapping/rubytypeFactory.rb b/lib/soap/mapping/rubytypeFactory.rb index 0a3f502dfe..3ebb799220 100644 --- a/lib/soap/mapping/rubytypeFactory.rb +++ b/lib/soap/mapping/rubytypeFactory.rb @@ -22,22 +22,28 @@ module Mapping class RubytypeFactory < Factory - TYPE_STRING = 'String' - TYPE_ARRAY = 'Array' - TYPE_REGEXP = 'Regexp' - TYPE_RANGE = 'Range' - TYPE_CLASS = 'Class' - TYPE_MODULE = 'Module' - TYPE_SYMBOL = 'Symbol' - TYPE_STRUCT = 'Struct' - TYPE_HASH = 'Map' - + TYPE_STRING = XSD::QName.new(RubyTypeNamespace, 'String') + TYPE_TIME = XSD::QName.new(RubyTypeNamespace, 'Time') + TYPE_ARRAY = XSD::QName.new(RubyTypeNamespace, 'Array') + TYPE_REGEXP = XSD::QName.new(RubyTypeNamespace, 'Regexp') + TYPE_RANGE = XSD::QName.new(RubyTypeNamespace, 'Range') + TYPE_CLASS = XSD::QName.new(RubyTypeNamespace, 'Class') + TYPE_MODULE = XSD::QName.new(RubyTypeNamespace, 'Module') + TYPE_SYMBOL = XSD::QName.new(RubyTypeNamespace, 'Symbol') + TYPE_STRUCT = XSD::QName.new(RubyTypeNamespace, 'Struct') + TYPE_HASH = XSD::QName.new(RubyTypeNamespace, 'Map') + def initialize(config = {}) @config = config @allow_untyped_struct = @config.key?(:allow_untyped_struct) ? @config[:allow_untyped_struct] : true @allow_original_mapping = @config.key?(:allow_original_mapping) ? @config[:allow_original_mapping] : false + @string_factory = StringFactory_.new(true) + @basetype_factory = BasetypeFactory_.new(true) + @datetime_factory = DateTimeFactory_.new(true) + @array_factory = ArrayFactory_.new(true) + @hash_factory = HashFactory_.new(true) end def obj2soap(soap_class, obj, info, map) @@ -47,48 +53,83 @@ class RubytypeFactory < Factory unless @allow_original_mapping return nil end - unless XSD::Charset.is_ces(obj, $KCODE) + param = @string_factory.obj2soap(SOAPString, obj, info, map) + if obj.class != String + param.extraattr[RubyTypeName] = obj.class.name + end + addiv2soapattr(param, obj, map) + when Time + unless @allow_original_mapping return nil end - encoded = XSD::Charset.encoding_conv(obj, $KCODE, XSD::Charset.encoding) - param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_STRING)) - mark_marshalled_obj(obj, param) - param.add('string', SOAPString.new(encoded)) - if obj.class != String + param = @datetime_factory.obj2soap(SOAPDateTime, obj, info, map) + if obj.class != Time param.extraattr[RubyTypeName] = obj.class.name end - addiv2soap(param, obj, map) + addiv2soapattr(param, obj, map) when Array unless @allow_original_mapping return nil end - arytype = Mapping.obj2element(obj) - if arytype.name - arytype.namespace ||= RubyTypeNamespace - else - arytype = XSD::AnyTypeName + param = @array_factory.obj2soap(nil, obj, info, map) + if obj.class != Array + param.extraattr[RubyTypeName] = obj.class.name end - if obj.instance_variables.empty? - param = SOAPArray.new(ValueArrayName, 1, arytype) - mark_marshalled_obj(obj, param) - obj.each do |var| - param.add(Mapping._obj2soap(var, map)) - end - else - param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_ARRAY)) - mark_marshalled_obj(obj, param) - ary = SOAPArray.new(ValueArrayName, 1, arytype) - obj.each do |var| - ary.add(Mapping._obj2soap(var, map)) - end - param.add('array', ary) - addiv2soap(param, obj, map) + addiv2soapattr(param, obj, map) + when NilClass + unless @allow_original_mapping + return nil end - if obj.class != Array + param = @basetype_factory.obj2soap(SOAPNil, obj, info, map) + addiv2soapattr(param, obj, map) + when FalseClass, TrueClass + unless @allow_original_mapping + return nil + end + param = @basetype_factory.obj2soap(SOAPBoolean, obj, info, map) + addiv2soapattr(param, obj, map) + when Integer + unless @allow_original_mapping + return nil + end + param = @basetype_factory.obj2soap(SOAPInt, obj, info, map) + param ||= @basetype_factory.obj2soap(SOAPInteger, obj, info, map) + param ||= @basetype_factory.obj2soap(SOAPDecimal, obj, info, map) + addiv2soapattr(param, obj, map) + when Float + unless @allow_original_mapping + return nil + end + param = @basetype_factory.obj2soap(SOAPDouble, obj, info, map) + if obj.class != Float param.extraattr[RubyTypeName] = obj.class.name end + addiv2soapattr(param, obj, map) + when Hash + unless @allow_original_mapping + return nil + end + if obj.respond_to?(:default_proc) && obj.default_proc + raise TypeError.new("cannot dump hash with default proc") + end + param = SOAPStruct.new(TYPE_HASH) + mark_marshalled_obj(obj, param) + if obj.class != Hash + param.extraattr[RubyTypeName] = obj.class.name + end + obj.each do |key, value| + elem = SOAPStruct.new # Undefined type. + elem.add("key", Mapping._obj2soap(key, map)) + elem.add("value", Mapping._obj2soap(value, map)) + param.add("item", elem) + end + param.add('default', Mapping._obj2soap(obj.default, map)) + addiv2soapattr(param, obj, map) when Regexp - param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_REGEXP)) + unless @allow_original_mapping + return nil + end + param = SOAPStruct.new(TYPE_REGEXP) mark_marshalled_obj(obj, param) if obj.class != Regexp param.extraattr[RubyTypeName] = obj.class.name @@ -119,9 +160,12 @@ class RubytypeFactory < Factory end end param.add('options', SOAPInt.new(options)) - addiv2soap(param, obj, map) + addiv2soapattr(param, obj, map) when Range - param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_RANGE)) + unless @allow_original_mapping + return nil + end + param = SOAPStruct.new(TYPE_RANGE) mark_marshalled_obj(obj, param) if obj.class != Range param.extraattr[RubyTypeName] = obj.class.name @@ -129,57 +173,42 @@ class RubytypeFactory < Factory param.add('begin', Mapping._obj2soap(obj.begin, map)) param.add('end', Mapping._obj2soap(obj.end, map)) param.add('exclude_end', SOAP::SOAPBoolean.new(obj.exclude_end?)) - addiv2soap(param, obj, map) - when Hash + addiv2soapattr(param, obj, map) + when Class unless @allow_original_mapping return nil end - if obj.respond_to?(:default_proc) && obj.default_proc - raise TypeError.new("cannot dump hash with default proc") - end - param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_HASH)) - mark_marshalled_obj(obj, param) - if obj.class != Hash - param.extraattr[RubyTypeName] = obj.class.name - end - obj.each do |key, value| - elem = SOAPStruct.new # Undefined type. - elem.add("key", Mapping._obj2soap(key, map)) - elem.add("value", Mapping._obj2soap(value, map)) - param.add("item", elem) - end - param.add('default', Mapping._obj2soap(obj.default, map)) - addiv2soap(param, obj, map) - when Class if obj.name.empty? raise TypeError.new("Can't dump anonymous class #{ obj }.") end - param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_CLASS)) + param = SOAPStruct.new(TYPE_CLASS) mark_marshalled_obj(obj, param) param.add('name', SOAPString.new(obj.name)) - addiv2soap(param, obj, map) + addiv2soapattr(param, obj, map) when Module + unless @allow_original_mapping + return nil + end if obj.name.empty? raise TypeError.new("Can't dump anonymous module #{ obj }.") end - param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_MODULE)) + param = SOAPStruct.new(TYPE_MODULE) mark_marshalled_obj(obj, param) param.add('name', SOAPString.new(obj.name)) - addiv2soap(param, obj, map) + addiv2soapattr(param, obj, map) when Symbol - param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_SYMBOL)) + unless @allow_original_mapping + return nil + end + param = SOAPStruct.new(TYPE_SYMBOL) mark_marshalled_obj(obj, param) param.add('id', SOAPString.new(obj.id2name)) - addiv2soap(param, obj, map) - when Exception - typestr = Mapping.name2elename(obj.class.to_s) - param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, typestr)) - mark_marshalled_obj(obj, param) - param.add('message', Mapping._obj2soap(obj.message, map)) - param.add('backtrace', Mapping._obj2soap(obj.backtrace, map)) - addiv2soap(param, obj, map) + addiv2soapattr(param, obj, map) when Struct - param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, TYPE_STRUCT)) + unless @allow_original_mapping + return nil + end + param = SOAPStruct.new(TYPE_STRUCT) mark_marshalled_obj(obj, param) param.add('type', ele_type = SOAPString.new(obj.class.to_s)) ele_member = SOAPStruct.new @@ -188,29 +217,23 @@ class RubytypeFactory < Factory Mapping._obj2soap(obj[member], map)) end param.add('member', ele_member) - addiv2soap(param, obj, map) + addiv2soapattr(param, obj, map) when IO, Binding, Continuation, Data, Dir, File::Stat, MatchData, Method, - Proc, Thread, ThreadGroup + Proc, Thread, ThreadGroup # from 1.8: Process::Status, UnboundMethod return nil when ::SOAP::Mapping::Object param = SOAPStruct.new(XSD::AnyTypeName) mark_marshalled_obj(obj, param) - setiv2soap(param, obj, map) # addiv2soap? - else - if obj.class.name.empty? - raise TypeError.new("Can't dump anonymous class #{ obj }.") - end - if check_singleton(obj) - raise TypeError.new("singleton can't be dumped #{ obj }") - end - type = Mapping.class2element(obj.class) - param = SOAPStruct.new(type) + addiv2soapattr(param, obj, map) + when Exception + typestr = Mapping.name2elename(obj.class.to_s) + param = SOAPStruct.new(XSD::QName.new(RubyTypeNamespace, typestr)) mark_marshalled_obj(obj, param) - if obj.class <= Marshallable - setiv2soap(param, obj, map) - else - setiv2soap(param, obj, map) # Should not be marshalled? - end + param.add('message', Mapping._obj2soap(obj.message, map)) + param.add('backtrace', Mapping._obj2soap(obj.backtrace, map)) + addiv2soapattr(param, obj, map) + else + param = unknownobj2soap(soap_class, obj, info, map) end param end @@ -218,26 +241,42 @@ class RubytypeFactory < Factory def soap2obj(obj_class, node, info, map) rubytype = node.extraattr[RubyTypeName] if rubytype or node.type.namespace == RubyTypeNamespace - rubytype2obj(node, map, rubytype) + rubytype2obj(node, info, map, rubytype) elsif node.type == XSD::AnyTypeName or node.type == XSD::AnySimpleTypeName - anytype2obj(node, map) + anytype2obj(node, info, map) else - unknowntype2obj(node, map) + unknowntype2obj(node, info, map) end end private - def check_singleton(obj) - unless singleton_methods_true(obj).empty? - return true + def addiv2soapattr(node, obj, map) + return if obj.instance_variables.empty? + ivars = SOAPStruct.new # Undefined type. + setiv2soap(ivars, obj, map) + node.extraattr[RubyIVarName] = ivars + end + + def unknownobj2soap(soap_class, obj, info, map) + if obj.class.name.empty? + raise TypeError.new("Can't dump anonymous class #{ obj }.") end singleton_class = class << obj; self; end - if !singleton_class.instance_variables.empty? or - !(singleton_class.ancestors - obj.class.ancestors).empty? - return true + if !singleton_methods_true(obj).empty? or + !singleton_class.instance_variables.empty? + raise TypeError.new("singleton can't be dumped #{ obj }") + end + if !(singleton_class.ancestors - obj.class.ancestors).empty? + typestr = Mapping.name2elename(obj.class.to_s) + type = XSD::QName.new(RubyTypeNamespace, typestr) + else + type = Mapping.class2element(obj.class) end - false + param = SOAPStruct.new(type) + mark_marshalled_obj(obj, param) + setiv2soap(param, obj, map) + param end if RUBY_VERSION >= '1.8.0' @@ -250,40 +289,54 @@ private end end - def rubytype2obj(node, map, rubytype) + def rubytype2obj(node, info, map, rubytype) + klass = rubytype ? Mapping.class_from_name(rubytype) : nil obj = nil - case node.class + case node when SOAPString - obj = string2obj(node, map, rubytype) - obj.replace(node.data) + return @string_factory.soap2obj(klass || String, node, info, map) + when SOAPDateTime + #return @datetime_factory.soap2obj(klass || Time, node, info, map) + klass ||= Time + t = node.to_time + arg = [t.year, t.month, t.mday, t.hour, t.min, t.sec, t.usec] + obj = t.gmt? ? klass.gm(*arg) : klass.local(*arg) + mark_unmarshalled_obj(node, obj) return true, obj when SOAPArray - obj = array2obj(node, map, rubytype) - node.soap2array(obj) do |elem| - elem ? Mapping._soap2obj(elem, map) : nil - end - return true, obj + return @array_factory.soap2obj(klass || Array, node, info, map) + when SOAPNil, SOAPBoolean, SOAPInt, SOAPInteger, SOAPDecimal, SOAPDouble + return @basetype_factory.soap2obj(nil, node, info, map) + when SOAPStruct + return rubytypestruct2obj(node, info, map, rubytype) + else + raise end + end - case node.type.name - when TYPE_STRING - obj = string2obj(node, map, rubytype) - obj.replace(node['string'].data) - setiv2obj(obj, node['ivars'], map) - when TYPE_ARRAY - obj = array2obj(node, map, rubytype) - node['array'].soap2array(obj) do |elem| - elem ? Mapping._soap2obj(elem, map) : nil - end - setiv2obj(obj, node['ivars'], map) + def rubytypestruct2obj(node, info, map, rubytype) + klass = rubytype ? Mapping.class_from_name(rubytype) : nil + obj = nil + case node.type + when TYPE_HASH + klass = rubytype ? Mapping.class_from_name(rubytype) : Hash + obj = create_empty_object(klass) + mark_unmarshalled_obj(node, obj) + node.each do |key, value| + next unless key == 'item' + obj[Mapping._soap2obj(value['key'], map)] = + Mapping._soap2obj(value['value'], map) + end + if node.key?('default') + obj.default = Mapping._soap2obj(node['default'], map) + end when TYPE_REGEXP klass = rubytype ? Mapping.class_from_name(rubytype) : Regexp obj = create_empty_object(klass) mark_unmarshalled_obj(node, obj) source = node['source'].string options = node['options'].data || 0 - obj.instance_eval { initialize(source, options) } - setiv2obj(obj, node['ivars'], map) + Regexp.instance_method(:initialize).bind(obj).call(source, options) when TYPE_RANGE klass = rubytype ? Mapping.class_from_name(rubytype) : Range obj = create_empty_object(klass) @@ -291,33 +344,13 @@ private first = Mapping._soap2obj(node['begin'], map) last = Mapping._soap2obj(node['end'], map) exclude_end = node['exclude_end'].data - obj.instance_eval { initialize(first, last, exclude_end) } - setiv2obj(obj, node['ivars'], map) - when TYPE_HASH - unless @allow_original_mapping - return false - end - klass = rubytype ? Mapping.class_from_name(rubytype) : Hash - obj = create_empty_object(klass) - mark_unmarshalled_obj(node, obj) - node.each do |key, value| - next unless key == 'item' - obj[Mapping._soap2obj(value['key'], map)] = - Mapping._soap2obj(value['value'], map) - end - if node.key?('default') - obj.default = Mapping._soap2obj(node['default'], map) - end - setiv2obj(obj, node['ivars'], map) + Range.instance_method(:initialize).bind(obj).call(first, last, exclude_end) when TYPE_CLASS obj = Mapping.class_from_name(node['name'].data) - setiv2obj(obj, node['ivars'], map) when TYPE_MODULE obj = Mapping.class_from_name(node['name'].data) - setiv2obj(obj, node['ivars'], map) when TYPE_SYMBOL obj = node['id'].data.intern - setiv2obj(obj, node['ivars'], map) when TYPE_STRUCT typestr = Mapping.elename2name(node['type'].data) klass = Mapping.class_from_name(typestr) @@ -333,40 +366,15 @@ private obj = create_empty_object(klass) mark_unmarshalled_obj(node, obj) node['member'].each do |name, value| - obj[Mapping.elename2name(name)] = - Mapping._soap2obj(value, map) + obj[Mapping.elename2name(name)] = Mapping._soap2obj(value, map) end - setiv2obj(obj, node['ivars'], map) else - conv, obj = exception2obj(node, map) - unless conv - return false - end - setiv2obj(obj, node['ivars'], map) + return unknowntype2obj(node, info, map) end return true, obj end - def exception2obj(node, map) - typestr = Mapping.elename2name(node.type.name) - klass = Mapping.class_from_name(typestr) - if klass.nil? - return false - end - unless klass <= Exception - return false - end - message = Mapping._soap2obj(node['message'], map) - backtrace = Mapping._soap2obj(node['backtrace'], map) - obj = create_empty_object(klass) - obj = obj.exception(message) - mark_unmarshalled_obj(node, obj) - obj.set_backtrace(backtrace) - setiv2obj(obj, node['ivars'], map) - return true, obj - end - - def anytype2obj(node, map) + def anytype2obj(node, info, map) case node when SOAPBasetype return true, node.data @@ -383,22 +391,24 @@ private end end - def unknowntype2obj(node, map) + def unknowntype2obj(node, info, map) if node.is_a?(SOAPStruct) - obj = struct2obj(node, map) + obj = unknownstruct2obj(node, info, map) return true, obj if obj if !@allow_untyped_struct return false end - return anytype2obj(node, map) + return anytype2obj(node, info, map) else # Basetype which is not defined... return false end end - def struct2obj(node, map) - obj = nil + def unknownstruct2obj(node, info, map) + unless node.type.name + return nil + end typestr = Mapping.elename2name(node.type.name) klass = Mapping.class_from_name(typestr) if klass.nil? @@ -407,6 +417,9 @@ private if klass.nil? return nil end + if klass <= ::Exception + return exception2obj(klass, node, map) + end klass_type = Mapping.class2qname(klass) return nil unless node.type.match(klass_type) obj = create_empty_object(klass) @@ -415,6 +428,16 @@ private obj end + def exception2obj(klass, node, map) + message = Mapping._soap2obj(node['message'], map) + backtrace = Mapping._soap2obj(node['backtrace'], map) + obj = create_empty_object(klass) + obj = obj.exception(message) + mark_unmarshalled_obj(node, obj) + obj.set_backtrace(backtrace) + obj + end + # Only creates empty array. Do String#replace it with real string. def array2obj(node, map, rubytype) klass = rubytype ? Mapping.class_from_name(rubytype) : Array |