aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionwebservice/Rakefile2
-rw-r--r--actionwebservice/lib/action_web_service/api.rb205
-rw-r--r--actionwebservice/lib/action_web_service/api/base.rb204
-rw-r--r--actionwebservice/lib/action_web_service/casting.rb3
-rw-r--r--actionwebservice/lib/action_web_service/client/soap_client.rb2
-rw-r--r--actionwebservice/lib/action_web_service/container/delegated_container.rb2
-rw-r--r--actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb5
-rw-r--r--actionwebservice/lib/action_web_service/protocol/soap_protocol.rb9
-rw-r--r--actionwebservice/lib/action_web_service/support/signature_types.rb9
-rw-r--r--actionwebservice/lib/action_web_service/templates/scaffolds/parameters.rhtml2
-rw-r--r--actionwebservice/lib/action_web_service/test_invoke.rb13
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)