diff options
Diffstat (limited to 'actionwebservice')
11 files changed, 226 insertions, 230 deletions
diff --git a/actionwebservice/Rakefile b/actionwebservice/Rakefile index 57940f6b9f..65026cdaef 100644 --- a/actionwebservice/Rakefile +++ b/actionwebservice/Rakefile @@ -25,7 +25,7 @@ task :default => [ :test ] # Run the unit tests Rake::TestTask.new { |t| t.libs << "test" - t.test_files = Dir['test/*_test.rb'] + Dir['test/ws/*_test.rb'] + t.test_files = Dir['test/*_test.rb'] t.verbose = true } diff --git a/actionwebservice/lib/action_web_service/api.rb b/actionwebservice/lib/action_web_service/api.rb index ab8b696ab4..4548856d86 100644 --- a/actionwebservice/lib/action_web_service/api.rb +++ b/actionwebservice/lib/action_web_service/api.rb @@ -1 +1,204 @@ -require 'action_web_service/api/base' +module ActionWebService # :nodoc: + module API # :nodoc: + # 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. + # + # It is not intended to be instantiated. + # + # It is attached to web service implementation classes like + # ActionWebService::Base and ActionController::Base derivatives by using + # ClassMethods#web_service_api. + class Base + # Whether to transform the public API method names into camel-cased names + class_inheritable_option :inflect_names, true + + # Whether to allow ActiveRecord::Base models in <tt>:expects</tt>. + # The default is +false+, you should be aware of the security implications + # of allowing this, and ensure that you don't allow remote callers to + # easily overwrite data they should not have access to. + class_inheritable_option :allow_active_record_expects, false + + # If present, the name of a method to call when the remote caller + # tried to call a nonexistent method. Semantically equivalent to + # +method_missing+. + class_inheritable_option :default_api_method + + # Disallow instantiation + private_class_method :new, :allocate + + class << self + include ActionWebService::SignatureTypes + + # API methods have a +name+, which must be the Ruby method name to use when + # performing the invocation on the web service object. + # + # The signatures for the method input parameters and return value can + # by specified in +options+. + # + # A signature is an array of one or more parameter specifiers. + # A parameter specifier can be one of the following: + # + # * A symbol or string of representing one of the Action Web Service base types. + # See ActionWebService::Signature for a canonical list of the base types. + # * The Class object of the parameter type + # * A single-element Array containing one of the two preceding items. This + # will cause Action Web Service to treat the parameter at that position + # as an array containing only values of the given type. + # * A Hash containing as key the name of the parameter, and as value + # one of the three preceding items + # + # If no method input parameter or method return value signatures are given, + # the method is assumed to take no parameters and/or return no values of + # interest, and any values that are received by the server will be + # discarded and ignored. + # + # Valid options: + # [<tt>:expects</tt>] Signature for the method input parameters + # [<tt>:returns</tt>] Signature for the method return value + # [<tt>:expects_and_returns</tt>] Signature for both input parameters and return value + def api_method(name, options={}) + validate_options([:expects, :returns, :expects_and_returns], options.keys) + if options[:expects_and_returns] + expects = options[:expects_and_returns] + returns = options[:expects_and_returns] + else + expects = options[:expects] + returns = options[:returns] + end + expects = canonical_signature(expects) + returns = canonical_signature(returns) + if expects + expects.each do |type| + type = type.element_type if type.is_a?(ArrayType) + if type.type_class.ancestors.include?(ActiveRecord::Base) && !allow_active_record_expects + raise(ActionWebServiceError, "ActiveRecord model classes not allowed in :expects") + end + end + end + name = name.to_sym + public_name = public_api_method_name(name) + 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 + + # Whether the given method name is a service method on this API + def has_api_method?(name) + api_methods.has_key?(name) + end + + # Whether the given public method name has a corresponding service method + # on this API + def has_public_api_method?(public_name) + api_public_method_names.has_key?(public_name) + end + + # The corresponding public method name for the given service method name + def public_api_method_name(name) + if inflect_names + name.to_s.camelize + else + name.to_s + end + end + + # The corresponding service method name for the given public method name + def api_method_name(public_name) + api_public_method_names[public_name] + end + + # A Hash containing all service methods on this API, and their + # associated metadata. + 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 + + private + def api_public_method_names + read_inheritable_attribute("api_public_method_names") || {} + end + + def validate_options(valid_option_keys, supplied_option_keys) + unknown_option_keys = supplied_option_keys - valid_option_keys + unless unknown_option_keys.empty? + raise(ActionWebServiceError, "Unknown options: #{unknown_option_keys}") + end + 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 + @caster = ActionWebService::Casting::BaseCaster.new(self) + end + + # The list of parameter names for this method + def param_names + return [] unless @expects + @expects.map{ |type| type.name } + end + + # Casts a set of Ruby values into the expected Ruby values + def cast_expects(params) + @caster.cast_expects(params) + end + + # Cast a Ruby return value into the expected Ruby value + def cast_returns(return_value) + @caster.cast_returns(return_value) + end + + # String representation of this method + def to_s + fqn = "" + fqn << (@returns ? (friendly_param(@returns[0], false) + " ") : "void ") + fqn << "#{@public_name}(" + fqn << @expects.map{ |p| friendly_param(p) }.join(", ") if @expects + fqn << ")" + fqn + end + + private + def friendly_param(type, show_name=true) + name = type.name.to_s + type_type = type.array?? type.element_type.type.to_s : type.type.to_s + str = type.array?? (type_type + '[]') : type_type + show_name ? (str + " " + name) : str + end + end + end +end diff --git a/actionwebservice/lib/action_web_service/api/base.rb b/actionwebservice/lib/action_web_service/api/base.rb deleted file mode 100644 index 4548856d86..0000000000 --- a/actionwebservice/lib/action_web_service/api/base.rb +++ /dev/null @@ -1,204 +0,0 @@ -module ActionWebService # :nodoc: - module API # :nodoc: - # 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. - # - # It is not intended to be instantiated. - # - # It is attached to web service implementation classes like - # ActionWebService::Base and ActionController::Base derivatives by using - # ClassMethods#web_service_api. - class Base - # Whether to transform the public API method names into camel-cased names - class_inheritable_option :inflect_names, true - - # Whether to allow ActiveRecord::Base models in <tt>:expects</tt>. - # The default is +false+, you should be aware of the security implications - # of allowing this, and ensure that you don't allow remote callers to - # easily overwrite data they should not have access to. - class_inheritable_option :allow_active_record_expects, false - - # If present, the name of a method to call when the remote caller - # tried to call a nonexistent method. Semantically equivalent to - # +method_missing+. - class_inheritable_option :default_api_method - - # Disallow instantiation - private_class_method :new, :allocate - - class << self - include ActionWebService::SignatureTypes - - # API methods have a +name+, which must be the Ruby method name to use when - # performing the invocation on the web service object. - # - # The signatures for the method input parameters and return value can - # by specified in +options+. - # - # A signature is an array of one or more parameter specifiers. - # A parameter specifier can be one of the following: - # - # * A symbol or string of representing one of the Action Web Service base types. - # See ActionWebService::Signature for a canonical list of the base types. - # * The Class object of the parameter type - # * A single-element Array containing one of the two preceding items. This - # will cause Action Web Service to treat the parameter at that position - # as an array containing only values of the given type. - # * A Hash containing as key the name of the parameter, and as value - # one of the three preceding items - # - # If no method input parameter or method return value signatures are given, - # the method is assumed to take no parameters and/or return no values of - # interest, and any values that are received by the server will be - # discarded and ignored. - # - # Valid options: - # [<tt>:expects</tt>] Signature for the method input parameters - # [<tt>:returns</tt>] Signature for the method return value - # [<tt>:expects_and_returns</tt>] Signature for both input parameters and return value - def api_method(name, options={}) - validate_options([:expects, :returns, :expects_and_returns], options.keys) - if options[:expects_and_returns] - expects = options[:expects_and_returns] - returns = options[:expects_and_returns] - else - expects = options[:expects] - returns = options[:returns] - end - expects = canonical_signature(expects) - returns = canonical_signature(returns) - if expects - expects.each do |type| - type = type.element_type if type.is_a?(ArrayType) - if type.type_class.ancestors.include?(ActiveRecord::Base) && !allow_active_record_expects - raise(ActionWebServiceError, "ActiveRecord model classes not allowed in :expects") - end - end - end - name = name.to_sym - public_name = public_api_method_name(name) - 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 - - # Whether the given method name is a service method on this API - def has_api_method?(name) - api_methods.has_key?(name) - end - - # Whether the given public method name has a corresponding service method - # on this API - def has_public_api_method?(public_name) - api_public_method_names.has_key?(public_name) - end - - # The corresponding public method name for the given service method name - def public_api_method_name(name) - if inflect_names - name.to_s.camelize - else - name.to_s - end - end - - # The corresponding service method name for the given public method name - def api_method_name(public_name) - api_public_method_names[public_name] - end - - # A Hash containing all service methods on this API, and their - # associated metadata. - 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 - - private - def api_public_method_names - read_inheritable_attribute("api_public_method_names") || {} - end - - def validate_options(valid_option_keys, supplied_option_keys) - unknown_option_keys = supplied_option_keys - valid_option_keys - unless unknown_option_keys.empty? - raise(ActionWebServiceError, "Unknown options: #{unknown_option_keys}") - end - 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 - @caster = ActionWebService::Casting::BaseCaster.new(self) - end - - # The list of parameter names for this method - def param_names - return [] unless @expects - @expects.map{ |type| type.name } - end - - # Casts a set of Ruby values into the expected Ruby values - def cast_expects(params) - @caster.cast_expects(params) - end - - # Cast a Ruby return value into the expected Ruby value - def cast_returns(return_value) - @caster.cast_returns(return_value) - end - - # String representation of this method - def to_s - fqn = "" - fqn << (@returns ? (friendly_param(@returns[0], false) + " ") : "void ") - fqn << "#{@public_name}(" - fqn << @expects.map{ |p| friendly_param(p) }.join(", ") if @expects - fqn << ")" - fqn - end - - private - def friendly_param(type, show_name=true) - name = type.name.to_s - type_type = type.array?? type.element_type.type.to_s : type.type.to_s - str = type.array?? (type_type + '[]') : type_type - show_name ? (str + " " + name) : str - end - end - end -end diff --git a/actionwebservice/lib/action_web_service/casting.rb b/actionwebservice/lib/action_web_service/casting.rb index 42ef97fd3b..88462d8cc9 100644 --- a/actionwebservice/lib/action_web_service/casting.rb +++ b/actionwebservice/lib/action_web_service/casting.rb @@ -29,8 +29,7 @@ module ActionWebService # :nodoc: 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) } + api_method.expects.zip(params).map{ |type, param| cast(param, type) } end def cast_returns(api_method, return_value) # :nodoc: diff --git a/actionwebservice/lib/action_web_service/client/soap_client.rb b/actionwebservice/lib/action_web_service/client/soap_client.rb index c906a71331..79edac0b71 100644 --- a/actionwebservice/lib/action_web_service/client/soap_client.rb +++ b/actionwebservice/lib/action_web_service/client/soap_client.rb @@ -78,12 +78,10 @@ module ActionWebService # :nodoc: expects = method.expects returns = method.returns param_def = [] - i = 0 if expects expects.each do |type| type_binding = @protocol.marshaler.lookup_type(type) param_def << ['in', type.name, type_binding.mapping] - i += 1 end end if returns diff --git a/actionwebservice/lib/action_web_service/container/delegated_container.rb b/actionwebservice/lib/action_web_service/container/delegated_container.rb index 674141aab6..ae2c257c9c 100644 --- a/actionwebservice/lib/action_web_service/container/delegated_container.rb +++ b/actionwebservice/lib/action_web_service/container/delegated_container.rb @@ -79,7 +79,7 @@ module ActionWebService # :nodoc: raise(ContainerError, "no such web service '#{web_service_name}'") end service = info[:block] - service ? instance_eval(&service) : info[:object] + service ? self.instance_eval(&service) : info[:object] end end end diff --git a/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb b/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb index a4659e5183..822939a101 100644 --- a/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb +++ b/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb @@ -121,8 +121,7 @@ module ActionWebService # :nodoc: api_method = request.api_method params = request.method_params if api_method && api_method.expects - i = 0 - params = api_method.expects.map{ |type| param = "#{type.name}=>#{params[i].inspect}"; i+= 1; param } + params = api_method.expects.zip(params).map{ |type, param| "#{type.name}=>#{param.inspect}" } else params = params.map{ |param| param.inspect } end @@ -255,11 +254,9 @@ module ActionWebService # :nodoc: end else expects = method.expects - i = 1 expects.each do |type| binding = marshaler.register_type(type) xm.part('name' => type.name, 'type' => binding.qualified_type_name('typens')) - i += 1 end if expects end end diff --git a/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb b/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb index cc3e90a4cc..4bc9d2806e 100644 --- a/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb +++ b/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb @@ -40,13 +40,10 @@ module ActionWebService # :nodoc: param_types.each{ |type| marshaler.register_type(type) } if param_types qname = XSD::QName.new(marshaler.type_namespace, method_name) param_def = [] - i = 0 if param_types - params = params.map do |param| - param_type = param_types[i] - param_def << ['in', param_type.name, marshaler.lookup_type(param_type).mapping] - i += 1 - [param_type.name, marshaler.ruby_to_soap(param)] + params = param_types.zip(params).map do |type, param| + param_def << ['in', type.name, marshaler.lookup_type(type).mapping] + [type.name, marshaler.ruby_to_soap(param)] end else params = [] diff --git a/actionwebservice/lib/action_web_service/support/signature_types.rb b/actionwebservice/lib/action_web_service/support/signature_types.rb index 5c57254bc3..a7ee2fc773 100644 --- a/actionwebservice/lib/action_web_service/support/signature_types.rb +++ b/actionwebservice/lib/action_web_service/support/signature_types.rb @@ -9,12 +9,9 @@ module ActionWebService # :nodoc: def canonical_signature_entry(spec, i) name = "param#{i}" if spec.is_a?(Hash) - name = spec.keys.first - spec = spec.values.first - type = spec - else - type = spec + name, spec = spec.keys.first, spec.values.first end + type = spec if spec.is_a?(Array) ArrayType.new(canonical_signature_entry(spec[0], 0), name) else @@ -173,7 +170,7 @@ module ActionWebService # :nodoc: yield name, type end elsif @type_class.respond_to?(:columns) - i = 0 + i = -1 @type_class.columns.each do |column| yield column.name, canonical_signature_entry(column.klass, i += 1) end diff --git a/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.rhtml b/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.rhtml index 64548360ad..f06b0986b4 100644 --- a/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.rhtml +++ b/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.rhtml @@ -10,13 +10,11 @@ </p> <strong>Method Parameters:</strong><br /> -<% i = 0 %> <% @scaffold_method.expects.each do |type| %> <p> <label for="method_params[]"><%= type.name.to_s.camelize %></label><br /> <%= method_parameter_input_fields(@scaffold_method, type) %> </p> - <% i += 1 %> <% end %> <%= submit_tag "Invoke" %> diff --git a/actionwebservice/lib/action_web_service/test_invoke.rb b/actionwebservice/lib/action_web_service/test_invoke.rb index 119bc21f68..18b18ef746 100644 --- a/actionwebservice/lib/action_web_service/test_invoke.rb +++ b/actionwebservice/lib/action_web_service/test_invoke.rb @@ -83,7 +83,18 @@ module Test # :nodoc: end def protocol - @protocol ||= ActionWebService::Protocol::Soap::SoapProtocol.new + if @protocol.nil? + @protocol ||= ActionWebService::Protocol::Soap::SoapProtocol.new + else + case @protocol + when :xmlrpc + @protocol = ActionWebService::Protocol::XmlRpc::XmlRpcProtocol.new + when :soap + @protocol = ActionWebService::Protocol::Soap::SoapProtocol.new + else + @protocol + end + end end def is_exception?(obj) |