1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Refactor ActionView::Template

ActionView::Template is now completely independent from template
  storage, which allows different back ends such as the database.
  ActionView::Template's only responsibility is to take in the
  template source (passed in from ActionView::Path), compile it,
  and render it.
This commit is contained in:
Yehuda Katz + Carl Lerche 2009-04-23 15:58:38 -07:00
parent da3c21ead5
commit cecafc52ee
23 changed files with 359 additions and 300 deletions

View file

@ -494,8 +494,18 @@ module ActionController #:nodoc:
end
protected :filter_parameters
end
@@exempt_from_layout = [ActionView::TemplateHandlers::RJS]
def exempt_from_layout(*types)
types.each do |type|
@@exempt_from_layout <<
ActionView::Template.handler_class_for_extension(type)
end
@@exempt_from_layout
end
delegate :exempt_from_layout, :to => 'ActionView::Template'
end
public
@ -856,13 +866,13 @@ module ActionController #:nodoc:
return (performed? ? ret : default_render) if called
begin
default_render
rescue ActionView::MissingTemplate => e
raise e unless e.action_name == action_name
# If the path is the same as the action_name, the action is completely missing
view_paths.find_by_parts(action_name, {:formats => formats, :locales => [I18n.locale]}, controller_path)
rescue => e
raise UnknownAction, "No action responded to #{action_name}. Actions: " +
"#{action_methods.sort.to_sentence}", caller
end
default_render
end
# Returns true if a render or redirect has already been performed.

View file

@ -378,13 +378,14 @@ module ActionController
# ==== Arguments
# parts<Array[String, Array[Symbol*], String, Boolean]>::
# Example: ["show", [:html, :xml], "users", false]
def render_for_parts(parts, layout, options = {})
def render_for_parts(parts, layout_details, options = {})
parts[1] = {:formats => parts[1], :locales => [I18n.locale]}
tmp = view_paths.find_by_parts(*parts)
layout = _pick_layout(*layout) unless tmp.exempt_from_layout?
layout = _pick_layout(*layout_details) unless
self.class.exempt_from_layout.include?(tmp.handler)
render_for_text(
@template._render_template_with_layout(tmp, layout, options, parts[3]))
end

View file

@ -98,22 +98,22 @@ module ActionController
clean_backtrace do
case options
when NilClass, String
rendered = @controller.response.rendered[:template].to_s
rendered = (@controller.response.rendered[:template] || []).map { |t| t.identifier }
msg = build_message(message,
"expecting <?> but rendering with <?>",
options, rendered)
options, rendered.join(', '))
assert_block(msg) do
if options.nil?
@controller.response.rendered[:template].blank?
else
rendered.to_s.match(options)
rendered.any? { |t| t.match(options) }
end
end
when Hash
if expected_partial = options[:partial]
partials = @controller.response.rendered[:partials]
if expected_count = options[:count]
found = partials.detect { |p, _| p.to_s.match(expected_partial) }
found = partials.detect { |p, _| p.identifier.match(expected_partial) }
actual_count = found.nil? ? 0 : found.second
msg = build_message(message,
"expecting ? to be rendered ? time(s) but rendered ? time(s)",
@ -123,7 +123,7 @@ module ActionController
msg = build_message(message,
"expecting partial <?> but action rendered <?>",
options[:partial], partials.keys)
assert(partials.keys.any? { |p| p.to_s.match(expected_partial) }, msg)
assert(partials.keys.any? { |p| p.identifier.match(expected_partial) }, msg)
end
else
assert @controller.response.rendered[:partials].empty?,

View file

@ -196,7 +196,9 @@ module ActionView #:nodoc:
delegate :controller_path, :to => :controller, :allow_nil => true
delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers,
:flash, :logger, :action_name, :controller_name, :to => :controller
:flash, :action_name, :controller_name, :to => :controller
delegate :logger, :to => :controller, :allow_nil => true
delegate :find_by_parts, :to => :view_paths

View file

@ -3,7 +3,7 @@ module ActionView #:nodoc:
def self.type_cast(obj)
if obj.is_a?(String)
cache = !Object.const_defined?(:Rails) || Rails.configuration.cache_classes
Template::FileSystemPath.new(obj, :cache => cache)
Template::FileSystemPathWithFallback.new(obj, :cache => cache)
else
obj
end
@ -34,18 +34,18 @@ module ActionView #:nodoc:
end
def find_by_parts(path, details = {}, prefix = nil, partial = false)
template_path = path.sub(/^\//, '')
# template_path = path.sub(/^\//, '')
template_path = path
each do |load_path|
if template = load_path.find_by_parts(template_path, details, prefix, partial)
return template
end
end
Template.new(path, self)
rescue ActionView::MissingTemplate => e
# TODO: Have a fallback absolute path?
extension = details[:formats] || []
raise ActionView::MissingTemplate.new(self, "#{prefix}/#{path}.{#{extension.join(",")}}")
raise ActionView::MissingTemplate.new(self, "#{prefix}/#{path} - #{details.inspect} - partial: #{!!partial}")
end
def find_by_parts?(path, extension = nil, prefix = nil, partial = false)

View file

@ -46,8 +46,8 @@ module ActionView
locals ||= {}
if controller && layout
response.layout = layout.path_without_format_and_extension if controller.respond_to?(:response)
logger.info("Rendering template within #{layout.path_without_format_and_extension}") if logger
response.layout = layout.identifier if controller.respond_to?(:response)
logger.info("Rendering template within #{layout.identifier}") if logger
end
begin
@ -76,7 +76,6 @@ module ActionView
end
end
rescue Exception => e
raise e if template.is_a?(InlineTemplate) || !template.filename
if TemplateError === e
e.sub_template_of(template)
raise e
@ -86,7 +85,9 @@ module ActionView
end
def _render_inline(inline, layout, options)
content = _render_template(InlineTemplate.new(options[:inline], options[:type]), options[:locals] || {})
handler = Template.handler_class_for_extension(options[:type] || "erb")
template = Template.new(options[:inline], "inline #{options[:inline].inspect}", handler, {})
content = _render_template(template, options[:locals] || {})
layout ? _render_content_with_layout(content, layout, options[:locals]) : content
end
@ -96,7 +97,7 @@ module ActionView
def _render_template_with_layout(template, layout = nil, options = {}, partial = false)
if controller && logger
logger.info("Rendering #{template.path_without_extension}" +
logger.info("Rendering #{template.identifier}" +
(options[:status] ? " (#{options[:status]})" : ''))
end
@ -107,7 +108,7 @@ module ActionView
_render_template(template, options[:locals] || {})
end
return content unless layout && !template.exempt_from_layout?
return content unless layout
_render_content_with_layout(content, layout, options[:locals] || {})
end
end

View file

@ -12,7 +12,7 @@ module ActionView
end
def file_name
@template.relative_path
@template.identifier
end
def message
@ -30,7 +30,7 @@ module ActionView
def sub_template_message
if @sub_templates
"Trace of template inclusion: " +
@sub_templates.collect { |template| template.relative_path }.join(", ")
@sub_templates.collect { |template| template.identifier }.join(", ")
else
""
end

View file

@ -46,7 +46,7 @@ module ActionView #:nodoc:
end
def handler_class_for_extension(extension)
registered_template_handler(extension) || @@default_template_handlers
(extension && registered_template_handler(extension.to_sym)) || @@default_template_handlers
end
end
end

View file

@ -1,3 +1,5 @@
require "pathname"
module ActionView
class Template
# Abstract super class
@ -26,13 +28,6 @@ module ActionView
def find_templates(name, details, prefix, partial)
raise NotImplementedError
end
# TODO: Refactor this to abstract out the file system
def initialize_template(file)
t = Template.new(file.split("#{self}/").last, self)
t.load!
t
end
def valid_handlers
@valid_handlers ||= TemplateHandlers.extensions
@ -44,10 +39,10 @@ module ActionView
/\.(?:#{e})$/
end
end
def handler_glob
e = TemplateHandlers.extensions.join(',')
".{#{e}}"
e = TemplateHandlers.extensions.map{|h| ".#{h},"}.join
"{#{e}}"
end
def formats_glob
@ -69,23 +64,19 @@ module ActionView
def initialize(path, options = {})
raise ArgumentError, "path already is a Path class" if path.is_a?(Path)
super(options)
@path = path
@path = Pathname.new(path).expand_path
end
# TODO: This is the currently needed API. Make this suck less
# ==== <suck>
attr_reader :path
def to_s
if defined?(RAILS_ROOT)
path.to_s.sub(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}\//, '')
else
path.to_s
end
path.to_s
end
def to_str
path.to_str
path.to_s
end
def ==(path)
@ -97,11 +88,15 @@ module ActionView
end
# ==== </suck>
def find_templates(name, details, prefix, partial)
if glob = parts_to_glob(name, details, prefix, partial)
def find_templates(name, details, prefix, partial, root = "#{@path}/")
if glob = details_to_glob(name, details, prefix, partial, root)
cached(glob) do
Dir[glob].map do |path|
initialize_template(path) unless File.directory?(path)
next if File.directory?(path)
source = File.read(path)
identifier = Pathname.new(path).expand_path.to_s
Template.new(source, identifier, *path_to_details(path))
end.compact
end
end
@ -109,7 +104,8 @@ module ActionView
private
def parts_to_glob(name, details, prefix, partial)
# :api: plugin
def details_to_glob(name, details, prefix, partial, root)
path = ""
path << "#{prefix}/" unless prefix.empty?
path << (partial ? "_#{name}" : name)
@ -123,8 +119,34 @@ module ActionView
end
end
"#{@path}/#{path}#{extensions}#{handler_glob}"
"#{root}#{path}#{extensions}#{handler_glob}"
end
# TODO: fix me
# :api: plugin
def path_to_details(path)
# [:erb, :format => :html, :locale => :en, :partial => true/false]
if m = path.match(%r'/(_)?[\w-]+(\.[\w-]+)*\.(\w+)$')
partial = m[1] == '_'
details = (m[2]||"").split('.').reject { |e| e.empty? }
handler = Template.handler_class_for_extension(m[3])
format = Mime[details.last] && details.pop.to_sym
locale = details.last && details.pop.to_sym
return handler, :format => format, :locale => locale, :partial => partial
end
end
end
class FileSystemPathWithFallback < FileSystemPath
def find_templates(name, details, prefix, partial)
templates = super
return super(name, details, prefix, partial, '') if templates.empty?
templates
end
end
end
end

View file

@ -1,188 +1,230 @@
# encoding: utf-8
# This is so that templates compiled in this file are UTF-8
require 'set'
require "action_view/template/path"
module ActionView #:nodoc:
module ActionView
class Template
extend TemplateHandlers
extend ActiveSupport::Memoizable
attr_reader :source, :identifier, :handler
module Loading
def load!
@cached = true
# freeze
end
def initialize(source, identifier, handler, details)
@source = source
@identifier = identifier
@handler = handler
@details = details
end
include Loading
include Renderable
# Templates that are exempt from layouts
@@exempt_from_layout = Set.new([/\.rjs$/])
# Don't render layouts for templates with the given extensions.
def self.exempt_from_layout(*extensions)
regexps = extensions.collect do |extension|
extension.is_a?(Regexp) ? extension : /\.#{Regexp.escape(extension.to_s)}$/
end
@@exempt_from_layout.merge(regexps)
def render(view, locals, &blk)
method_name = compile(locals, view)
view.send(method_name, locals, &blk)
end
# TODO: Figure out how to abstract this
def variable_name
identifier[%r'_?(\w+)(\.\w+)*$', 1].to_sym
end
attr_accessor :template_path, :filename, :load_path, :base_path
attr_accessor :locale, :name, :format, :extension
delegate :to_s, :to => :path
def initialize(template_path, load_paths = [])
template_path = template_path.dup
@load_path, @filename = find_full_path(template_path, load_paths)
@base_path, @name, @locale, @format, @extension = split(template_path)
@base_path.to_s.gsub!(/\/$/, '') # Push to split method
# Extend with partial super powers
extend RenderablePartial if @name =~ /^_/
# TODO: Figure out how to abstract this
def counter_name
"#{variable_name}_counter".to_sym
end
def accessible_paths
paths = []
if valid_extension?(extension)
paths << path
paths << path_without_extension
if multipart?
formats = format.split(".")
paths << "#{path_without_format_and_extension}.#{formats.first}"
paths << "#{path_without_format_and_extension}.#{formats.second}"
end
else
# template without explicit template handler should only be reachable through its exact path
paths << template_path
end
paths
# TODO: kill hax
def partial?
@details[:partial]
end
def relative_path
path = File.expand_path(filename)
path.sub!(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}\//, '') if defined?(RAILS_ROOT)
path
end
memoize :relative_path
def source
File.read(filename)
end
memoize :source
def exempt_from_layout?
@@exempt_from_layout.any? { |exempted| path =~ exempted }
end
def path_without_extension
[base_path, [name, locale, format].compact.join('.')].compact.join('/')
end
memoize :path_without_extension
def path_without_format_and_extension
[base_path, [name, locale].compact.join('.')].compact.join('/')
end
memoize :path_without_format_and_extension
def path
[base_path, [name, locale, format, extension].compact.join('.')].compact.join('/')
end
memoize :path
# TODO: Move out of Template
def mime_type
Mime::Type.lookup_by_extension(format) if format && defined?(::Mime)
Mime::Type.lookup_by_extension(@details[:format]) if @details[:format]
end
memoize :mime_type
def multipart?
format && format.include?('.')
end
def content_type
format && format.gsub('.', '/')
end
private
def format_and_extension
(extensions = [format, extension].compact.join(".")).blank? ? nil : extensions
end
memoize :format_and_extension
def mtime
File.mtime(filename)
end
memoize :mtime
def compile(locals, view)
method_name = build_method_name(locals)
return method_name if view.respond_to?(method_name)
locals_code = locals.keys.map! { |key| "#{key} = local_assigns[:#{key}];" }.join
def method_segment
relative_path.to_s.gsub(/([^a-zA-Z0-9_])/) { $1.ord }
end
memoize :method_segment
def stale?
File.mtime(filename) > mtime
end
def recompile?
!@cached
end
def valid_extension?(extension)
!Template.registered_template_handler(extension).nil?
end
def valid_locale?(locale)
I18n.available_locales.include?(locale.to_sym)
end
def find_full_path(path, load_paths)
load_paths = Array(load_paths) + [nil]
load_paths.each do |load_path|
file = load_path ? "#{load_path.to_str}/#{path}" : path
return load_path, file if File.file?(file)
end
raise MissingTemplate.new(load_paths, path)
end
# Returns file split into an array
# [base_path, name, locale, format, extension]
def split(file)
if m = file.to_s.match(/^(.*\/)?([^\.]+)\.(.*)$/)
base_path = m[1]
name = m[2]
extensions = m[3]
else
return
end
locale = nil
format = nil
extension = nil
if m = extensions.split(".")
if valid_locale?(m[0]) && m[1] && valid_extension?(m[2]) # All three
locale = m[0]
format = m[1]
extension = m[2]
elsif m[0] && m[1] && valid_extension?(m[2]) # Multipart formats
format = "#{m[0]}.#{m[1]}"
extension = m[2]
elsif valid_locale?(m[0]) && valid_extension?(m[1]) # locale and extension
locale = m[0]
extension = m[1]
elsif valid_extension?(m[1]) # format and extension
format = m[0]
extension = m[1]
elsif valid_extension?(m[0]) # Just extension
extension = m[0]
else # No extension
format = m[0]
source = <<-end_src
def #{method_name}(local_assigns)
old_output_buffer = output_buffer;#{locals_code};#{@handler.call(self)}
ensure
self.output_buffer = old_output_buffer
end
end
end_src
[base_path, name, locale, format, extension]
begin
ActionView::Base::CompiledTemplates.module_eval(source, identifier, 0)
method_name
rescue Exception => e # errors from template code
if logger = (view && view.logger)
logger.debug "ERROR: compiling #{method_name} RAISED #{e}"
logger.debug "Function body: #{source}"
logger.debug "Backtrace: #{e.backtrace.join("\n")}"
end
raise ActionView::TemplateError.new(self, {}, e)
end
end
def build_method_name(locals)
# TODO: is locals.keys.hash reliably the same?
"_render_template_#{@identifier.hash}_#{__id__}_#{locals.keys.hash}".gsub('-', "_")
end
end
end
if false
module ActionView #:nodoc:
class Template
extend TemplateHandlers
extend ActiveSupport::Memoizable
module Loading
def load!
@cached = true
# freeze
end
end
include Loading
include Renderable
# Templates that are exempt from layouts
@@exempt_from_layout = Set.new([/\.rjs$/])
# Don't render layouts for templates with the given extensions.
def self.exempt_from_layout(*extensions)
regexps = extensions.collect do |extension|
extension.is_a?(Regexp) ? extension : /\.#{Regexp.escape(extension.to_s)}$/
end
@@exempt_from_layout.merge(regexps)
end
attr_accessor :template_path, :filename, :load_path, :base_path
attr_accessor :locale, :name, :format, :extension
delegate :to_s, :to => :path
def initialize(template_path, load_paths = [])
template_path = template_path.dup
@load_path, @filename = find_full_path(template_path, load_paths)
@name = template_path.to_s.split("/").last.split(".").first
# @base_path, @name, @locale, @format, @extension = split(template_path)
@base_path.to_s.gsub!(/\/$/, '') # Push to split method
# Extend with partial super powers
extend RenderablePartial if @name =~ /^_/
end
def accessible_paths
paths = []
if valid_extension?(extension)
paths << path
paths << path_without_extension
if multipart?
formats = format.split(".")
paths << "#{path_without_format_and_extension}.#{formats.first}"
paths << "#{path_without_format_and_extension}.#{formats.second}"
end
else
# template without explicit template handler should only be reachable through its exact path
paths << template_path
end
paths
end
def relative_path
path = File.expand_path(filename)
path.sub!(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}\//, '') if defined?(RAILS_ROOT)
path
end
memoize :relative_path
def source
File.read(filename)
end
memoize :source
def exempt_from_layout?
@@exempt_from_layout.any? { |exempted| path =~ exempted }
end
def path_without_extension
[base_path, [name, locale, format].compact.join('.')].compact.join('/')
end
memoize :path_without_extension
def path_without_format_and_extension
[base_path, [name, locale].compact.join('.')].compact.join('/')
end
memoize :path_without_format_and_extension
def path
[base_path, [name, locale, format, extension].compact.join('.')].compact.join('/')
end
memoize :path
def mime_type
Mime::Type.lookup_by_extension(format) if format && defined?(::Mime)
end
memoize :mime_type
def multipart?
format && format.include?('.')
end
def content_type
format && format.gsub('.', '/')
end
private
def format_and_extension
(extensions = [format, extension].compact.join(".")).blank? ? nil : extensions
end
memoize :format_and_extension
def mtime
File.mtime(filename)
end
memoize :mtime
def method_segment
relative_path.to_s.gsub(/([^a-zA-Z0-9_])/) { $1.ord }
end
memoize :method_segment
def stale?
File.mtime(filename) > mtime
end
def recompile?
!@cached
end
def valid_extension?(extension)
!Template.registered_template_handler(extension).nil?
end
def valid_locale?(locale)
I18n.available_locales.include?(locale.to_sym)
end
def find_full_path(path, load_paths)
load_paths = Array(load_paths) + [nil]
load_paths.each do |load_path|
file = load_path ? "#{load_path.to_str}/#{path}" : path
return load_path, file if File.file?(file)
end
raise MissingTemplate.new(load_paths, path)
end
end
end
end

View file

@ -10,9 +10,10 @@ module ActionView
alias_method :_render_template_without_template_tracking, :_render_template
def _render_template(template, local_assigns = {})
if template.respond_to?(:path) && !template.is_a?(InlineTemplate)
@_rendered[:partials][template] += 1 if template.is_a?(RenderablePartial)
@_rendered[:template] ||= template
if template.respond_to?(:identifier)
@_rendered[:partials][template] += 1 if template.partial?
@_rendered[:template] ||= []
@_rendered[:template] << template
end
_render_template_without_template_tracking(template, local_assigns)
end

View file

@ -139,7 +139,7 @@ module AbstractController
private
def self.layout(formats)
begin
view_paths.find_by_parts(name.underscore, {:formats => formats}t, "layouts")
view_paths.find_by_parts(name.underscore, {:formats => formats}, "layouts")
rescue ActionView::MissingTemplate
begin
view_paths.find_by_parts("application", {:formats => formats}, "layouts")

View file

@ -211,7 +211,7 @@ class IsolatedHelpersTest < Test::Unit::TestCase
end
def test_helper_in_a
assert_raise(NameError) { A.process(@request, @response) }
assert_raise(ActionView::TemplateError) { A.process(@request, @response) }
end
def test_helper_in_b

View file

@ -56,8 +56,8 @@ class LayoutAutoDiscoveryTest < ActionController::TestCase
def test_third_party_template_library_auto_discovers_layout
@controller = ThirdPartyTemplateLibraryController.new
get :hello
assert_equal 'layouts/third_party_template_library.mab', @controller.active_layout(true).to_s
assert_equal 'layouts/third_party_template_library', @response.layout
assert @controller.active_layout(true).identifier.include?('layouts/third_party_template_library.mab')
assert @response.layout.include?('layouts/third_party_template_library')
assert_response :success
assert_equal 'Mab', @response.body
end
@ -72,7 +72,7 @@ class LayoutAutoDiscoveryTest < ActionController::TestCase
def test_namespaced_controllers_auto_detect_layouts
@controller = MultipleExtensions.new
get :hello
assert_equal 'layouts/multiple_extensions.html.erb', @controller.active_layout(true).to_s
assert @controller.active_layout(true).identifier.include?('layouts/multiple_extensions.html.erb')
assert_equal 'multiple_extensions.html.erb hello.rhtml', @response.body.strip
end
end
@ -116,22 +116,24 @@ class RendersNoLayoutController < LayoutTest
end
class LayoutSetInResponseTest < ActionController::TestCase
include ActionView::TemplateHandlers
def test_layout_set_when_using_default_layout
@controller = DefaultLayoutController.new
get :hello
assert_equal 'layouts/layout_test', @response.layout
assert @response.layout.include?('layouts/layout_test')
end
def test_layout_set_when_set_in_controller
@controller = HasOwnLayoutController.new
get :hello
assert_equal 'layouts/item', @response.layout
assert @response.layout.include?('layouts/item')
end
def test_layout_only_exception_when_included
@controller = OnlyLayoutController.new
get :hello
assert_equal 'layouts/item', @response.layout
assert @response.layout.include?('layouts/item')
end
def test_layout_only_exception_when_excepted
@ -143,7 +145,7 @@ class LayoutSetInResponseTest < ActionController::TestCase
def test_layout_except_exception_when_included
@controller = ExceptLayoutController.new
get :hello
assert_equal 'layouts/item', @response.layout
assert @response.layout.include?('layouts/item')
end
def test_layout_except_exception_when_excepted
@ -155,7 +157,7 @@ class LayoutSetInResponseTest < ActionController::TestCase
def test_layout_set_when_using_render
@controller = SetsLayoutInRenderController.new
get :hello
assert_equal 'layouts/third_party_template_library', @response.layout
assert @response.layout.include?('layouts/third_party_template_library')
end
def test_layout_is_not_set_when_none_rendered
@ -165,14 +167,14 @@ class LayoutSetInResponseTest < ActionController::TestCase
end
def test_exempt_from_layout_honored_by_render_template
ActionController::Base.exempt_from_layout :rhtml
ActionController::Base.exempt_from_layout :erb
@controller = RenderWithTemplateOptionController.new
get :hello
assert_equal "alt/hello.rhtml", @response.body.strip
ensure
ActionController::Base.exempt_from_layout.delete(/\.rhtml$/)
ActionController::Base.exempt_from_layout.delete(ERB)
end
def test_layout_is_picked_from_the_controller_instances_view_path
@ -232,7 +234,7 @@ unless RUBY_PLATFORM =~ /(:?mswin|mingw|bccwin)/
@controller = LayoutSymlinkedTest.new
get :hello
assert_response 200
assert_equal "layouts/symlinked/symlinked_layout", @response.layout
assert @response.layout.include?("layouts/symlinked/symlinked_layout")
end
end
end

View file

@ -773,7 +773,7 @@ class RenderTest < ActionController::TestCase
begin
get :render_line_offset
flunk "the action should have raised an exception"
rescue RuntimeError => exc
rescue StandardError => exc
line = exc.backtrace.first
assert(line =~ %r{:(\d+):})
assert_equal "1", $1,
@ -1736,7 +1736,7 @@ class RenderingLoggingTest < ActionController::TestCase
@controller.logger = MockLogger.new
get :layout_test
logged = @controller.logger.logged.find_all {|l| l =~ /render/i }
assert_equal "Rendering test/hello_world", logged[0]
assert_equal "Rendering template within layouts/standard", logged[1]
assert logged[0] =~ %r{Rendering.*test/hello_world}
assert logged[1] =~ %r{Rendering template within.*layouts/standard}
end
end

View file

@ -20,7 +20,7 @@ class ViewLoadPathsTest < ActionController::TestCase
layout 'test/sub'
def hello_world; render(:template => 'test/hello_world'); end
end
def setup
TestController.view_paths = nil
@ -42,30 +42,39 @@ class ViewLoadPathsTest < ActionController::TestCase
ActiveSupport::Deprecation.behavior = @old_behavior
end
def expand(array)
array.map {|x| File.expand_path(x)}
end
def assert_paths(*paths)
controller = paths.first.is_a?(Class) ? paths.shift : @controller
assert_equal expand(paths), controller.view_paths.map(&:to_s)
end
def test_template_load_path_was_set_correctly
assert_equal [FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s)
assert_paths FIXTURE_LOAD_PATH
end
def test_controller_appends_view_path_correctly
@controller.append_view_path 'foo'
assert_equal [FIXTURE_LOAD_PATH, 'foo'], @controller.view_paths.map(&:to_s)
assert_paths(FIXTURE_LOAD_PATH, "foo")
@controller.append_view_path(%w(bar baz))
assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s)
assert_paths(FIXTURE_LOAD_PATH, "foo", "bar", "baz")
@controller.append_view_path(FIXTURE_LOAD_PATH)
assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s)
assert_paths(FIXTURE_LOAD_PATH, "foo", "bar", "baz", FIXTURE_LOAD_PATH)
end
def test_controller_prepends_view_path_correctly
@controller.prepend_view_path 'baz'
assert_equal ['baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s)
assert_paths("baz", FIXTURE_LOAD_PATH)
@controller.prepend_view_path(%w(foo bar))
assert_equal ['foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s)
assert_paths "foo", "bar", "baz", FIXTURE_LOAD_PATH
@controller.prepend_view_path(FIXTURE_LOAD_PATH)
assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s)
assert_paths FIXTURE_LOAD_PATH, "foo", "bar", "baz", FIXTURE_LOAD_PATH
end
def test_template_appends_view_path_correctly
@ -73,11 +82,11 @@ class ViewLoadPathsTest < ActionController::TestCase
class_view_paths = TestController.view_paths
@controller.append_view_path 'foo'
assert_equal [FIXTURE_LOAD_PATH, 'foo'], @controller.view_paths.map(&:to_s)
assert_paths FIXTURE_LOAD_PATH, "foo"
@controller.append_view_path(%w(bar baz))
assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s)
assert_equal class_view_paths, TestController.view_paths
assert_paths FIXTURE_LOAD_PATH, "foo", "bar", "baz"
assert_paths TestController, *class_view_paths
end
def test_template_prepends_view_path_correctly
@ -85,11 +94,11 @@ class ViewLoadPathsTest < ActionController::TestCase
class_view_paths = TestController.view_paths
@controller.prepend_view_path 'baz'
assert_equal ['baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s)
assert_paths "baz", FIXTURE_LOAD_PATH
@controller.prepend_view_path(%w(foo bar))
assert_equal ['foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s)
assert_equal class_view_paths, TestController.view_paths
assert_paths "foo", "bar", "baz", FIXTURE_LOAD_PATH
assert_paths TestController, *class_view_paths
end
def test_view_paths
@ -130,12 +139,12 @@ class ViewLoadPathsTest < ActionController::TestCase
A.view_paths = ['a/path']
assert_equal ['a/path'], A.view_paths.map(&:to_s)
assert_equal A.view_paths, B.view_paths
assert_equal original_load_paths, C.view_paths
assert_paths A, "a/path"
assert_paths A, *B.view_paths
assert_paths C, *original_load_paths
C.view_paths = []
assert_nothing_raised { C.view_paths << 'c/path' }
assert_equal ['c/path'], C.view_paths.map(&:to_s)
assert_paths C, "c/path"
end
end

View file

@ -0,0 +1 @@
<%= secret ||= 'one' %>

View file

@ -5,37 +5,13 @@ class CompiledTemplatesTest < Test::Unit::TestCase
def setup
@compiled_templates = ActionView::Base::CompiledTemplates
@compiled_templates.instance_methods.each do |m|
@compiled_templates.send(:remove_method, m) if m =~ /^_run_/
@compiled_templates.send(:remove_method, m) if m =~ /^_render_template_/
end
end
def test_template_gets_compiled
assert_equal 0, @compiled_templates.instance_methods.size
assert_equal "Hello world!", render(:file => "test/hello_world.erb")
assert_equal 1, @compiled_templates.instance_methods.size
end
def test_template_gets_recompiled_when_using_different_keys_in_local_assigns
assert_equal 0, @compiled_templates.instance_methods.size
assert_equal "Hello world!", render(:file => "test/hello_world.erb")
assert_equal "Hello world!", render(:file => "test/hello_world.erb", :locals => {:foo => "bar"})
assert_equal 2, @compiled_templates.instance_methods.size
end
def test_compiled_template_will_not_be_recompiled_when_rendered_with_identical_local_assigns
assert_equal 0, @compiled_templates.instance_methods.size
assert_equal "Hello world!", render(:file => "test/hello_world.erb")
ActionView::Template.any_instance.expects(:compile!).never
assert_equal "Hello world!", render(:file => "test/hello_world.erb")
end
def test_compiled_template_will_always_be_recompiled_when_template_is_not_cached
ActionView::Template.any_instance.expects(:recompile?).times(3).returns(true)
assert_equal 0, @compiled_templates.instance_methods.size
assert_equal "Hello world!", render(:file => "#{FIXTURE_LOAD_PATH}/test/hello_world.erb")
ActionView::Template.any_instance.expects(:compile!).times(3)
3.times { assert_equal "Hello world!", render(:file => "#{FIXTURE_LOAD_PATH}/test/hello_world.erb") }
assert_equal 1, @compiled_templates.instance_methods.size
assert_equal "one", render(:file => "test/render_file_with_locals_and_default.erb")
assert_equal "two", render(:file => "test/render_file_with_locals_and_default.erb", :locals => { :secret => "two" })
end
def test_template_changes_are_not_reflected_with_cached_templates
@ -61,14 +37,12 @@ class CompiledTemplatesTest < Test::Unit::TestCase
def render_with_cache(*args)
view_paths = ActionController::Base.view_paths
assert_equal ActionView::Template::FileSystemPath, view_paths.first.class
ActionView::Base.new(view_paths, {}).render(*args)
end
def render_without_cache(*args)
path = ActionView::Template::FileSystemPath.new(FIXTURE_LOAD_PATH)
path = ActionView::Template::FileSystemPathWithFallback.new(FIXTURE_LOAD_PATH)
view_paths = ActionView::Base.process_view_paths(path)
assert_equal ActionView::Template::FileSystemPath, view_paths.first.class
ActionView::Base.new(view_paths, {}).render(*args)
end

View file

@ -91,10 +91,6 @@ module RenderTestCases
assert_equal "The secret is in the sauce\n", @view.render(:file => "test/dot.directory/render_file_with_ivar")
end
def test_render_has_access_current_template
assert_equal "test/template.erb", @view.render(:file => "test/template.erb")
end
def test_render_update
# TODO: You should not have to stub out template because template is self!
@view.instance_variable_set(:@template, @view)
@ -240,10 +236,6 @@ module RenderTestCases
end
end
def test_template_with_malformed_template_handler_is_reachable_through_its_exact_filename
assert_equal "Don't render me!", @view.render(:file => 'test/malformed/malformed.html.erb~')
end
def test_render_with_layout
assert_equal %(<title></title>\nHello world!\n),
@view.render(:file => "test/hello_world.erb", :layout => "layouts/yield")
@ -269,7 +261,7 @@ class CachedViewRenderTest < ActiveSupport::TestCase
# Ensure view path cache is primed
def setup
view_paths = ActionController::Base.view_paths
assert_equal ActionView::Template::FileSystemPath, view_paths.first.class
assert_equal ActionView::Template::FileSystemPathWithFallback, view_paths.first.class
setup_view(view_paths)
end
end
@ -280,9 +272,9 @@ class LazyViewRenderTest < ActiveSupport::TestCase
# Test the same thing as above, but make sure the view path
# is not eager loaded
def setup
path = ActionView::Template::FileSystemPath.new(FIXTURE_LOAD_PATH)
path = ActionView::Template::FileSystemPathWithFallback.new(FIXTURE_LOAD_PATH)
view_paths = ActionView::Base.process_view_paths(path)
assert_equal ActionView::Template::FileSystemPath, view_paths.first.class
assert_equal ActionView::Template::FileSystemPathWithFallback, view_paths.first.class
setup_view(view_paths)
end
end

View file

@ -110,8 +110,10 @@ class Module
allow_nil = options[:allow_nil] && "#{to} && "
file, line = caller[0].split(":")
methods.each do |method|
module_eval(<<-EOS, "(__DELEGATION__)", 1)
module_eval(<<-EOS, file, line.to_i)
def #{prefix}#{method}(*args, &block) # def customer_name(*args, &block)
#{allow_nil}#{to}.__send__(#{method.inspect}, *args, &block) # client && client.__send__(:name, *args, &block)
end # end

View file

@ -132,8 +132,8 @@ class TestPluginLoader < Test::Unit::TestCase
@loader.send :add_engine_view_paths
assert_equal [ File.join(plugin_fixture_path('engines/engine'), 'app', 'views') ], ActionController::Base.view_paths
assert_equal [ File.join(plugin_fixture_path('engines/engine'), 'app', 'views') ], ActionMailer::Base.view_paths
assert_equal [ File.join(plugin_fixture_path('engines/engine'), 'app', 'views') ], ActionController::Base.view_paths.map { |p| p.to_s }
assert_equal [ File.join(plugin_fixture_path('engines/engine'), 'app', 'views') ], ActionMailer::Base.view_paths.map { |p| p.to_s }
end
def test_should_add_plugin_load_paths_to_Dependencies_load_once_paths

View file

@ -12,7 +12,7 @@ RAILS_ROOT = '.' unless defined?(RAILS_ROOT)
class Test::Unit::TestCase
private
def plugin_fixture_root_path
File.join(File.dirname(__FILE__), 'fixtures', 'plugins')
File.expand_path(File.join(File.dirname(__FILE__), 'fixtures', 'plugins'))
end
def only_load_the_following_plugins!(plugins)