2009-09-14 15:47:31 -04:00
|
|
|
require 'active_support/core_ext/class/inheritable_attributes'
|
|
|
|
|
2009-05-01 20:27:44 -04:00
|
|
|
module ActionController
|
2009-08-06 18:50:22 -04:00
|
|
|
# ActionController::Metal provides a way to get a valid Rack application from a controller.
|
2009-06-10 18:27:53 -04:00
|
|
|
#
|
|
|
|
# In AbstractController, dispatching is triggered directly by calling #process on a new controller.
|
2009-08-06 18:50:22 -04:00
|
|
|
# ActionController::Metal provides an #action method that returns a valid Rack application for a
|
2009-06-10 18:27:53 -04:00
|
|
|
# given action. Other rack builders, such as Rack::Builder, Rack::URLMap, and the Rails router,
|
|
|
|
# can dispatch directly to the action returned by FooController.action(:index).
|
2009-08-06 18:50:22 -04:00
|
|
|
class Metal < AbstractController::Base
|
2009-05-01 20:27:44 -04:00
|
|
|
abstract!
|
2009-05-28 10:49:02 -04:00
|
|
|
|
2009-05-01 20:27:44 -04:00
|
|
|
# :api: public
|
2009-05-27 04:40:43 -04:00
|
|
|
attr_internal :params, :env
|
2009-05-01 20:27:44 -04:00
|
|
|
|
2009-06-10 18:27:53 -04:00
|
|
|
# Returns the last part of the controller's name, underscored, without the ending
|
|
|
|
# "Controller". For instance, MyApp::MyPostsController would return "my_posts" for
|
|
|
|
# controller_name
|
|
|
|
#
|
|
|
|
# ==== Returns
|
|
|
|
# String
|
2009-05-01 20:27:44 -04:00
|
|
|
def self.controller_name
|
|
|
|
@controller_name ||= controller_path.split("/").last
|
|
|
|
end
|
|
|
|
|
2009-06-10 18:27:53 -04:00
|
|
|
# Delegates to the class' #controller_name
|
2009-05-28 10:49:02 -04:00
|
|
|
def controller_name
|
|
|
|
self.class.controller_name
|
|
|
|
end
|
2009-05-01 20:27:44 -04:00
|
|
|
|
2009-06-10 18:27:53 -04:00
|
|
|
# Returns the full controller name, underscored, without the ending Controller.
|
|
|
|
# For instance, MyApp::MyPostsController would return "my_app/my_posts" for
|
|
|
|
# controller_name.
|
|
|
|
#
|
|
|
|
# ==== Returns
|
|
|
|
# String
|
2009-05-01 20:27:44 -04:00
|
|
|
def self.controller_path
|
2009-06-23 17:04:04 -04:00
|
|
|
@controller_path ||= name && name.sub(/Controller$/, '').underscore
|
2009-05-01 20:27:44 -04:00
|
|
|
end
|
2009-05-28 10:49:02 -04:00
|
|
|
|
2009-06-10 18:27:53 -04:00
|
|
|
# Delegates to the class' #controller_path
|
2009-05-28 10:49:02 -04:00
|
|
|
def controller_path
|
|
|
|
self.class.controller_path
|
|
|
|
end
|
|
|
|
|
2009-05-27 04:40:43 -04:00
|
|
|
# The details below can be overridden to support a specific
|
|
|
|
# Request and Response object. The default ActionController::Base
|
2009-12-20 21:05:26 -05:00
|
|
|
# implementation includes RackDelegation, which makes a request
|
2009-05-27 04:40:43 -04:00
|
|
|
# and response object available. You might wish to control the
|
|
|
|
# environment and response manually for performance reasons.
|
2009-05-20 19:38:48 -04:00
|
|
|
|
2009-11-05 18:38:04 -05:00
|
|
|
attr_internal :status, :headers, :content_type, :response
|
2009-05-27 04:40:43 -04:00
|
|
|
|
|
|
|
def initialize(*)
|
|
|
|
@_headers = {}
|
|
|
|
super
|
|
|
|
end
|
|
|
|
|
2009-06-10 18:27:53 -04:00
|
|
|
# Basic implementations for content_type=, location=, and headers are
|
2009-12-20 21:05:26 -05:00
|
|
|
# provided to reduce the dependency on the RackDelegation module
|
|
|
|
# in Renderer and Redirector.
|
2009-05-27 04:40:43 -04:00
|
|
|
|
|
|
|
def content_type=(type)
|
|
|
|
headers["Content-Type"] = type.to_s
|
|
|
|
end
|
|
|
|
|
|
|
|
def location=(url)
|
|
|
|
headers["Location"] = url
|
2009-05-12 19:21:34 -04:00
|
|
|
end
|
2009-05-28 10:49:02 -04:00
|
|
|
|
2009-12-20 21:50:47 -05:00
|
|
|
def status=(status)
|
2009-12-22 17:08:03 -05:00
|
|
|
@_status = Rack::Utils.status_code(status)
|
2009-12-20 21:50:47 -05:00
|
|
|
end
|
|
|
|
|
2009-05-01 20:27:44 -04:00
|
|
|
# :api: private
|
2009-11-05 18:38:04 -05:00
|
|
|
def dispatch(name, env)
|
2009-05-27 04:40:43 -04:00
|
|
|
@_env = env
|
2009-05-02 05:15:09 -04:00
|
|
|
process(name)
|
2009-08-06 19:05:14 -04:00
|
|
|
to_a
|
2009-05-02 05:15:09 -04:00
|
|
|
end
|
2009-05-28 10:49:02 -04:00
|
|
|
|
2009-05-27 04:40:43 -04:00
|
|
|
# :api: private
|
2009-08-06 19:05:14 -04:00
|
|
|
def to_a
|
2009-08-25 15:14:31 -04:00
|
|
|
response ? response.to_a : [status, headers, response_body]
|
|
|
|
end
|
|
|
|
|
|
|
|
class ActionEndpoint
|
2009-12-28 19:28:26 -05:00
|
|
|
@@endpoints = Hash.new {|h,k| h[k] = Hash.new {|sh,sk| sh[sk] = {} } }
|
2009-09-12 16:38:34 -04:00
|
|
|
|
|
|
|
def self.for(controller, action, stack)
|
|
|
|
@@endpoints[controller][action][stack] ||= begin
|
|
|
|
endpoint = new(controller, action)
|
|
|
|
stack.build(endpoint)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-08-25 15:14:31 -04:00
|
|
|
def initialize(controller, action)
|
|
|
|
@controller, @action = controller, action
|
2009-12-20 21:50:47 -05:00
|
|
|
@_formats = [Mime::HTML]
|
2009-08-25 15:14:31 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def call(env)
|
2009-11-05 18:38:04 -05:00
|
|
|
@controller.new.dispatch(@action, env)
|
2009-08-25 15:14:31 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2009-09-12 14:51:15 -04:00
|
|
|
extlib_inheritable_accessor(:middleware_stack) { ActionDispatch::MiddlewareStack.new }
|
|
|
|
|
|
|
|
def self.use(*args)
|
|
|
|
middleware_stack.use(*args)
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.middleware
|
|
|
|
middleware_stack
|
|
|
|
end
|
|
|
|
|
2009-10-20 17:03:55 -04:00
|
|
|
def self.call(env)
|
|
|
|
action(env['action_dispatch.request.path_parameters'][:action]).call(env)
|
|
|
|
end
|
|
|
|
|
2009-06-10 18:27:53 -04:00
|
|
|
# Return a rack endpoint for the given action. Memoize the endpoint, so
|
|
|
|
# multiple calls into MyController.action will return the same object
|
|
|
|
# for the same action.
|
|
|
|
#
|
|
|
|
# ==== Parameters
|
|
|
|
# action<#to_s>:: An action name
|
|
|
|
#
|
|
|
|
# ==== Returns
|
|
|
|
# Proc:: A rack application
|
2009-05-02 05:15:09 -04:00
|
|
|
def self.action(name)
|
2009-09-12 16:38:34 -04:00
|
|
|
ActionEndpoint.for(self, name, middleware_stack)
|
2009-08-25 15:14:31 -04:00
|
|
|
end
|
2009-05-01 20:27:44 -04:00
|
|
|
end
|
|
|
|
end
|