mirror of
https://github.com/github/rails.git
synced 2026-02-18 10:01:39 -05:00
Merge branch 'master' of git@github.com:rails/rails
This commit is contained in:
@@ -867,8 +867,9 @@ module ActionController #:nodoc:
|
||||
end
|
||||
end
|
||||
|
||||
response.layout = layout = pick_layout(options)
|
||||
logger.info("Rendering template within #{layout}") if logger && layout
|
||||
layout = pick_layout(options)
|
||||
response.layout = layout.path_without_format_and_extension if layout
|
||||
logger.info("Rendering template within #{layout.path_without_format_and_extension}") if logger && layout
|
||||
|
||||
if content_type = options[:content_type]
|
||||
response.content_type = content_type.to_s
|
||||
|
||||
@@ -137,7 +137,6 @@ module ActionController
|
||||
run_callbacks :prepare_dispatch
|
||||
|
||||
Routing::Routes.reload
|
||||
ActionController::Base.view_paths.reload!
|
||||
ActionView::Helpers::AssetTagHelper::AssetTag::Cache.clear
|
||||
end
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
require 'stringio'
|
||||
require 'uri'
|
||||
require 'active_support/test_case'
|
||||
|
||||
module ActionController
|
||||
module Integration #:nodoc:
|
||||
|
||||
@@ -175,13 +175,12 @@ module ActionController #:nodoc:
|
||||
def default_layout(format) #:nodoc:
|
||||
layout = read_inheritable_attribute(:layout)
|
||||
return layout unless read_inheritable_attribute(:auto_layout)
|
||||
@default_layout ||= {}
|
||||
@default_layout[format] ||= default_layout_with_format(format, layout)
|
||||
@default_layout[format]
|
||||
find_layout(layout, format)
|
||||
end
|
||||
|
||||
def layout_list #:nodoc:
|
||||
Array(view_paths).sum([]) { |path| Dir["#{path}/layouts/**/*"] }
|
||||
def find_layout(layout, *formats) #:nodoc:
|
||||
return layout if layout.respond_to?(:render)
|
||||
view_paths.find_template(layout.to_s =~ /layouts\// ? layout : "layouts/#{layout}", *formats)
|
||||
end
|
||||
|
||||
private
|
||||
@@ -189,7 +188,7 @@ module ActionController #:nodoc:
|
||||
inherited_without_layout(child)
|
||||
unless child.name.blank?
|
||||
layout_match = child.name.underscore.sub(/_controller$/, '').sub(/^controllers\//, '')
|
||||
child.layout(layout_match, {}, true) unless child.layout_list.grep(%r{layouts/#{layout_match}(\.[a-z][0-9a-z]*)+$}).empty?
|
||||
child.layout(layout_match, {}, true) if child.find_layout(layout_match, :all)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -200,15 +199,6 @@ module ActionController #:nodoc:
|
||||
def normalize_conditions(conditions)
|
||||
conditions.inject({}) {|hash, (key, value)| hash.merge(key => [value].flatten.map {|action| action.to_s})}
|
||||
end
|
||||
|
||||
def default_layout_with_format(format, layout)
|
||||
list = layout_list
|
||||
if list.grep(%r{layouts/#{layout}\.#{format}(\.[a-z][0-9a-z]*)+$}).empty?
|
||||
(!list.grep(%r{layouts/#{layout}\.([a-z][0-9a-z]*)+$}).empty? && format == :html) ? layout : nil
|
||||
else
|
||||
layout
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the name of the active layout. If the layout was specified as a method reference (through a symbol), this method
|
||||
@@ -217,20 +207,18 @@ module ActionController #:nodoc:
|
||||
# weblog/standard, but <tt>layout "standard"</tt> will return layouts/standard.
|
||||
def active_layout(passed_layout = nil)
|
||||
layout = passed_layout || self.class.default_layout(default_template_format)
|
||||
|
||||
active_layout = case layout
|
||||
when String then layout
|
||||
when Symbol then __send__(layout)
|
||||
when Proc then layout.call(self)
|
||||
else layout
|
||||
end
|
||||
|
||||
# Explicitly passed layout names with slashes are looked up relative to the template root,
|
||||
# but auto-discovered layouts derived from a nested controller will contain a slash, though be relative
|
||||
# to the 'layouts' directory so we have to check the file system to infer which case the layout name came from.
|
||||
if active_layout
|
||||
if active_layout.include?('/') && ! layout_directory?(active_layout)
|
||||
active_layout
|
||||
if layout = self.class.find_layout(active_layout, @template.template_format)
|
||||
layout
|
||||
else
|
||||
"layouts/#{active_layout}"
|
||||
raise ActionView::MissingTemplate.new(self.class.view_paths, active_layout)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -271,12 +259,6 @@ module ActionController #:nodoc:
|
||||
end
|
||||
end
|
||||
|
||||
def layout_directory?(layout_name)
|
||||
@template.__send__(:_pick_template, "#{File.join('layouts', layout_name)}.#{@template.template_format}") ? true : false
|
||||
rescue ActionView::MissingTemplate
|
||||
false
|
||||
end
|
||||
|
||||
def default_template_format
|
||||
response.template.template_format
|
||||
end
|
||||
|
||||
@@ -322,9 +322,7 @@ module ActionView #:nodoc:
|
||||
end
|
||||
|
||||
# OPTIMIZE: Checks to lookup template in view path
|
||||
if template = self.view_paths["#{template_file_name}.#{template_format}"]
|
||||
template
|
||||
elsif template = self.view_paths[template_file_name]
|
||||
if template = self.view_paths.find_template(template_file_name, template_format)
|
||||
template
|
||||
elsif (first_render = @_render_stack.first) && first_render.respond_to?(:format_and_extension) &&
|
||||
(template = self.view_paths["#{template_file_name}.#{first_render.format_and_extension}"])
|
||||
|
||||
@@ -40,18 +40,10 @@ module ActionView #:nodoc:
|
||||
end
|
||||
|
||||
class Path #:nodoc:
|
||||
def self.eager_load_templates!
|
||||
@eager_load_templates = true
|
||||
end
|
||||
|
||||
def self.eager_load_templates?
|
||||
@eager_load_templates || false
|
||||
end
|
||||
|
||||
attr_reader :path, :paths
|
||||
delegate :to_s, :to_str, :hash, :inspect, :to => :path
|
||||
|
||||
def initialize(path, load = true)
|
||||
def initialize(path, load = false)
|
||||
raise ArgumentError, "path already is a Path class" if path.is_a?(Path)
|
||||
@path = path.freeze
|
||||
reload! if load
|
||||
@@ -65,9 +57,35 @@ module ActionView #:nodoc:
|
||||
to_str == path.to_str
|
||||
end
|
||||
|
||||
# Returns a ActionView::Template object for the given path string. The
|
||||
# input path should be relative to the view path directory,
|
||||
# +hello/index.html.erb+. This method also has a special exception to
|
||||
# match partial file names without a handler extension. So
|
||||
# +hello/index.html+ will match the first template it finds with a
|
||||
# known template extension, +hello/index.html.erb+. Template extensions
|
||||
# should not be confused with format extensions +html+, +js+, +xml+,
|
||||
# etc. A format must be supplied to match a formated file. +hello/index+
|
||||
# will never match +hello/index.html.erb+.
|
||||
#
|
||||
# This method also has two different implementations, one that is "lazy"
|
||||
# and makes file system calls every time and the other is cached,
|
||||
# "eager" which looks up the template in an in memory index. The "lazy"
|
||||
# version is designed for development where you want to automatically
|
||||
# find new templates between requests. The "eager" version is designed
|
||||
# for production mode and it is much faster but requires more time
|
||||
# upfront to build the file index.
|
||||
def [](path)
|
||||
raise "Unloaded view path! #{@path}" unless @loaded
|
||||
@paths[path]
|
||||
if loaded?
|
||||
@paths[path]
|
||||
else
|
||||
Dir.glob("#{@path}/#{path}*").each do |file|
|
||||
template = create_template(file)
|
||||
if path == template.path_without_extension || path == template.path
|
||||
return template
|
||||
end
|
||||
end
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def loaded?
|
||||
@@ -84,9 +102,7 @@ module ActionView #:nodoc:
|
||||
@paths = {}
|
||||
|
||||
templates_in_path do |template|
|
||||
# Eager load memoized methods and freeze cached template
|
||||
template.freeze if self.class.eager_load_templates?
|
||||
|
||||
template.freeze
|
||||
@paths[template.path] = template
|
||||
@paths[template.path_without_extension] ||= template
|
||||
end
|
||||
@@ -98,11 +114,13 @@ module ActionView #:nodoc:
|
||||
private
|
||||
def templates_in_path
|
||||
(Dir.glob("#{@path}/**/*/**") | Dir.glob("#{@path}/**")).each do |file|
|
||||
unless File.directory?(file)
|
||||
yield Template.new(file.split("#{self}/").last, self)
|
||||
end
|
||||
yield create_template(file) unless File.directory?(file)
|
||||
end
|
||||
end
|
||||
|
||||
def create_template(file)
|
||||
Template.new(file.split("#{self}/").last, self)
|
||||
end
|
||||
end
|
||||
|
||||
def load
|
||||
@@ -121,5 +139,20 @@ module ActionView #:nodoc:
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
def find_template(path, *formats)
|
||||
if formats && formats.first == :all
|
||||
formats = Mime::EXTENSION_LOOKUP.values.map(&:to_sym)
|
||||
end
|
||||
formats.each do |format|
|
||||
if template = self["#{path}.#{format}"]
|
||||
return template
|
||||
end
|
||||
end
|
||||
if template = self[path]
|
||||
return template
|
||||
end
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -96,7 +96,7 @@ module ActionView
|
||||
# The template will be compiled if the file has not been compiled yet, or
|
||||
# if local_assigns has a new key, which isn't supported by the compiled code yet.
|
||||
def recompile?(symbol)
|
||||
!(ActionView::PathSet::Path.eager_load_templates? && Base::CompiledTemplates.method_defined?(symbol))
|
||||
!(frozen? && Base::CompiledTemplates.method_defined?(symbol))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -30,8 +30,8 @@ ActionController::Base.logger = nil
|
||||
ActionController::Routing::Routes.reload rescue nil
|
||||
|
||||
FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures')
|
||||
ActionView::PathSet::Path.eager_load_templates!
|
||||
ActionController::Base.view_paths = FIXTURE_LOAD_PATH
|
||||
ActionController::Base.view_paths.load
|
||||
|
||||
def uses_mocha(test_name)
|
||||
yield
|
||||
|
||||
@@ -3,6 +3,10 @@ require 'abstract_unit'
|
||||
# The view_paths array must be set on Base and not LayoutTest so that LayoutTest's inherited
|
||||
# method has access to the view_paths array when looking for a layout to automatically assign.
|
||||
old_load_paths = ActionController::Base.view_paths
|
||||
|
||||
ActionView::Template::register_template_handler :mab,
|
||||
lambda { |template| template.source.inspect }
|
||||
|
||||
ActionController::Base.view_paths = [ File.dirname(__FILE__) + '/../fixtures/layout_tests/' ]
|
||||
|
||||
class LayoutTest < ActionController::Base
|
||||
@@ -31,9 +35,6 @@ end
|
||||
class MultipleExtensions < LayoutTest
|
||||
end
|
||||
|
||||
ActionView::Template::register_template_handler :mab,
|
||||
lambda { |template| template.source.inspect }
|
||||
|
||||
class LayoutAutoDiscoveryTest < ActionController::TestCase
|
||||
def setup
|
||||
@request.host = "www.nextangle.com"
|
||||
@@ -52,10 +53,9 @@ class LayoutAutoDiscoveryTest < ActionController::TestCase
|
||||
end
|
||||
|
||||
def test_third_party_template_library_auto_discovers_layout
|
||||
ThirdPartyTemplateLibraryController.view_paths.reload!
|
||||
@controller = ThirdPartyTemplateLibraryController.new
|
||||
get :hello
|
||||
assert_equal 'layouts/third_party_template_library', @controller.active_layout
|
||||
assert_equal 'layouts/third_party_template_library.mab', @controller.active_layout.to_s
|
||||
assert_equal 'layouts/third_party_template_library', @response.layout
|
||||
assert_response :success
|
||||
assert_equal 'Mab', @response.body
|
||||
@@ -64,14 +64,14 @@ class LayoutAutoDiscoveryTest < ActionController::TestCase
|
||||
def test_namespaced_controllers_auto_detect_layouts
|
||||
@controller = ControllerNameSpace::NestedController.new
|
||||
get :hello
|
||||
assert_equal 'layouts/controller_name_space/nested', @controller.active_layout
|
||||
assert_equal 'layouts/controller_name_space/nested', @controller.active_layout.to_s
|
||||
assert_equal 'controller_name_space/nested.rhtml hello.rhtml', @response.body
|
||||
end
|
||||
|
||||
def test_namespaced_controllers_auto_detect_layouts
|
||||
@controller = MultipleExtensions.new
|
||||
get :hello
|
||||
assert_equal 'layouts/multiple_extensions', @controller.active_layout
|
||||
assert_equal 'layouts/multiple_extensions.html.erb', @controller.active_layout.to_s
|
||||
assert_equal 'multiple_extensions.html.erb hello.rhtml', @response.body.strip
|
||||
end
|
||||
end
|
||||
|
||||
@@ -30,15 +30,6 @@ uses_mocha 'TestTemplateRecompilation' do
|
||||
assert_equal "Hello world!", render(:file => "test/hello_world.erb")
|
||||
end
|
||||
|
||||
def test_compiled_template_will_always_be_recompiled_when_eager_loaded_templates_is_off
|
||||
ActionView::PathSet::Path.expects(:eager_load_templates?).times(4).returns(false)
|
||||
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
|
||||
end
|
||||
|
||||
private
|
||||
def render(*args)
|
||||
ActionView::Base.new(ActionController::Base.view_paths, {}).render(*args)
|
||||
|
||||
@@ -4,7 +4,9 @@ require 'controller/fake_models'
|
||||
class ViewRenderTest < Test::Unit::TestCase
|
||||
def setup
|
||||
@assigns = { :secret => 'in the sauce' }
|
||||
@view = ActionView::Base.new(ActionController::Base.view_paths, @assigns)
|
||||
view_paths = ActionController::Base.view_paths
|
||||
@view = ActionView::Base.new(view_paths, @assigns)
|
||||
assert view_paths.first.loaded?
|
||||
end
|
||||
|
||||
def test_render_file
|
||||
@@ -157,7 +159,7 @@ class ViewRenderTest < Test::Unit::TestCase
|
||||
end
|
||||
|
||||
def test_render_fallbacks_to_erb_for_unknown_types
|
||||
assert_equal "Hello, World!", @view.render(:inline => "Hello, World!", :type => :foo)
|
||||
assert_equal "Hello, World!", @view.render(:inline => "Hello, World!", :type => :bar)
|
||||
end
|
||||
|
||||
CustomHandler = lambda do |template|
|
||||
@@ -196,3 +198,14 @@ class ViewRenderTest < Test::Unit::TestCase
|
||||
@view.render(:file => "test/nested_layout.erb", :layout => "layouts/yield")
|
||||
end
|
||||
end
|
||||
|
||||
class LazyViewRenderTest < ViewRenderTest
|
||||
# Test the same thing as above, but make sure the view path
|
||||
# is not eager loaded
|
||||
def setup
|
||||
@assigns = { :secret => 'in the sauce' }
|
||||
view_paths = ActionView::Base.process_view_paths(FIXTURE_LOAD_PATH)
|
||||
@view = ActionView::Base.new(view_paths, @assigns)
|
||||
assert !view_paths.first.loaded?
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user