aboutsummaryrefslogtreecommitdiffstats
path: root/actionwebservice/lib/action_web_service/api/base.rb
diff options
context:
space:
mode:
authorLeon Breedt <bitserf@gmail.com>2005-03-28 03:20:13 +0000
committerLeon Breedt <bitserf@gmail.com>2005-03-28 03:20:13 +0000
commit594063f23cf8e7cecd24329e801992784f420b55 (patch)
treed52e9a6fc0521d51fcc3875162adf0411ee6caa0 /actionwebservice/lib/action_web_service/api/base.rb
parent439a216dcb65ac83d86ca04bb898e1797a87ce70 (diff)
downloadrails-594063f23cf8e7cecd24329e801992784f420b55.tar.gz
rails-594063f23cf8e7cecd24329e801992784f420b55.tar.bz2
rails-594063f23cf8e7cecd24329e801992784f420b55.zip
generalize casting code to be used by both SOAP and XML-RPC (previously only XML-RPC). switch
to better model for API methods, and improve the ability to generate protocol requests/response, will be required by upcoming scaffolding. git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@1030 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
Diffstat (limited to 'actionwebservice/lib/action_web_service/api/base.rb')
-rw-r--r--actionwebservice/lib/action_web_service/api/base.rb164
1 files changed, 161 insertions, 3 deletions
diff --git a/actionwebservice/lib/action_web_service/api/base.rb b/actionwebservice/lib/action_web_service/api/base.rb
index c30c833f9d..e440a8b1bd 100644
--- a/actionwebservice/lib/action_web_service/api/base.rb
+++ b/actionwebservice/lib/action_web_service/api/base.rb
@@ -1,5 +1,8 @@
module ActionWebService # :nodoc:
module API # :nodoc:
+ class CastingError < ActionWebService::ActionWebServiceError
+ end
+
# A web service API class specifies the methods that will be available for
# invocation for an API. It also contains metadata such as the method type
# signature hints.
@@ -77,8 +80,8 @@ module ActionWebService # :nodoc:
end
name = name.to_sym
public_name = public_api_method_name(name)
- info = { :expects => expects, :returns => returns }
- write_inheritable_hash("api_methods", name => info)
+ method = Method.new(name, public_name, expects, returns)
+ write_inheritable_hash("api_methods", name => method)
write_inheritable_hash("api_public_method_names", public_name => name)
end
@@ -112,7 +115,39 @@ module ActionWebService # :nodoc:
def api_methods
read_inheritable_attribute("api_methods") || {}
end
-
+
+ # The Method instance for the given public API method name, if any
+ def public_api_method_instance(public_method_name)
+ api_method_instance(api_method_name(public_method_name))
+ end
+
+ # The Method instance for the given API method name, if any
+ def api_method_instance(method_name)
+ api_methods[method_name]
+ end
+
+ # The Method instance for the default API method, if any
+ def default_api_method_instance
+ return nil unless name = default_api_method
+ instance = read_inheritable_attribute("default_api_method_instance")
+ if instance && instance.name == name
+ return instance
+ end
+ instance = Method.new(name, public_api_method_name(name), nil, nil)
+ write_inheritable_attribute("default_api_method_instance", instance)
+ instance
+ end
+
+ # Creates a dummy API Method instance for the given public method name
+ def dummy_public_api_method_instance(public_method_name)
+ Method.new(public_method_name.underscore.to_sym, public_method_name, nil, nil)
+ end
+
+ # Creates a dummy API Method instance for the given method name
+ def dummy_api_method_instance(method_name)
+ Method.new(method_name, public_api_method_name(method_name), nil, nil)
+ end
+
private
def api_public_method_names
read_inheritable_attribute("api_public_method_names") || {}
@@ -131,5 +166,128 @@ module ActionWebService # :nodoc:
end
end
end
+
+ # Represents an API method and its associated metadata, and provides functionality
+ # to assist in commonly performed API method tasks.
+ class Method
+ attr :name
+ attr :public_name
+ attr :expects
+ attr :returns
+
+ def initialize(name, public_name, expects, returns)
+ @name = name
+ @public_name = public_name
+ @expects = expects
+ @returns = returns
+ end
+
+ # The list of parameter names for this method
+ def param_names
+ return [] unless @expects
+ i = 0
+ @expects.map{ |spec| param_name(spec, i += 1) }
+ end
+
+ # The name for the given parameter
+ def param_name(spec, i=1)
+ spec.is_a?(Hash) ? spec.keys.first.to_s : "p#{i}"
+ end
+
+ # The type of the parameter declared in +spec+. Is either
+ # the Class of the parameter, or its canonical name (if its a
+ # base type). Typed array specifications will return the type of
+ # their elements.
+ def param_type(spec)
+ spec = spec.values.first if spec.is_a?(Hash)
+ param_type = spec.is_a?(Array) ? spec[0] : spec
+ WS::BaseTypes::class_to_type_name(param_type) rescue param_type
+ end
+
+ # The Class of the parameter declared in +spec+.
+ def param_class(spec)
+ type = param_type(spec)
+ type.is_a?(Symbol) ? WS::BaseTypes.type_name_to_class(type) : type
+ end
+
+ # Registers all types known to this method with the given marshaler
+ def register_types(marshaler)
+ @expects.each{ |x| marshaler.register_type(x) } if @expects
+ @returns.each{ |x| marshaler.register_type(x) } if @returns
+ end
+
+ # Encodes an RPC call for this method. Casting is performed if
+ # the <tt>:strict</tt> option is given.
+ def encode_rpc_call(marshaler, encoder, params, options={})
+ name = options[:method_name] || @public_name
+ expects = @expects || []
+ returns = @returns || []
+ (expects + returns).each { |spec| marshaler.register_type spec }
+ (0..(params.length-1)).each do |i|
+ spec = expects[i] || params[i].class
+ type_binding = marshaler.lookup_type(spec)
+ param_info = WS::ParamInfo.create(spec, type_binding, i)
+ if options[:strict]
+ value = marshaler.cast_outbound_recursive(params[i], spec)
+ else
+ value = params[i]
+ end
+ param = WS::Param.new(value, param_info)
+ params[i] = marshaler.marshal(param)
+ end
+ encoder.encode_rpc_call(name, params)
+ end
+
+ # Encodes an RPC response for this method. Casting is performed if
+ # the <tt>:strict</tt> option is given.
+ def encode_rpc_response(marshaler, encoder, return_value, options={})
+ if !return_value.nil? && @returns
+ return_type = @returns[0]
+ type_binding = marshaler.register_type(return_type)
+ param_info = WS::ParamInfo.create(return_type, type_binding, 0)
+ if options[:strict]
+ return_value = marshaler.cast_inbound_recursive(return_value, return_type)
+ end
+ return_value = marshaler.marshal(WS::Param.new(return_value, param_info))
+ else
+ return_value = nil
+ end
+ encoder.encode_rpc_response(response_name(encoder), return_value)
+ end
+
+ # Casts a set of WS::Param values into the appropriate
+ # Ruby values
+ def cast_expects_ws2ruby(marshaler, params)
+ return [] if @expects.nil?
+ i = 0
+ @expects.map do |spec|
+ value = marshaler.cast_inbound_recursive(params[i].value, spec)
+ i += 1
+ value
+ end
+ end
+
+ # Casts a set of Ruby values into the expected Ruby values
+ def cast_expects(marshaler, params)
+ return [] if @expects.nil?
+ i = 0
+ @expects.map do |spec|
+ value = marshaler.cast_outbound_recursive(params[i], spec)
+ i += 1
+ value
+ end
+ end
+
+ # Cast a Ruby return value into the expected Ruby value
+ def cast_returns(marshaler, return_value)
+ return nil if @returns.nil?
+ marshaler.cast_inbound_recursive(return_value, @returns[0])
+ end
+
+ private
+ def response_name(encoder)
+ encoder.is_a?(WS::Encoding::SoapRpcEncoding) ? (@public_name + "Response") : @public_name
+ end
+ end
end
end