diff options
author | Leon Breedt <bitserf@gmail.com> | 2005-04-02 21:03:36 +0000 |
---|---|---|
committer | Leon Breedt <bitserf@gmail.com> | 2005-04-02 21:03:36 +0000 |
commit | aaea48fe9826b9e5d2d5b92795a297b8f238c58d (patch) | |
tree | e7c01c7f95d467f837c1f96d58dac74c3c902610 /actionwebservice/lib/action_web_service/casting.rb | |
parent | aa09c770e9b5400683be11952673017295246de7 (diff) | |
download | rails-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/casting.rb')
-rw-r--r-- | actionwebservice/lib/action_web_service/casting.rb | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/actionwebservice/lib/action_web_service/casting.rb b/actionwebservice/lib/action_web_service/casting.rb new file mode 100644 index 0000000000..ce90c463d8 --- /dev/null +++ b/actionwebservice/lib/action_web_service/casting.rb @@ -0,0 +1,105 @@ +require 'time' +require 'date' +require 'generator' + +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? + SyncEnumerator.new(params, api_method.expects).map{ |r| cast(r[0], r[1]) } + 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? + 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 = 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 + else + raise CastingError, "Don't know how to cast #{value.class} to #{signature_type.type_class}" + end + obj + end + end + end + end +end |