提交 2db7304c 编写于 作者: A Aaron Patterson

create a new renderer instance on calls to `for`

This changes the renderer class to store the controller and defaults as
an instance variable rather than allocating a new class.  You can create
a new renderer with an new env by calling `Renderer#new` or use new
defaults by calling `Renderer#with_defaults` and saving the return value
somewhere.

Also I want to keep the `env` private since I would like to change the
keys in the future.  This commit only translates particular keys that
the user requested.
上级 8e489db9
......@@ -34,67 +34,74 @@ module ActionController
# ApplicationController.renderer.new(method: 'post', https: true)
#
class Renderer
class_attribute :controller, :defaults
# Rack environment to render templates in.
attr_reader :env
attr_reader :defaults, :controller
class << self
delegate :render, to: :new
DEFAULTS = {
http_host: 'example.org',
https: false,
method: 'get',
script_name: '',
input: ''
}.freeze
# Create a new renderer class for a specific controller class.
def for(controller)
Class.new self do
self.controller = controller
self.defaults = {
http_host: 'example.org',
https: false,
method: 'get',
script_name: '',
'rack.input' => ''
}
end
end
# Create a new renderer instance for a specific controller class.
def self.for(controller, env = {}, defaults = DEFAULTS)
new(controller, env, defaults)
end
# Create a new renderer for the same controller but with a new env.
def new(env = {})
self.class.new controller, env, defaults
end
# Create a new renderer for the same controller but with new defaults.
def with_defaults(defaults)
self.class.new controller, env, self.defaults.merge(defaults)
end
# Accepts a custom Rack environment to render templates in.
# It will be merged with ActionController::Renderer.defaults
def initialize(env = {})
def initialize(controller, env, defaults)
@controller = controller
@defaults = defaults
@env = normalize_keys(defaults).merge normalize_keys(env)
@env['action_dispatch.routes'] = controller._routes
end
# Render templates with any options from ActionController::Base#render_to_string.
def render(*args)
raise 'missing controller' unless controller?
raise 'missing controller' unless controller
instance = controller.build_with_env(env)
instance = controller.build_with_env(@env)
instance.render_to_string(*args)
end
private
def normalize_keys(env)
http_header_format(env).tap do |new_env|
handle_method_key! new_env
handle_https_key! new_env
end
new_env = {}
env.each_pair { |k,v| new_env[rack_key_for(k)] = rack_value_for(k, v) }
new_env
end
def http_header_format(env)
env.transform_keys do |key|
key.is_a?(Symbol) ? key.to_s.upcase : key
end
end
RACK_KEY_TRANSLATION = {
http_host: 'HTTP_HOST',
https: 'HTTPS',
method: 'REQUEST_METHOD',
script_name: 'SCRIPT_NAME',
input: 'rack.input'
}
def handle_method_key!(env)
if method = env.delete('METHOD')
env['REQUEST_METHOD'] = method.upcase
end
end
IDENTITY = ->(_) { _ }
RACK_VALUE_TRANSLATION = {
https: ->(v) { v ? 'on' : 'off' },
method: ->(v) { v.upcase },
}
def rack_key_for(key); RACK_KEY_TRANSLATION[key]; end
def handle_https_key!(env)
if env.has_key? 'HTTPS'
env['HTTPS'] = env['HTTPS'] ? 'on' : 'off'
end
def rack_value_for(key, value)
RACK_VALUE_TRANSLATION.fetch(key, IDENTITY).call value
end
end
end
......@@ -61,8 +61,7 @@ class RendererTest < ActiveSupport::TestCase
end
test 'rendering with defaults' do
renderer = ApplicationController.renderer
renderer.defaults[:https] = true
renderer = ApplicationController.renderer.new https: true
content = renderer.render inline: '<%= request.ssl? %>'
assert_equal 'true', content
......@@ -71,8 +70,8 @@ class RendererTest < ActiveSupport::TestCase
test 'same defaults from the same controller' do
renderer_defaults = ->(controller) { controller.renderer.defaults }
assert renderer_defaults[AccountsController].equal? renderer_defaults[AccountsController]
assert_not renderer_defaults[AccountsController].equal? renderer_defaults[CommentsController]
assert_equal renderer_defaults[AccountsController], renderer_defaults[AccountsController]
assert_equal renderer_defaults[AccountsController], renderer_defaults[CommentsController]
end
test 'rendering with different formats' do
......@@ -87,18 +86,6 @@ class RendererTest < ActiveSupport::TestCase
test 'rendering with helpers' do
assert_equal "<p>1\n<br />2</p>", render[inline: '<%= simple_format "1\n2" %>']
end
test 'rendering from inherited renderer' do
inherited = Class.new ApplicationController.renderer do
defaults[:script_name] = 'script'
def render(options)
super options.merge(locals: { param: :value })
end
end
template = '<%= url_for controller: :foo, action: :bar, param: param %>'
assert_equal 'script/foo/bar?param=value', inherited.render(inline: template)
end
private
def render
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册