1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00
rails--rails/actionwebservice/lib/action_web_service/casting.rb
Leon Breedt d7a7d85dbd * Fix casting of nested members in structured types if we have a signature
type available for it even if they are already of the desired type as
   SOAP/XML-RPC unmarshaling may have gotten it wrong: SOAP likes to always
   use DateTime no matter what, for example, whereas we allow a distinction
   between Date, DateTime and Time in the signature for convenience casting
 * Fix raising of exceptions by test_invoke so functional tests fail properly on exception
   instead of returning the exception object
 * Fix Struct#each_pair to yield the value and not the member type


git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@1089 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
2005-04-04 22:58:02 +00:00

112 lines
3.7 KiB
Ruby

require 'time'
require 'date'
module ActionWebService # :nodoc:
module Casting # :nodoc:
class CastingError < ActionWebServiceError # :nodoc:
end
# Performs casting of arbitrary values into the correct types for the signature
class BaseCaster
def initialize(api_method)
@api_method = api_method
end
# Coerces the parameters in +params+ (an Enumerable) into the types
# this method expects
def cast_expects(params)
self.class.cast_expects(@api_method, params)
end
# Coerces the given +return_value+ into the the type returned by this
# method
def cast_returns(return_value)
self.class.cast_returns(@api_method, return_value)
end
class << self
include ActionWebService::SignatureTypes
def cast_expects(api_method, params) # :nodoc:
return [] if api_method.expects.nil?
i = -1
api_method.expects.map{ |type| cast(params[i+=1], type) }
end
def cast_returns(api_method, return_value) # :nodoc:
return nil if api_method.returns.nil?
cast(return_value, api_method.returns[0])
end
def cast(value, signature_type) # :nodoc:
return value if signature_type.nil? # signature.length != params.length
unless signature_type.array? || signature_type.structured?
return value if canonical_type(value.class) == signature_type.type
end
if signature_type.array?
unless value.respond_to?(:entries) && !value.is_a?(String)
raise CastingError, "Don't know how to cast #{value.class} into #{signature_type.type.inspect}"
end
value.entries.map do |entry|
cast(entry, signature_type.element_type)
end
elsif signature_type.structured?
cast_to_structured_type(value, signature_type)
elsif !signature_type.custom?
cast_base_type(value, signature_type)
end
end
def cast_base_type(value, signature_type) # :nodoc:
case signature_type.type
when :int
Integer(value)
when :string
value.to_s
when :bool
return false if value.nil?
return value if value == true || value == false
case value.to_s.downcase
when '1', 'true', 'y', 'yes'
true
when '0', 'false', 'n', 'no'
false
else
raise CastingError, "Don't know how to cast #{value.class} into Boolean"
end
when :float
Float(value)
when :time
Time.parse(value.to_s)
when :date
Date.parse(value.to_s)
when :datetime
DateTime.parse(value.to_s)
end
end
def cast_to_structured_type(value, signature_type) # :nodoc:
obj = nil
obj = value if canonical_type(value.class) == canonical_type(signature_type.type)
obj ||= signature_type.type_class.new
if value.respond_to?(:each_pair)
klass = signature_type.type_class
value.each_pair do |name, val|
type = klass.respond_to?(:member_type) ? klass.member_type(name) : nil
val = cast(val, type) if type
obj.__send__("#{name}=", val)
end
elsif value.respond_to?(:attributes)
signature_type.each_member do |name, type|
val = value.__send__(name)
obj.__send__("#{name}=", cast(val, type))
end
else
raise CastingError, "Don't know how to cast #{value.class} to #{signature_type.type_class}"
end
obj
end
end
end
end
end