From aaea48fe9826b9e5d2d5b92795a297b8f238c58d Mon Sep 17 00:00:00 2001 From: Leon Breedt Date: Sat, 2 Apr 2005 21:03:36 +0000 Subject: * 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 --- .../lib/action_web_service/vendor/ws/common.rb | 8 - .../lib/action_web_service/vendor/ws/encoding.rb | 3 - .../vendor/ws/encoding/abstract.rb | 26 -- .../vendor/ws/encoding/soap_rpc_encoding.rb | 90 ------- .../vendor/ws/encoding/xmlrpc_encoding.rb | 44 ---- .../lib/action_web_service/vendor/ws/marshaling.rb | 3 - .../vendor/ws/marshaling/abstract.rb | 33 --- .../vendor/ws/marshaling/soap_marshaling.rb | 283 --------------------- .../vendor/ws/marshaling/xmlrpc_marshaling.rb | 143 ----------- .../lib/action_web_service/vendor/ws/types.rb | 165 ------------ 10 files changed, 798 deletions(-) delete mode 100644 actionwebservice/lib/action_web_service/vendor/ws/common.rb delete mode 100644 actionwebservice/lib/action_web_service/vendor/ws/encoding.rb delete mode 100644 actionwebservice/lib/action_web_service/vendor/ws/encoding/abstract.rb delete mode 100644 actionwebservice/lib/action_web_service/vendor/ws/encoding/soap_rpc_encoding.rb delete mode 100644 actionwebservice/lib/action_web_service/vendor/ws/encoding/xmlrpc_encoding.rb delete mode 100644 actionwebservice/lib/action_web_service/vendor/ws/marshaling.rb delete mode 100644 actionwebservice/lib/action_web_service/vendor/ws/marshaling/abstract.rb delete mode 100644 actionwebservice/lib/action_web_service/vendor/ws/marshaling/soap_marshaling.rb delete mode 100644 actionwebservice/lib/action_web_service/vendor/ws/marshaling/xmlrpc_marshaling.rb delete mode 100644 actionwebservice/lib/action_web_service/vendor/ws/types.rb (limited to 'actionwebservice/lib/action_web_service/vendor/ws') 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 -- cgit v1.2.3