aboutsummaryrefslogtreecommitdiffstats
path: root/actionwebservice/lib/action_web_service/scaffolding.rb
diff options
context:
space:
mode:
Diffstat (limited to 'actionwebservice/lib/action_web_service/scaffolding.rb')
-rw-r--r--actionwebservice/lib/action_web_service/scaffolding.rb181
1 files changed, 181 insertions, 0 deletions
diff --git a/actionwebservice/lib/action_web_service/scaffolding.rb b/actionwebservice/lib/action_web_service/scaffolding.rb
new file mode 100644
index 0000000000..21790c101b
--- /dev/null
+++ b/actionwebservice/lib/action_web_service/scaffolding.rb
@@ -0,0 +1,181 @@
+require 'ostruct'
+require 'uri'
+
+module ActionWebService
+ module Scaffolding # :nodoc:
+ def self.append_features(base)
+ super
+ base.extend(ClassMethods)
+ end
+
+ # Web service invocation scaffolding provides a way to quickly invoke web service methods in a controller. The
+ # generated scaffold actions have default views to let you enter the method parameters and view the
+ # results.
+ #
+ # Example:
+ #
+ # class ApiController < ActionController
+ # web_service_scaffold :invoke
+ # end
+ #
+ # This example generates an +invoke+ action in the +ApiController+ that you can navigate to from
+ # your browser, select the API method, enter its parameters, and perform the invocation.
+ #
+ # If you want to customize the default views, create the following views in "app/views":
+ #
+ # * <tt>action_name/methods.rhtml</tt>
+ # * <tt>action_name/parameters.rhtml</tt>
+ # * <tt>action_name/result.rhtml</tt>
+ # * <tt>action_name/layout.rhtml</tt>
+ #
+ # Where <tt>action_name</tt> is the name of the action you gave to ClassMethods#web_service_scaffold.
+ #
+ # You can use the default views in <tt>RAILS_DIR/lib/action_web_service/templates/scaffolds</tt> as
+ # a guide.
+ module ClassMethods
+ # Generates web service invocation scaffolding for the current controller. The given action name
+ # can then be used as the entry point for invoking API methods from a web browser.
+ def web_service_scaffold(action_name)
+ add_template_helper(Helpers)
+ module_eval <<-END, __FILE__, __LINE__
+ def #{action_name}
+ if @request.method == :get
+ setup_#{action_name}_assigns
+ render_#{action_name}_scaffold 'methods'
+ end
+ end
+
+ def #{action_name}_method_params
+ if @request.method == :get
+ setup_#{action_name}_assigns
+ render_#{action_name}_scaffold 'parameters'
+ end
+ end
+
+ def #{action_name}_submit
+ if @request.method == :post
+ setup_#{action_name}_assigns
+ protocol_name = @params['protocol'] ? @params['protocol'].to_sym : :soap
+ case protocol_name
+ when :soap
+ protocol = Protocol::Soap::SoapProtocol.new
+ when :xmlrpc
+ protocol = Protocol::XmlRpc::XmlRpcProtocol.new
+ end
+ @method_request_xml = @scaffold_method.encode_rpc_call(protocol.marshaler, protocol.encoder, @params['method_params'].dup)
+ cgi = @request.cgi
+ @request = protocol.create_action_pack_request(@scaffold_service.name, @scaffold_method.public_name, @method_request_xml)
+ dispatch_web_service_request
+ @method_response_xml = @response.body
+ @method_return_value = protocol.marshaler.unmarshal(protocol.encoder.decode_rpc_response(@method_response_xml)[1]).value
+ add_instance_variables_to_assigns
+ @response = ::ActionController::CgiResponse.new(cgi)
+ @performed_render = false
+ render_#{action_name}_scaffold 'result'
+ end
+ end
+
+ private
+ def setup_#{action_name}_assigns
+ @scaffold_class = self.class
+ @scaffold_action_name = "#{action_name}"
+ @scaffold_container = WebServiceModel::Container.new(self)
+ if @params['service'] && @params['method']
+ @scaffold_service = @scaffold_container.services.find{ |x| x.name == @params['service'] }
+ @scaffold_method = @scaffold_service.api_methods[@params['method']]
+ end
+ add_instance_variables_to_assigns
+ end
+
+ def render_#{action_name}_scaffold(action)
+ customized_template = "\#{self.class.controller_path}/#{action_name}/\#{action}"
+ default_template = scaffold_path(action)
+ @content_for_layout = template_exists?(customized_template) ? @template.render_file(customized_template) : @template.render_file(default_template, false)
+ self.active_layout ? render_file(self.active_layout, "200 OK", true) : render_file(scaffold_path("layout"))
+ end
+
+ def scaffold_path(template_name)
+ File.dirname(__FILE__) + "/templates/scaffolds/" + template_name + ".rhtml"
+ end
+ END
+ end
+ end
+
+ module Helpers # :nodoc:
+ def method_parameter_input_fields(method, param_spec, i)
+ klass = method.param_class(param_spec)
+ unless WS::BaseTypes.base_type?(klass)
+ name = method.param_name(param_spec, i)
+ raise "Parameter #{name}: Structured/array types not supported in scaffolding input fields yet"
+ end
+ type_name = method.param_type(param_spec)
+ field_name = "method_params[]"
+ case type_name
+ when :int
+ text_field_tag field_name
+ when :string
+ text_field_tag field_name
+ when :bool
+ radio_button_tag field_name, "True"
+ radio_button_tag field_name, "False"
+ when :float
+ text_field_tag field_name
+ when :time
+ select_datetime Time.now, 'name' => field_name
+ when :date
+ select_date Date.today, 'name' => field_name
+ end
+ end
+
+ def service_method_list(service)
+ action = @scaffold_action_name + '_method_params'
+ methods = service.api_methods_full.map do |desc, name|
+ content_tag("li", link_to(desc, :action => action, :service => service.name, :method => name))
+ end
+ content_tag("ul", methods.join("\n"))
+ end
+ end
+
+ module WebServiceModel # :nodoc:
+ class Container # :nodoc:
+ attr :services
+
+ def initialize(real_container)
+ @real_container = real_container
+ @services = []
+ if @real_container.class.web_service_dispatching_mode == :direct
+ @services << Service.new(@real_container.controller_name, @real_container)
+ else
+ @real_container.class.web_services.each do |name|
+ @services << Service.new(name, @real_container.instance_eval{ web_service_object(name) })
+ end
+ end
+ end
+ end
+
+ class Service # :nodoc:
+ attr :name
+ attr :object
+ attr :api
+ attr :api_methods
+ attr :api_methods_full
+
+ def initialize(name, real_service)
+ @name = name.to_s
+ @object = real_service
+ @api = @object.class.web_service_api
+ @api_methods = {}
+ @api_methods_full = []
+ @api.api_methods.each do |name, method|
+ @api_methods[method.public_name.to_s] = method
+ @api_methods_full << [method.to_s, method.public_name.to_s]
+ end
+ end
+
+ def to_s
+ self.name.camelize
+ end
+ end
+ end
+ end
+end