Skip to content

Commit

Permalink
Renamed presenter to renderer, added some documentation and defined i…
Browse files Browse the repository at this point in the history
…ts API.
  • Loading branch information
josevalim committed Aug 7, 2009
1 parent 1fd65c8 commit aed135d
Show file tree
Hide file tree
Showing 18 changed files with 294 additions and 241 deletions.
4 changes: 2 additions & 2 deletions actionpack/examples/very_simple.rb
Expand Up @@ -6,7 +6,7 @@
class Kaigi < ActionController::Metal
include AbstractController::Callbacks
include ActionController::RackConvenience
include ActionController::Renderer
include ActionController::RenderingController
include ActionController::Layouts
include ActionView::Context

Expand Down Expand Up @@ -47,4 +47,4 @@ def set_name
map("/kaigi/alt") { run Kaigi.action(:alt) }
end.to_app

Rack::Handler::Mongrel.run app, :Port => 3000
Rack::Handler::Mongrel.run app, :Port => 3000
20 changes: 10 additions & 10 deletions actionpack/lib/abstract_controller.rb
Expand Up @@ -2,15 +2,15 @@
require "active_support/core_ext/module/delegation"

module AbstractController
autoload :Base, "abstract_controller/base"
autoload :Benchmarker, "abstract_controller/benchmarker"
autoload :Callbacks, "abstract_controller/callbacks"
autoload :Helpers, "abstract_controller/helpers"
autoload :Layouts, "abstract_controller/layouts"
autoload :Logger, "abstract_controller/logger"
autoload :Renderer, "abstract_controller/renderer"
autoload :Base, "abstract_controller/base"
autoload :Benchmarker, "abstract_controller/benchmarker"
autoload :Callbacks, "abstract_controller/callbacks"
autoload :Helpers, "abstract_controller/helpers"
autoload :Layouts, "abstract_controller/layouts"
autoload :Logger, "abstract_controller/logger"
autoload :RenderingController, "abstract_controller/rendering_controller"
# === Exceptions
autoload :ActionNotFound, "abstract_controller/exceptions"
autoload :DoubleRenderError, "abstract_controller/exceptions"
autoload :Error, "abstract_controller/exceptions"
autoload :ActionNotFound, "abstract_controller/exceptions"
autoload :DoubleRenderError, "abstract_controller/exceptions"
autoload :Error, "abstract_controller/exceptions"
end
2 changes: 1 addition & 1 deletion actionpack/lib/abstract_controller/helpers.rb
Expand Up @@ -2,7 +2,7 @@ module AbstractController
module Helpers
extend ActiveSupport::Concern

include Renderer
include RenderingController

included do
extlib_inheritable_accessor(:_helpers) { Module.new }
Expand Down
2 changes: 1 addition & 1 deletion actionpack/lib/abstract_controller/layouts.rb
Expand Up @@ -2,7 +2,7 @@ module AbstractController
module Layouts
extend ActiveSupport::Concern

include Renderer
include RenderingController

included do
extlib_inheritable_accessor(:_layout_conditions) { Hash.new }
Expand Down
@@ -1,7 +1,7 @@
require "abstract_controller/logger"

module AbstractController
module Renderer
module RenderingController
extend ActiveSupport::Concern

include AbstractController::Logger
Expand Down Expand Up @@ -67,7 +67,7 @@ def render_to_body(options = {})
#
# :api: plugin
def render_to_string(options = {})
AbstractController::Renderer.body_to_s(render_to_body(options))
AbstractController::RenderingController.body_to_s(render_to_body(options))
end

# Renders the template from an object.
Expand Down
4 changes: 2 additions & 2 deletions actionpack/lib/action_controller.rb
Expand Up @@ -8,8 +8,8 @@ module ActionController
autoload :Rails2Compatibility, "action_controller/metal/compatibility"
autoload :Redirector, "action_controller/metal/redirector"
autoload :Renderer, "action_controller/metal/renderer"
autoload :RenderingController, "action_controller/metal/rendering_controller"
autoload :RenderOptions, "action_controller/metal/render_options"
autoload :Renderers, "action_controller/metal/render_options"
autoload :Rescue, "action_controller/metal/rescuable"
autoload :Testing, "action_controller/metal/testing"
autoload :UrlFor, "action_controller/metal/url_for"
Expand Down Expand Up @@ -69,4 +69,4 @@ module ActionController
require 'active_support/core_ext/module/attr_internal'
require 'active_support/core_ext/module/delegation'
require 'active_support/core_ext/name_error'
require 'active_support/inflector'
require 'active_support/inflector'
4 changes: 2 additions & 2 deletions actionpack/lib/action_controller/base.rb
Expand Up @@ -10,8 +10,8 @@ class Base < Metal
include ActionController::HideActions
include ActionController::UrlFor
include ActionController::Redirector
include ActionController::Renderer
include ActionController::Renderers::All
include ActionController::RenderingController
include ActionController::RenderOptions::All
include ActionController::Layouts
include ActionController::ConditionalGet
include ActionController::RackConvenience
Expand Down
2 changes: 1 addition & 1 deletion actionpack/lib/action_controller/metal/layouts.rb
Expand Up @@ -158,7 +158,7 @@ module ActionController
module Layouts
extend ActiveSupport::Concern

include ActionController::Renderer
include ActionController::RenderingController
include AbstractController::Layouts

module ClassMethods
Expand Down
162 changes: 10 additions & 152 deletions actionpack/lib/action_controller/metal/mime_responds.rb
@@ -1,146 +1,4 @@
module ActionController #:nodoc:

# Presenter is responsible to expose a resource for different mime requests,
# usually depending on the HTTP verb. The presenter is triggered when
# respond_with is called. The simplest case to study is a GET request:
#
# class PeopleController < ApplicationController
# respond_to :html, :xml, :json
#
# def index
# @people = Person.find(:all)
# respond_with(@people)
# end
# end
#
# When a request comes, for example with format :xml, three steps happen:
#
# 1) respond_with searches for a template at people/index.xml;
#
# 2) if the template is not available, it will create a presenter, passing
# the controller and the resource, and invoke :to_xml on it;
#
# 3) if the presenter does not respond_to :to_xml, call to_format on it.
#
# === Builtin HTTP verb semantics
#
# Rails default presenter holds semantics for each HTTP verb. Depending on the
# content type, verb and the resource status, it will behave differently.
#
# Using Rails default presenter, a POST request could be written as:
#
# def create
# @user = User.new(params[:user])
# flash[:notice] = 'User was successfully created.' if @user.save
# respond_with(@user)
# end
#
# Which is exactly the same as:
#
# def create
# @user = User.new(params[:user])
#
# respond_to do |format|
# if @user.save
# flash[:notice] = 'User was successfully created.'
# format.html { redirect_to(@user) }
# format.xml { render :xml => @user, :status => :created, :location => @user }
# else
# format.html { render :action => "new" }
# format.xml { render :xml => @user.errors, :status => :unprocessable_entity }
# end
# end
# end
#
# The same happens for PUT and DELETE requests. By default, it accepts just
# :location as parameter, which is used as redirect destination, in both
# POST, PUT, DELETE requests for HTML mime, as in the example below:
#
# def destroy
# @person = Person.find(params[:id])
# @person.destroy
# respond_with(@person, :location => root_url)
# end
#
# === Nested resources
#
# You can given nested resource as you do in form_for and polymorphic_url.
# Consider the project has many tasks example. The create action for
# TasksController would be like:
#
# def create
# @project = Project.find(params[:project_id])
# @task = @project.comments.build(params[:task])
# flash[:notice] = 'Task was successfully created.' if @task.save
# respond_with([@project, @task])
# end
#
# Given a nested resource, you ensure that the presenter will redirect to
# project_task_url instead of task_url.
#
# Namespaced and singleton resources requires a symbol to be given, as in
# polymorphic urls. If a project has one manager which has many tasks, it
# should be invoked as:
#
# respond_with([@project, :manager, @task])
#
# Check polymorphic_url documentation for more examples.
#
class Presenter
attr_reader :controller, :request, :format, :resource, :resource_location, :options

def initialize(controller, resource, options)
@controller = controller
@request = controller.request
@format = controller.formats.first
@resource = resource.is_a?(Array) ? resource.last : resource
@resource_location = options[:location] || resource
@options = options
end

delegate :head, :render, :redirect_to, :to => :controller
delegate :get?, :post?, :put?, :delete?, :to => :request

# Undefine :to_json since it's defined on Object
undef_method :to_json

def to_html
if get?
render
elsif has_errors?
render :action => default_action
else
redirect_to resource_location
end
end

def to_format
return render unless resourceful?

if get?
render format => resource
elsif has_errors?
render format => resource.errors, :status => :unprocessable_entity
elsif post?
render format => resource, :status => :created, :location => resource_location
else
head :ok
end
end

def resourceful?
resource.respond_to?(:"to_#{format}")
end

def has_errors?
resource.respond_to?(:errors) && !resource.errors.empty?
end

def default_action
request.post? ? :new : :edit
end
end

module MimeResponds #:nodoc:
extend ActiveSupport::Concern

Expand Down Expand Up @@ -339,10 +197,10 @@ def respond_to(*mimes, &block)
end
end

# respond_with wraps a resource around a presenter for default representation.
# respond_with wraps a resource around a renderer for default representation.
# First it invokes respond_to, if a response cannot be found (ie. no block
# for the request was given and template was not available), it instantiates
# an ActionController::Presenter with the controller and resource.
# an ActionController::Renderer with the controller and resource.
#
# ==== Example
#
Expand All @@ -363,19 +221,19 @@ def respond_to(*mimes, &block)
# end
# end
#
# All options given to respond_with are sent to the underlying presenter.
# All options given to respond_with are sent to the underlying renderer,
# except for the option :renderer itself. Since the renderer interface
# is quite simple (it just needs to respond to call), you can even give
# a proc to it.
#
def respond_with(resource, options={}, &block)
respond_to(&block)
rescue ActionView::MissingTemplate
presenter = ActionController::Presenter.new(self, resource, options)
format_method = :"to_#{self.formats.first}"
(options.delete(:renderer) || renderer).call(self, resource, options)
end

if presenter.respond_to?(format_method)
presenter.send(format_method)
else
presenter.to_format
end
def renderer
ActionController::Renderer
end

protected
Expand Down
10 changes: 5 additions & 5 deletions actionpack/lib/action_controller/metal/render_options.rb
Expand Up @@ -47,7 +47,7 @@ def base.register_renderer(name)
end
end

module Renderers
module RenderOptions
module Json
extend RenderOption
register_renderer :json
Expand Down Expand Up @@ -94,10 +94,10 @@ def render_update(proc, options)
module All
extend ActiveSupport::Concern

include ActionController::Renderers::Json
include ActionController::Renderers::Js
include ActionController::Renderers::Xml
include ActionController::Renderers::RJS
include ActionController::RenderOptions::Json
include ActionController::RenderOptions::Js
include ActionController::RenderOptions::Xml
include ActionController::RenderOptions::RJS
end
end
end

0 comments on commit aed135d

Please sign in to comment.