aboutsummaryrefslogtreecommitdiffstats
path: root/actionwebservice/lib/action_web_service/vendor/ws
diff options
context:
space:
mode:
authorLeon Breedt <bitserf@gmail.com>2005-04-02 21:03:36 +0000
committerLeon Breedt <bitserf@gmail.com>2005-04-02 21:03:36 +0000
commitaaea48fe9826b9e5d2d5b92795a297b8f238c58d (patch)
treee7c01c7f95d467f837c1f96d58dac74c3c902610 /actionwebservice/lib/action_web_service/vendor/ws
parentaa09c770e9b5400683be11952673017295246de7 (diff)
downloadrails-aaea48fe9826b9e5d2d5b92795a297b8f238c58d.tar.gz
rails-aaea48fe9826b9e5d2d5b92795a297b8f238c58d.tar.bz2
rails-aaea48fe9826b9e5d2d5b92795a297b8f238c58d.zip
* collapse 'ws' back into protocols, it just added complexity and indirection, and was hard to extend.
* extract casting into seperate support file * ensure casting always does the right thing for return values, should fix interoperability issues with Ecto and possibly other XML-RPC clients * add functional unit tests for scaffolding * represent signature items with classes instead of symbols/Class objects, much more flexible * tweak logging to always show casted versions of parameters and return values, if possible. git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@1072 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
Diffstat (limited to 'actionwebservice/lib/action_web_service/vendor/ws')
-rw-r--r--actionwebservice/lib/action_web_service/vendor/ws/common.rb8
-rw-r--r--actionwebservice/lib/action_web_service/vendor/ws/encoding.rb3
-rw-r--r--actionwebservice/lib/action_web_service/vendor/ws/encoding/abstract.rb26
-rw-r--r--actionwebservice/lib/action_web_service/vendor/ws/encoding/soap_rpc_encoding.rb90
-rw-r--r--actionwebservice/lib/action_web_service/vendor/ws/encoding/xmlrpc_encoding.rb44
-rw-r--r--actionwebservice/lib/action_web_service/vendor/ws/marshaling.rb3
-rw-r--r--actionwebservice/lib/action_web_service/vendor/ws/marshaling/abstract.rb33
-rw-r--r--actionwebservice/lib/action_web_service/vendor/ws/marshaling/soap_marshaling.rb283
-rw-r--r--actionwebservice/lib/action_web_service/vendor/ws/marshaling/xmlrpc_marshaling.rb143
-rw-r--r--actionwebservice/lib/action_web_service/vendor/ws/types.rb165
10 files changed, 0 insertions, 798 deletions
diff --git a/actionwebservice/lib/action_web_service/vendor/ws/common.rb b/actionwebservice/lib/action_web_service/vendor/ws/common.rb
deleted file mode 100644
index 4266a7141d..0000000000
--- a/actionwebservice/lib/action_web_service/vendor/ws/common.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-module WS
- class WSError < StandardError
- end
-
- def self.derived_from?(ancestor, child)
- child.ancestors.include?(ancestor)
- end
-end
diff --git a/actionwebservice/lib/action_web_service/vendor/ws/encoding.rb b/actionwebservice/lib/action_web_service/vendor/ws/encoding.rb
deleted file mode 100644
index 790317639b..0000000000
--- a/actionwebservice/lib/action_web_service/vendor/ws/encoding.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-require 'ws/encoding/abstract'
-require 'ws/encoding/soap_rpc_encoding'
-require 'ws/encoding/xmlrpc_encoding'
diff --git a/actionwebservice/lib/action_web_service/vendor/ws/encoding/abstract.rb b/actionwebservice/lib/action_web_service/vendor/ws/encoding/abstract.rb
deleted file mode 100644
index 257c7d0993..0000000000
--- a/actionwebservice/lib/action_web_service/vendor/ws/encoding/abstract.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-module WS
- module Encoding
- # Encoders operate on _foreign_ objects. That is, Ruby object
- # instances that are the _marshaling format specific_ representation
- # of objects. In other words, objects that have not yet been marshaled, but
- # are in protocol-specific form (such as an AST or DOM element), and not
- # native Ruby form.
- class AbstractEncoding
- def encode_rpc_call(method_name, params)
- raise NotImplementedError
- end
-
- def decode_rpc_call(obj)
- raise NotImplementedError
- end
-
- def encode_rpc_response(method_name, return_value)
- raise NotImplementedError
- end
-
- def decode_rpc_response(obj)
- raise NotImplementedError
- end
- end
- end
-end
diff --git a/actionwebservice/lib/action_web_service/vendor/ws/encoding/soap_rpc_encoding.rb b/actionwebservice/lib/action_web_service/vendor/ws/encoding/soap_rpc_encoding.rb
deleted file mode 100644
index f4d2f5a7d6..0000000000
--- a/actionwebservice/lib/action_web_service/vendor/ws/encoding/soap_rpc_encoding.rb
+++ /dev/null
@@ -1,90 +0,0 @@
-require 'soap/processor'
-require 'soap/mapping'
-require 'soap/rpc/element'
-
-module WS
- module Encoding
- class SoapRpcError < WSError
- end
-
- class SoapRpcEncoding < AbstractEncoding
- attr_accessor :method_namespace
-
- def initialize(method_namespace='')
- @method_namespace = method_namespace
- end
-
- def encode_rpc_call(method_name, foreign_params)
- qname = create_method_qname(method_name)
- param_def = []
- params = foreign_params.map do |p|
- param_def << ['in', p.param.info.name, p.param.info.data.mapping]
- [p.param.info.name, p.soap_object]
- end
- request = SOAP::RPC::SOAPMethodRequest.new(qname, param_def)
- request.set_param(params)
- envelope = create_soap_envelope(request)
- SOAP::Processor.marshal(envelope)
- end
-
- def decode_rpc_call(obj)
- envelope = SOAP::Processor.unmarshal(obj)
- unless envelope
- raise(SoapRpcError, "Malformed SOAP request")
- end
- request = envelope.body.request
- method_name = request.elename.name
- params = request.collect do |key, value|
- info = ParamInfo.new(key, nil, nil)
- param = Param.new(nil, info)
- Marshaling::SoapForeignObject.new(param, request[key])
- end
- [method_name, params]
- end
-
- def encode_rpc_response(method_name, return_value)
- response = nil
- qname = create_method_qname(method_name)
- if return_value.nil?
- response = SOAP::RPC::SOAPMethodResponse.new(qname, nil)
- else
- param = return_value.param
- soap_object = return_value.soap_object
- param_def = [['retval', 'return', param.info.data.mapping]]
- if soap_object.is_a?(SOAP::SOAPFault)
- response = soap_object
- else
- response = SOAP::RPC::SOAPMethodResponse.new(qname, param_def)
- response.retval = soap_object
- end
- end
- envelope = create_soap_envelope(response)
- SOAP::Processor.marshal(envelope)
- end
-
- def decode_rpc_response(obj)
- envelope = SOAP::Processor.unmarshal(obj)
- unless envelope
- raise(SoapRpcError, "Malformed SOAP response")
- end
- method_name = envelope.body.request.elename.name
- return_value = envelope.body.response
- info = ParamInfo.new('return', nil, nil)
- param = Param.new(nil, info)
- return_value = Marshaling::SoapForeignObject.new(param, return_value)
- [method_name, return_value]
- end
-
- private
- def create_soap_envelope(body)
- header = SOAP::SOAPHeader.new
- body = SOAP::SOAPBody.new(body)
- SOAP::SOAPEnvelope.new(header, body)
- end
-
- def create_method_qname(method_name)
- XSD::QName.new(@method_namespace, method_name)
- end
- end
- end
-end
diff --git a/actionwebservice/lib/action_web_service/vendor/ws/encoding/xmlrpc_encoding.rb b/actionwebservice/lib/action_web_service/vendor/ws/encoding/xmlrpc_encoding.rb
deleted file mode 100644
index 4876c08705..0000000000
--- a/actionwebservice/lib/action_web_service/vendor/ws/encoding/xmlrpc_encoding.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-require 'xmlrpc/marshal'
-
-module WS
- module Encoding
- class XmlRpcEncoding < AbstractEncoding
- def encode_rpc_call(method_name, params)
- XMLRPC::Marshal.dump_call(method_name, *params)
- end
-
- def decode_rpc_call(obj)
- method_name, params = XMLRPC::Marshal.load_call(obj)
- i = 0
- params = params.map do |value|
- param = XmlRpcDecodedParam.new("param#{i}", value)
- i += 1
- param
- end
- [method_name, params]
- end
-
- def encode_rpc_response(method_name, return_value)
- if return_value.nil?
- XMLRPC::Marshal.dump_response(true)
- else
- XMLRPC::Marshal.dump_response(return_value)
- end
- end
-
- def decode_rpc_response(obj)
- return_value = XMLRPC::Marshal.load_response(obj)
- [nil, XmlRpcDecodedParam.new('return', return_value)]
- end
- end
-
- class XmlRpcDecodedParam
- attr :param
-
- def initialize(name, value)
- info = ParamInfo.new(name, value.class)
- @param = Param.new(value, info)
- end
- end
- end
-end
diff --git a/actionwebservice/lib/action_web_service/vendor/ws/marshaling.rb b/actionwebservice/lib/action_web_service/vendor/ws/marshaling.rb
deleted file mode 100644
index 3a0a2e8cc1..0000000000
--- a/actionwebservice/lib/action_web_service/vendor/ws/marshaling.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-require 'ws/marshaling/abstract'
-require 'ws/marshaling/soap_marshaling'
-require 'ws/marshaling/xmlrpc_marshaling'
diff --git a/actionwebservice/lib/action_web_service/vendor/ws/marshaling/abstract.rb b/actionwebservice/lib/action_web_service/vendor/ws/marshaling/abstract.rb
deleted file mode 100644
index e897f62297..0000000000
--- a/actionwebservice/lib/action_web_service/vendor/ws/marshaling/abstract.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-module WS
- module Marshaling
- class AbstractMarshaler
- def initialize
- @base_type_caster = BaseTypeCaster.new
- end
-
- def marshal(param)
- raise NotImplementedError
- end
-
- def unmarshal(param)
- raise NotImplementedError
- end
-
- def register_type(type)
- nil
- end
- alias :lookup_type :register_type
-
- def cast_inbound_recursive(value, spec)
- raise NotImplementedError
- end
-
- def cast_outbound_recursive(value, spec)
- raise NotImplementedError
- end
-
- attr :base_type_caster
- protected :base_type_caster
- end
- end
-end
diff --git a/actionwebservice/lib/action_web_service/vendor/ws/marshaling/soap_marshaling.rb b/actionwebservice/lib/action_web_service/vendor/ws/marshaling/soap_marshaling.rb
deleted file mode 100644
index 14c8d8401d..0000000000
--- a/actionwebservice/lib/action_web_service/vendor/ws/marshaling/soap_marshaling.rb
+++ /dev/null
@@ -1,283 +0,0 @@
-require 'soap/mapping'
-require 'xsd/ns'
-
-module WS
- module Marshaling
- SoapEncodingNS = 'http://schemas.xmlsoap.org/soap/encoding/'
-
- class SoapError < WSError
- end
-
- class SoapMarshaler < AbstractMarshaler
- attr :registry
- attr_accessor :type_namespace
-
- def initialize(type_namespace='')
- super()
- @type_namespace = type_namespace
- @registry = SOAP::Mapping::Registry.new
- @spec2binding = {}
- end
-
- def marshal(param)
- annotate_arrays(param.info.data, param.value)
- if param.value.is_a?(Exception)
- detail = SOAP::Mapping::SOAPException.new(param.value)
- soap_obj = SOAP::SOAPFault.new(
- SOAP::SOAPQName.new('%s:%s' % [SOAP::SOAPNamespaceTag, 'Server']),
- SOAP::SOAPString.new(param.value.to_s),
- SOAP::SOAPString.new(self.class.name),
- SOAP::Mapping.obj2soap(detail))
- else
- soap_obj = SOAP::Mapping.obj2soap(param.value, @registry)
- end
- SoapForeignObject.new(param, soap_obj)
- end
-
- def unmarshal(obj)
- param = obj.param
- soap_object = obj.soap_object
- soap_type = soap_object ? soap_object.type : nil
- value = soap_object ? SOAP::Mapping.soap2obj(soap_object, @registry) : nil
- param.value = value
- param.info.type = value.class
- mapping = @registry.find_mapped_soap_class(param.info.type) rescue nil
- if soap_type && soap_type.name == 'Array' && soap_type.namespace == SoapEncodingNS
- param.info.data = SoapBinding.new(self, soap_object.arytype, Array, mapping)
- else
- param.info.data = SoapBinding.new(self, soap_type, value.class, mapping)
- end
- param
- end
-
- def register_type(spec)
- if @spec2binding.has_key?(spec)
- return @spec2binding[spec]
- end
-
- klass = BaseTypes.canonical_param_type_class(spec)
- if klass.is_a?(Array)
- type_class = klass[0]
- else
- type_class = klass
- end
-
- type_binding = nil
- if (mapping = @registry.find_mapped_soap_class(type_class) rescue nil)
- qname = mapping[2] ? mapping[2][:type] : nil
- qname ||= soap_base_type_name(mapping[0])
- type_binding = SoapBinding.new(self, qname, type_class, mapping)
- else
- qname = XSD::QName.new(@type_namespace, soap_type_name(type_class.name))
- @registry.add(type_class,
- SOAP::SOAPStruct,
- typed_struct_factory(type_class),
- { :type => qname })
- mapping = @registry.find_mapped_soap_class(type_class)
- type_binding = SoapBinding.new(self, qname, type_class, mapping)
- end
-
- array_binding = nil
- if klass.is_a?(Array)
- array_mapping = @registry.find_mapped_soap_class(Array) rescue nil
- if (array_mapping && !array_mapping[1].is_a?(SoapTypedArrayFactory)) || array_mapping.nil?
- @registry.set(Array,
- SOAP::SOAPArray,
- SoapTypedArrayFactory.new)
- array_mapping = @registry.find_mapped_soap_class(Array)
- end
- qname = XSD::QName.new(@type_namespace, soap_type_name(type_class.name) + 'Array')
- array_binding = SoapBinding.new(self, qname, Array, array_mapping, type_binding)
- end
-
- @spec2binding[spec] = array_binding ? array_binding : type_binding
- @spec2binding[spec]
- end
- alias :lookup_type :register_type
-
- def cast_inbound_recursive(value, spec)
- binding = lookup_type(spec)
- if binding.is_custom_type?
- value
- else
- base_type_caster.cast(value, binding.type_class)
- end
- end
-
- def cast_outbound_recursive(value, spec)
- binding = lookup_type(spec)
- if binding.is_custom_type?
- value
- else
- base_type_caster.cast(value, binding.type_class)
- end
- end
-
- protected
- def annotate_arrays(binding, value)
- if binding.is_typed_array?
- mark_typed_array(value, binding.element_binding.qname)
- if binding.element_binding.is_custom_type?
- value.each do |element|
- annotate_arrays(register_type(element.class), element)
- end
- end
- elsif binding.is_typed_struct?
- if binding.type_class.respond_to?(:members)
- binding.type_class.members.each do |name, spec|
- member_binding = register_type(spec)
- member_value = value.respond_to?('[]') ? value[name] : value.send(name)
- if member_binding.is_custom_type?
- annotate_arrays(member_binding, member_value)
- end
- end
- end
- end
- end
-
- def mark_typed_array(array, qname)
- (class << array; self; end).class_eval do
- define_method(:arytype) do
- qname
- end
- end
- end
-
- def typed_struct_factory(type_class)
- if Object.const_defined?('ActiveRecord')
- if WS.derived_from?(ActiveRecord::Base, type_class)
- qname = XSD::QName.new(@type_namespace, soap_type_name(type_class.name))
- type_class.instance_variable_set('@qname', qname)
- return SoapActiveRecordStructFactory.new
- end
- end
- SOAP::Mapping::Registry::TypedStructFactory
- end
-
- def soap_type_name(type_name)
- type_name.gsub(/::/, '..')
- end
-
- def soap_base_type_name(type)
- xsd_type = type.ancestors.find{|c| c.const_defined? 'Type'}
- xsd_type ? xsd_type.const_get('Type') : XSD::XSDAnySimpleType::Type
- end
- end
-
- class SoapForeignObject
- attr_accessor :param
- attr_accessor :soap_object
-
- def initialize(param, soap_object)
- @param = param
- @soap_object = soap_object
- end
- end
-
- class SoapBinding
- attr :qname
- attr :type_class
- attr :mapping
- attr :element_binding
-
- def initialize(marshaler, qname, type_class, mapping, element_binding=nil)
- @marshaler = marshaler
- @qname = qname
- @type_class = type_class
- @mapping = mapping
- @element_binding = element_binding
- end
-
- def is_custom_type?
- is_typed_array? || is_typed_struct?
- end
-
- def is_typed_array?
- @mapping[1].is_a?(WS::Marshaling::SoapTypedArrayFactory)
- end
-
- def is_typed_struct?
- @mapping[1] == SOAP::Mapping::Registry::TypedStructFactory || \
- @mapping[1].is_a?(WS::Marshaling::SoapActiveRecordStructFactory)
- end
-
- def each_member(&block)
- if is_typed_struct?
- if @mapping[1] == SOAP::Mapping::Registry::TypedStructFactory
- if @type_class.respond_to?(:members)
- @type_class.members.each do |name, spec|
- yield name, spec
- end
- end
- elsif @mapping[1].is_a?(WS::Marshaling::SoapActiveRecordStructFactory)
- @type_class.columns.each do |column|
- yield column.name, column.klass
- end
- end
- end
- end
-
- def type_name
- is_custom_type? ? @qname.name : nil
- end
-
- def qualified_type_name(ns=nil)
- if is_custom_type?
- "#{ns ? ns : @qname.namespace}:#{@qname.name}"
- else
- ns = XSD::NS.new
- ns.assign(XSD::Namespace, SOAP::XSDNamespaceTag)
- xsd_klass = mapping[0].ancestors.find{|c| c.const_defined?('Type')}
- return ns.name(XSD::AnyTypeName) unless xsd_klass
- ns.name(xsd_klass.const_get('Type'))
- end
- end
- end
-
- class SoapActiveRecordStructFactory < SOAP::Mapping::Factory
- def obj2soap(soap_class, obj, info, map)
- unless obj.is_a?(ActiveRecord::Base)
- return nil
- end
- soap_obj = soap_class.new(obj.class.instance_variable_get('@qname'))
- obj.class.columns.each do |column|
- key = column.name.to_s
- value = obj.send(key)
- soap_obj[key] = SOAP::Mapping._obj2soap(value, map)
- end
- soap_obj
- end
-
- def soap2obj(obj_class, node, info, map)
- unless node.type == obj_class.instance_variable_get('@qname')
- return false
- end
- obj = obj_class.new
- node.each do |key, value|
- obj[key] = value.data
- end
- obj.instance_variable_set('@new_record', false)
- return true, obj
- end
- end
-
- class SoapTypedArrayFactory < SOAP::Mapping::Factory
- def obj2soap(soap_class, obj, info, map)
- unless obj.respond_to?(:arytype)
- return nil
- end
- soap_obj = soap_class.new(SOAP::ValueArrayName, 1, obj.arytype)
- mark_marshalled_obj(obj, soap_obj)
- obj.each do |item|
- child = SOAP::Mapping._obj2soap(item, map)
- soap_obj.add(child)
- end
- soap_obj
- end
-
- def soap2obj(obj_class, node, info, map)
- return false
- end
- end
- end
-end
diff --git a/actionwebservice/lib/action_web_service/vendor/ws/marshaling/xmlrpc_marshaling.rb b/actionwebservice/lib/action_web_service/vendor/ws/marshaling/xmlrpc_marshaling.rb
deleted file mode 100644
index 56cc7597fb..0000000000
--- a/actionwebservice/lib/action_web_service/vendor/ws/marshaling/xmlrpc_marshaling.rb
+++ /dev/null
@@ -1,143 +0,0 @@
-module WS
- module Marshaling
- class XmlRpcError < WSError
- end
-
- class XmlRpcMarshaler < AbstractMarshaler
- def initialize
- super()
- @spec2binding = {}
- end
-
- def marshal(param)
- value = param.value
- cast_outbound_recursive(param.value, spec_for(param)) rescue value
- end
-
- def unmarshal(obj)
- obj.param
- end
-
- def typed_unmarshal(obj, spec)
- obj.param.info.data = lookup_type(spec)
- value = obj.param.value
- obj.param.value = cast_inbound_recursive(value, spec) rescue value
- obj.param
- end
-
- def register_type(spec)
- if @spec2binding.has_key?(spec)
- return @spec2binding[spec]
- end
-
- klass = BaseTypes.canonical_param_type_class(spec)
- type_binding = nil
- if klass.is_a?(Array)
- type_binding = XmlRpcArrayBinding.new(klass[0])
- else
- type_binding = XmlRpcBinding.new(klass)
- end
-
- @spec2binding[spec] = type_binding
- end
- alias :lookup_type :register_type
-
- def cast_inbound_recursive(value, spec)
- binding = lookup_type(spec)
- case binding
- when XmlRpcArrayBinding
- value.map{ |x| cast_inbound(x, binding.element_klass) }
- when XmlRpcBinding
- cast_inbound(value, binding.klass)
- end
- end
-
- def cast_outbound_recursive(value, spec)
- binding = lookup_type(spec)
- case binding
- when XmlRpcArrayBinding
- value.map{ |x| cast_outbound(x, binding.element_klass) }
- when XmlRpcBinding
- cast_outbound(value, binding.klass)
- end
- end
-
- private
- def spec_for(param)
- binding = param.info.data
- binding.is_a?(XmlRpcArrayBinding) ? [binding.element_klass] : binding.klass
- end
-
- def cast_inbound(value, klass)
- if BaseTypes.base_type?(klass)
- value = value.to_time if value.is_a?(XMLRPC::DateTime)
- base_type_caster.cast(value, klass)
- elsif value.is_a?(XMLRPC::FaultException)
- value
- elsif klass.ancestors.include?(ActionWebService::Struct)
- obj = klass.new
- klass.members.each do |name, klass|
- name = name.to_s
- obj.send('%s=' % name, cast_inbound_recursive(value[name], klass))
- end
- obj
- else
- obj = klass.new
- if obj.respond_to?(:update)
- obj.update(value)
- else
- value.each do |name, val|
- obj.send('%s=' % name.to_s, val)
- end
- end
- obj
- end
- end
-
- def cast_outbound(value, klass)
- if BaseTypes.base_type?(klass)
- base_type_caster.cast(value, klass)
- elsif value.is_a?(Exception)
- XMLRPC::FaultException.new(2, value.message)
- elsif Object.const_defined?('ActiveRecord') && value.is_a?(ActiveRecord::Base)
- value.attributes
- elsif value.is_a?(ActionWebService::Struct)
- struct = {}
- value.class.members.each do |name, klass|
- name = name.to_s
- struct[name] = cast_outbound_recursive(value[name], klass)
- end
- struct
- else
- struct = {}
- if value.respond_to?(:each_pair)
- value.each_pair{ |key, value| struct[key] = value }
- else
- value.instance_variables.each do |name|
- key = name.sub(/^@/, '')
- struct[key] = value.instance_variable_get(name)
- end
- end
- struct
- end
- end
- end
-
- class XmlRpcBinding
- attr :klass
-
- def initialize(klass)
- @klass = klass
- end
- end
-
- class XmlRpcArrayBinding < XmlRpcBinding
- attr :element_klass
-
- def initialize(element_klass)
- super(Array)
- @element_klass = element_klass
- end
- end
- end
-end
diff --git a/actionwebservice/lib/action_web_service/vendor/ws/types.rb b/actionwebservice/lib/action_web_service/vendor/ws/types.rb
deleted file mode 100644
index 88098b5bce..0000000000
--- a/actionwebservice/lib/action_web_service/vendor/ws/types.rb
+++ /dev/null
@@ -1,165 +0,0 @@
-require 'time'
-require 'date'
-
-module WS
- module BaseTypes
- class << self
- def type_name_to_class(name)
- case canonical_type_name(name)
- when :int
- Integer
- when :string
- String
- when :bool
- TrueClass
- when :float
- Float
- when :time
- Time
- when :date
- Date
- end
- end
-
- def class_to_type_name(klass)
- if WS.derived_from?(Integer, klass) || WS.derived_from?(Fixnum, klass) || WS.derived_from?(Bignum, klass)
- :int
- elsif klass == String
- :string
- elsif klass == TrueClass || klass == FalseClass
- :bool
- elsif WS.derived_from?(Float, klass) || WS.derived_from?(Precision, klass) || WS.derived_from?(Numeric, klass)
- :float
- elsif klass == Time || klass == DateTime
- :time
- elsif klass == Date
- :date
- else
- raise(TypeError, "#{klass} is not a valid base type")
- end
- end
-
- def base_type?(klass)
- !(canonical_type_class(klass) rescue nil).nil?
- end
-
- def canonical_type_class(klass)
- type_name_to_class(class_to_type_name(klass))
- end
-
- def canonical_param_type_class(spec)
- klass = spec.is_a?(Hash) ? spec.values[0] : spec
- array_element_class = klass.is_a?(Array) ? klass[0] : nil
- klass = array_element_class ? array_element_class : klass
- klass = type_name_to_class(klass) if klass.is_a?(Symbol) || klass.is_a?(String)
- base_class = canonical_type_class(klass) rescue nil
- klass = base_class unless base_class.nil?
- array_element_class ? [klass] : klass
- end
-
- def canonical_param_type_spec(spec)
- klass = canonical_param_type_class(spec)
- spec.is_a?(Hash) ? {spec.keys[0]=>klass} : klass
- end
-
- def canonical_type_name(name)
- name = name.to_sym
- case name
- when :int, :integer, :fixnum, :bignum
- :int
- when :string, :base64
- :string
- when :bool, :boolean
- :bool
- when :float, :double
- :float
- when :time, :datetime, :timestamp
- :time
- when :date
- :date
- else
- raise(TypeError, "#{name} is not a valid base type")
- end
- end
- end
- end
-
- class Param
- attr_accessor :value
- attr_accessor :info
-
- def initialize(value, info)
- @value = value
- @info = info
- end
- end
-
- class ParamInfo
- attr_accessor :name
- attr_accessor :type
- attr_accessor :data
-
- def initialize(name, type, data=nil)
- @name = name
- @type = type
- @data = data
- end
-
- def self.create(spec, data, index=nil)
- name = spec.is_a?(Hash) ? spec.keys[0].to_s : (index ? "param#{index}" : nil)
- type = BaseTypes.canonical_param_type_class(spec)
- ParamInfo.new(name, type, data)
- end
- end
-
- class BaseTypeCaster
- def initialize
- @handlers = {}
- install_handlers
- end
-
- def cast(value, klass)
- type_class = BaseTypes.canonical_type_class(klass)
- return value unless type_class
- @handlers[type_class].call(value, type_class)
- end
-
- protected
- def install_handlers
- handler = method(:cast_base_type)
- [:int, :string, :bool, :float, :time, :date].each do |name|
- type = BaseTypes.type_name_to_class(name)
- @handlers[type] = handler
- end
- @handlers[Fixnum] = handler
- end
-
- def cast_base_type(value, type_class)
- desired_class = BaseTypes.canonical_type_class(type_class)
- value_class = BaseTypes.canonical_type_class(value.class)
- return value if desired_class == value_class
- desired_name = BaseTypes.class_to_type_name(desired_class)
- case desired_name
- when :int
- Integer(value)
- when :string
- value.to_s
- when :bool
- return false if value.nil?
- int_value = Integer(value) rescue nil
- return true if int_value == 1
- return false if int_value == 0
- value = value.to_s
- return true if value == 'true'
- return false if value == 'false'
- raise(TypeError, "can't convert #{value} to boolean")
- when :float
- Float(value)
- when :time
- Time.parse(value.to_s)
- when :date
- Date.parse(value.to_s)
- end
- end
- end
-end