summaryrefslogtreecommitdiff
path: root/lib/soap/mapping
diff options
context:
space:
mode:
authornahi <nahi@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2003-10-14 15:14:02 +0000
committernahi <nahi@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2003-10-14 15:14:02 +0000
commit9cba39a1a1b09f94a5d890e0ad6f4c74bb9f36bf (patch)
tree559f6780e94880fc3e7c37678fbe8b49ff0556d7 /lib/soap/mapping
parent0b841783b508c9bddb1c0117b1970fc7c350843b (diff)
* lib/soap/baseData.rb: Introduce SOAPType as the common ancestor of
SOAPBasetype and SOAPCompoundtype. * lib/soap/generator.rb, lib/soap/element.rb, lib/soap/encodingstyle/*: Encoding methods signature change. Pass SOAPGenerator as a parameter. * lib/soap/mapping/*, test/soap/marshal/test_marshal.rb: Refactoring for better marshalling/unmarshalling support. Now I think SOAP marshaller supports all kind of object graph which is supported by Ruby's original marshaller. Of course there could be bugs as always. Find it. :-) * lib/soap/rpc/standaloneServer.rb: Set severity threshould to INFO. DEBUG is too noisy. * lib/xsd/datatypes.rb: DateTime#of is obsoleted. Use DateTime#offset. * test/wsdl/emptycomplextype.wsdl, test/xsd/xmlschema.xml: Avoid useless warning. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@4760 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/soap/mapping')
-rw-r--r--lib/soap/mapping/factory.rb91
-rw-r--r--lib/soap/mapping/mapping.rb10
-rw-r--r--lib/soap/mapping/registry.rb119
-rw-r--r--lib/soap/mapping/rubytypeFactory.rb377
4 files changed, 358 insertions, 239 deletions
diff --git a/lib/soap/mapping/factory.rb b/lib/soap/mapping/factory.rb
index 2e5ddc1f15..6a34da55a8 100644
--- a/lib/soap/mapping/factory.rb
+++ b/lib/soap/mapping/factory.rb
@@ -24,6 +24,10 @@ module Mapping
class Factory
include TraverseSupport
+ def initialize
+ # nothing to do
+ end
+
def obj2soap(soap_class, obj, info, map)
raise NotImplementError.new
# return soap_obj
@@ -48,24 +52,13 @@ class Factory
end
end
- def set_instance_vars(obj, values)
- values.each do |name, value|
- setter = name + "="
- if obj.respond_to?(setter)
- obj.__send__(setter, value)
- else
- obj.instance_eval("@#{ name } = value")
- end
- end
- end
-
def setiv2obj(obj, node, map)
return if node.nil?
vars = {}
node.each do |name, value|
vars[Mapping.elename2name(name)] = Mapping._soap2obj(value, map)
end
- set_instance_vars(obj, vars)
+ Mapping.set_instance_vars(obj, vars)
end
def setiv2soap(node, obj, map)
@@ -76,13 +69,6 @@ class Factory
end
end
- def addiv2soap(node, obj, map)
- return if obj.instance_variables.empty?
- ivars = SOAPStruct.new # Undefined type.
- setiv2soap(ivars, obj, map)
- node.add('ivars', ivars)
- end
-
# It breaks Thread.current[:SOAPMarshalDataKey].
def mark_marshalled_obj(obj, soap_obj)
Thread.current[:SOAPMarshalDataKey][obj.__id__] = soap_obj
@@ -103,14 +89,21 @@ class Factory
end
class StringFactory_ < Factory
+ def initialize(allow_original_mapping = false)
+ super()
+ @allow_original_mapping = allow_original_mapping
+ end
+
def obj2soap(soap_class, obj, info, map)
+ if !@allow_original_mapping and !obj.instance_variables.empty?
+ return nil
+ end
begin
- if XSD::Charset.is_ces(obj, $KCODE)
- encoded = XSD::Charset.encoding_conv(obj, $KCODE, XSD::Charset.encoding)
- soap_obj = soap_class.new(encoded)
- else
- return nil
+ unless XSD::Charset.is_ces(obj, $KCODE)
+ return nil
end
+ encoded = XSD::Charset.encoding_conv(obj, $KCODE, XSD::Charset.encoding)
+ soap_obj = soap_class.new(encoded)
rescue XSD::ValueSpaceError
return nil
end
@@ -119,14 +112,24 @@ class StringFactory_ < Factory
end
def soap2obj(obj_class, node, info, map)
- obj = XSD::Charset.encoding_conv(node.data, XSD::Charset.encoding, $KCODE)
+ obj = create_empty_object(obj_class)
+ decoded = XSD::Charset.encoding_conv(node.data, XSD::Charset.encoding, $KCODE)
+ obj.replace(decoded)
mark_unmarshalled_obj(node, obj)
return true, obj
end
end
class BasetypeFactory_ < Factory
+ def initialize(allow_original_mapping = false)
+ super()
+ @allow_original_mapping = allow_original_mapping
+ end
+
def obj2soap(soap_class, obj, info, map)
+ if !@allow_original_mapping and !obj.instance_variables.empty?
+ return nil
+ end
soap_obj = nil
begin
soap_obj = soap_class.new(obj)
@@ -145,7 +148,16 @@ class BasetypeFactory_ < Factory
end
class DateTimeFactory_ < Factory
+ def initialize(allow_original_mapping = false)
+ super()
+ @allow_original_mapping = allow_original_mapping
+ end
+
def obj2soap(soap_class, obj, info, map)
+ if !@allow_original_mapping and
+ Time === obj and !obj.instance_variables.empty?
+ return nil
+ end
soap_obj = nil
begin
soap_obj = soap_class.new(obj)
@@ -176,6 +188,7 @@ end
class Base64Factory_ < Factory
def obj2soap(soap_class, obj, info, map)
+ return nil unless obj.instance_variables.empty?
soap_obj = soap_class.new(obj)
mark_marshalled_obj(obj, soap_obj) if soap_obj
soap_obj
@@ -189,9 +202,17 @@ class Base64Factory_ < Factory
end
class ArrayFactory_ < Factory
+ def initialize(allow_original_mapping = false)
+ super()
+ @allow_original_mapping = allow_original_mapping
+ end
+
# [[1], [2]] is converted to Array of Array, not 2-D Array.
# To create M-D Array, you must call Mapping.ary2md.
def obj2soap(soap_class, obj, info, map)
+ if !@allow_original_mapping and !obj.instance_variables.empty?
+ return nil
+ end
arytype = Mapping.obj2element(obj)
if arytype.name
arytype.namespace ||= RubyTypeNamespace
@@ -217,7 +238,15 @@ class ArrayFactory_ < Factory
end
class TypedArrayFactory_ < Factory
+ def initialize(allow_original_mapping = false)
+ super()
+ @allow_original_mapping = allow_original_mapping
+ end
+
def obj2soap(soap_class, obj, info, map)
+ if !@allow_original_mapping and !obj.instance_variables.empty?
+ return nil
+ end
arytype = info[:type] || info[0]
param = SOAPArray.new(ValueArrayName, 1, arytype)
mark_marshalled_obj(obj, param)
@@ -271,9 +300,17 @@ end
MapQName = XSD::QName.new(ApacheSOAPTypeNamespace, 'Map')
class HashFactory_ < Factory
+ def initialize(allow_original_mapping = false)
+ super()
+ @allow_original_mapping = allow_original_mapping
+ end
+
def obj2soap(soap_class, obj, info, map)
- if obj.default or
- (obj.respond_to?(:default_proc) and obj.default_proc)
+ if !@allow_original_mapping and !obj.instance_variables.empty?
+ return nil
+ end
+ if !obj.default.nil? or
+ (obj.respond_to?(:default_proc) and obj.default_proc)
return nil
end
param = SOAPStruct.new(MapQName)
diff --git a/lib/soap/mapping/mapping.rb b/lib/soap/mapping/mapping.rb
index 19eca5dab0..f660c2c63f 100644
--- a/lib/soap/mapping/mapping.rb
+++ b/lib/soap/mapping/mapping.rb
@@ -129,6 +129,16 @@ module Mapping
return registry.soap2obj(node.class, node)
end
+ def self.set_instance_vars(obj, values)
+ values.each do |name, value|
+ setter = name + "="
+ if obj.respond_to?(setter)
+ obj.__send__(setter, value)
+ else
+ obj.instance_eval("@#{ name } = value")
+ end
+ end
+ end
# Allow only (Letter | '_') (Letter | Digit | '-' | '_')* here.
# Caution: '.' is not allowed here.
diff --git a/lib/soap/mapping/registry.rb b/lib/soap/mapping/registry.rb
index 568f34ac3e..bdf14d4fc6 100644
--- a/lib/soap/mapping/registry.rb
+++ b/lib/soap/mapping/registry.rb
@@ -39,6 +39,8 @@ module MappedException; end
RubyTypeName = XSD::QName.new(RubyTypeInstanceNamespace, 'rubyType')
+RubyExtendName = XSD::QName.new(RubyTypeInstanceNamespace, 'extends')
+RubyIVarName = XSD::QName.new(RubyTypeInstanceNamespace, 'ivars')
# Inner class to pass an exception.
@@ -217,11 +219,11 @@ class Registry
[::TrueClass, ::SOAP::SOAPBoolean, BasetypeFactory],
[::FalseClass, ::SOAP::SOAPBoolean, BasetypeFactory],
[::String, ::SOAP::SOAPString, StringFactory],
- [::DateTime, ::SOAP::SOAPDateTime, BasetypeFactory],
- [::Date, ::SOAP::SOAPDateTime, BasetypeFactory],
- [::Date, ::SOAP::SOAPDate, BasetypeFactory],
- [::Time, ::SOAP::SOAPDateTime, BasetypeFactory],
- [::Time, ::SOAP::SOAPTime, BasetypeFactory],
+ [::DateTime, ::SOAP::SOAPDateTime, DateTimeFactory],
+ [::Date, ::SOAP::SOAPDateTime, DateTimeFactory],
+ [::Date, ::SOAP::SOAPDate, DateTimeFactory],
+ [::Time, ::SOAP::SOAPDateTime, DateTimeFactory],
+ [::Time, ::SOAP::SOAPTime, DateTimeFactory],
[::Float, ::SOAP::SOAPDouble, BasetypeFactory,
{:derived_class => true}],
[::Float, ::SOAP::SOAPFloat, BasetypeFactory,
@@ -261,11 +263,11 @@ class Registry
[::TrueClass, ::SOAP::SOAPBoolean, BasetypeFactory],
[::FalseClass, ::SOAP::SOAPBoolean, BasetypeFactory],
[::String, ::SOAP::SOAPString, StringFactory],
- [::DateTime, ::SOAP::SOAPDateTime, BasetypeFactory],
- [::Date, ::SOAP::SOAPDateTime, BasetypeFactory],
- [::Date, ::SOAP::SOAPDate, BasetypeFactory],
- [::Time, ::SOAP::SOAPDateTime, BasetypeFactory],
- [::Time, ::SOAP::SOAPTime, BasetypeFactory],
+ [::DateTime, ::SOAP::SOAPDateTime, DateTimeFactory],
+ [::Date, ::SOAP::SOAPDateTime, DateTimeFactory],
+ [::Date, ::SOAP::SOAPDate, DateTimeFactory],
+ [::Time, ::SOAP::SOAPDateTime, DateTimeFactory],
+ [::Time, ::SOAP::SOAPTime, DateTimeFactory],
[::Float, ::SOAP::SOAPDouble, BasetypeFactory,
{:derived_class => true}],
[::Float, ::SOAP::SOAPFloat, BasetypeFactory,
@@ -304,18 +306,18 @@ class Registry
@config = config
@map = Map.new(self)
if @config[:allow_original_mapping]
- allow_original_mapping = true
+ @allow_original_mapping = true
@map.init(RubyOriginalMap)
else
- allow_original_mapping = false
+ @allow_original_mapping = false
@map.init(SOAPBaseMap)
end
- allow_untyped_struct = @config.key?(:allow_untyped_struct) ?
+ @allow_untyped_struct = @config.key?(:allow_untyped_struct) ?
@config[:allow_untyped_struct] : true
@rubytype_factory = RubytypeFactory.new(
- :allow_untyped_struct => allow_untyped_struct,
- :allow_original_mapping => allow_original_mapping
+ :allow_untyped_struct => @allow_untyped_struct,
+ :allow_original_mapping => @allow_original_mapping
)
@default_factory = @rubytype_factory
@excn_handler_obj2soap = nil
@@ -329,8 +331,47 @@ class Registry
# This mapping registry ignores type hint.
def obj2soap(klass, obj, type = nil)
+ soap = _obj2soap(klass, obj, type)
+ if @allow_original_mapping
+ addextend2soap(soap, obj)
+ end
+ soap
+ end
+
+ def soap2obj(klass, node)
+ obj = _soap2obj(klass, node)
+ if @allow_original_mapping
+ addextend2obj(obj, node.extraattr[RubyExtendName])
+ addiv2obj(obj, node.extraattr[RubyIVarName])
+ end
+ obj
+ end
+
+ def default_factory=(factory)
+ @default_factory = factory
+ end
+
+ def excn_handler_obj2soap=(handler)
+ @excn_handler_obj2soap = handler
+ end
+
+ def excn_handler_soap2obj=(handler)
+ @excn_handler_soap2obj = handler
+ end
+
+ def find_mapped_soap_class(obj_class)
+ @map.find_mapped_soap_class(obj_class)
+ end
+
+ def find_mapped_obj_class(soap_class)
+ @map.find_mapped_obj_class(soap_class)
+ end
+
+private
+
+ def _obj2soap(klass, obj, type)
ret = nil
- if obj.is_a?(SOAPStruct) || obj.is_a?(SOAPArray)
+ if obj.is_a?(SOAPStruct) or obj.is_a?(SOAPArray)
obj.replace do |ele|
Mapping._obj2soap(ele, self)
end
@@ -344,18 +385,17 @@ class Registry
rescue MappingError
end
return ret if ret
-
if @excn_handler_obj2soap
ret = @excn_handler_obj2soap.call(obj) { |yield_obj|
Mapping._obj2soap(yield_obj, self)
}
end
return ret if ret
-
raise MappingError.new("Cannot map #{ klass.name } to SOAP/OM.")
end
- def soap2obj(klass, node)
+ # Might return nil as a mapping result.
+ def _soap2obj(klass, node)
if node.extraattr.key?(RubyTypeName)
conv, obj = @rubytype_factory.soap2obj(klass, node, nil, self)
return obj if conv
@@ -369,34 +409,43 @@ class Registry
if @excn_handler_soap2obj
begin
return @excn_handler_soap2obj.call(node) { |yield_node|
- Mapping._soap2obj(yield_node, self)
- }
+ Mapping._soap2obj(yield_node, self)
+ }
rescue Exception
end
end
-
raise MappingError.new("Cannot map #{ node.type.name } to Ruby object.")
end
- def default_factory=(factory)
- @default_factory = factory
- end
-
- def excn_handler_obj2soap=(handler)
- @excn_handler_obj2soap = handler
+ def addiv2obj(obj, attr)
+ return unless attr
+ vars = {}
+ attr.__getobj__.each do |name, value|
+ vars[name] = Mapping._soap2obj(value, self)
+ end
+ Mapping.set_instance_vars(obj, vars)
end
- def excn_handler_soap2obj=(handler)
- @excn_handler_soap2obj = handler
+ def addextend2obj(obj, attr)
+ return unless attr
+ attr.split(/ /).reverse_each do |mstr|
+ obj.extend(Mapping.class_from_name(mstr))
+ end
end
- def find_mapped_soap_class(obj_class)
- @map.find_mapped_soap_class(obj_class)
+ def addextend2soap(node, obj)
+ return if obj.is_a?(Symbol) or obj.is_a?(Fixnum)
+ list = (class << obj; self; end).ancestors - obj.class.ancestors
+ unless list.empty?
+ node.extraattr[RubyExtendName] = list.collect { |c|
+ if c.name.empty?
+ raise TypeError.new("singleton can't be dumped #{ obj }")
+ end
+ c.name
+ }.join(" ")
+ end
end
- def find_mapped_obj_class(soap_class)
- @map.find_mapped_obj_class(soap_class)
- end
end
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