mirror of
https://github.com/github/rails.git
synced 2026-01-08 22:27:59 -05:00
Port fast reloadable templates from rails-dev-boost.
This commit is contained in:
@@ -19,6 +19,7 @@ ActionView::Template.register_template_handler :bak, lambda { |template| "Lame b
|
||||
|
||||
$:.unshift "#{File.dirname(__FILE__)}/fixtures/helpers"
|
||||
|
||||
ActionView::Base.cache_template_loading = true
|
||||
FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures')
|
||||
ActionMailer::Base.template_root = FIXTURE_LOAD_PATH
|
||||
|
||||
|
||||
@@ -975,7 +975,7 @@ end
|
||||
|
||||
class InheritableTemplateRootTest < Test::Unit::TestCase
|
||||
def test_attr
|
||||
expected = "#{File.dirname(__FILE__)}/fixtures/path.with.dots"
|
||||
expected = ("#{File.dirname(__FILE__)}/fixtures/path.with.dots").sub(/\.\//, '')
|
||||
assert_equal expected, FunkyPathMailer.template_root.to_s
|
||||
|
||||
sub = Class.new(FunkyPathMailer)
|
||||
|
||||
@@ -38,7 +38,7 @@ module ActionController #:nodoc:
|
||||
'ActionView::TemplateError' => 'template_error'
|
||||
}
|
||||
|
||||
RESCUES_TEMPLATE_PATH = ActionView::Template::Path.new(
|
||||
RESCUES_TEMPLATE_PATH = ActionView::Template::EagerPath.new_and_loaded(
|
||||
File.join(File.dirname(__FILE__), "templates"))
|
||||
|
||||
def self.included(base) #:nodoc:
|
||||
|
||||
@@ -44,6 +44,7 @@ module ActionView
|
||||
autoload :Renderable, 'action_view/renderable'
|
||||
autoload :RenderablePartial, 'action_view/renderable_partial'
|
||||
autoload :Template, 'action_view/template'
|
||||
autoload :ReloadableTemplate, 'action_view/reloadable_template'
|
||||
autoload :TemplateError, 'action_view/template_error'
|
||||
autoload :TemplateHandler, 'action_view/template_handler'
|
||||
autoload :TemplateHandlers, 'action_view/template_handlers'
|
||||
|
||||
@@ -182,10 +182,15 @@ module ActionView #:nodoc:
|
||||
# that alert()s the caught exception (and then re-raises it).
|
||||
cattr_accessor :debug_rjs
|
||||
|
||||
# Specify whether to check whether modified templates are recompiled without a restart
|
||||
# Specify whether templates should be cached. Otherwise the file we be read everytime it is accessed.
|
||||
# Automaticaly reloading templates are not thread safe and should only be used in development mode.
|
||||
@@cache_template_loading = false
|
||||
cattr_accessor :cache_template_loading
|
||||
|
||||
def self.cache_template_loading?
|
||||
ActionController::Base.allow_concurrency || cache_template_loading
|
||||
end
|
||||
|
||||
attr_internal :request
|
||||
|
||||
delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers,
|
||||
@@ -226,6 +231,8 @@ module ActionView #:nodoc:
|
||||
|
||||
def view_paths=(paths)
|
||||
@view_paths = self.class.process_view_paths(paths)
|
||||
# we might be using ReloadableTemplates, so we need to let them know this a new request
|
||||
@view_paths.load!
|
||||
end
|
||||
|
||||
# Returns the result of a render that's dictated by the options hash. The primary options are:
|
||||
@@ -247,8 +254,8 @@ module ActionView #:nodoc:
|
||||
if options[:layout]
|
||||
_render_with_layout(options, local_assigns, &block)
|
||||
elsif options[:file]
|
||||
template = self.view_paths.find_template(options[:file], template_format)
|
||||
template.render_template(self, options[:locals])
|
||||
tempalte = self.view_paths.find_template(options[:file], template_format)
|
||||
tempalte.render_template(self, options[:locals])
|
||||
elsif options[:partial]
|
||||
render_partial(options)
|
||||
elsif options[:inline]
|
||||
|
||||
@@ -235,5 +235,6 @@ module ActionView
|
||||
|
||||
self.view_paths.find_template(path, self.template_format)
|
||||
end
|
||||
memoize :_pick_partial_template
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,12 +2,16 @@ module ActionView #:nodoc:
|
||||
class PathSet < Array #:nodoc:
|
||||
def self.type_cast(obj)
|
||||
if obj.is_a?(String)
|
||||
Template::Path.new(obj)
|
||||
if Base.cache_template_loading?
|
||||
Template::EagerPath.new(obj.to_s)
|
||||
else
|
||||
ReloadableTemplate::ReloadablePath.new(obj.to_s)
|
||||
end
|
||||
else
|
||||
obj
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def initialize(*args)
|
||||
super(*args).map! { |obj| self.class.type_cast(obj) }
|
||||
end
|
||||
@@ -31,9 +35,14 @@ module ActionView #:nodoc:
|
||||
def unshift(*objs)
|
||||
super(*objs.map { |obj| self.class.type_cast(obj) })
|
||||
end
|
||||
|
||||
def load!
|
||||
each(&:load!)
|
||||
end
|
||||
|
||||
def find_template(template_path, format = nil)
|
||||
return template_path if template_path.respond_to?(:render)
|
||||
def find_template(original_template_path, format = nil)
|
||||
return original_template_path if original_template_path.respond_to?(:render)
|
||||
template_path = original_template_path.sub(/^\//, '')
|
||||
|
||||
each do |load_path|
|
||||
if format && (template = load_path["#{template_path}.#{I18n.locale}.#{format}"])
|
||||
@@ -52,11 +61,9 @@ module ActionView #:nodoc:
|
||||
end
|
||||
end
|
||||
|
||||
if File.exist?(template_path)
|
||||
return Template.new(template_path, template_path[0] == 47 ? "" : ".")
|
||||
end
|
||||
return Template.new(original_template_path, original_template_path =~ /\A\// ? "" : ".") if File.file?(original_template_path)
|
||||
|
||||
raise MissingTemplate.new(self, template_path, format)
|
||||
raise MissingTemplate.new(self, original_template_path, format)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
120
actionpack/lib/action_view/reloadable_template.rb
Normal file
120
actionpack/lib/action_view/reloadable_template.rb
Normal file
@@ -0,0 +1,120 @@
|
||||
module ActionView #:nodoc:
|
||||
class ReloadableTemplate < Template
|
||||
|
||||
class TemplateDeleted < ActionView::ActionViewError
|
||||
end
|
||||
|
||||
class ReloadablePath < Template::Path
|
||||
|
||||
def initialize(path)
|
||||
super
|
||||
@paths = {}
|
||||
new_request!
|
||||
end
|
||||
|
||||
def new_request!
|
||||
@disk_cache = {}
|
||||
end
|
||||
alias_method :load!, :new_request!
|
||||
|
||||
def [](path)
|
||||
if found_template = @paths[path]
|
||||
begin
|
||||
found_template.reset_cache_if_stale!
|
||||
rescue TemplateDeleted
|
||||
unregister_template(found_template)
|
||||
self[path]
|
||||
end
|
||||
else
|
||||
load_all_templates_from_dir(templates_dir_from_path(path))
|
||||
@paths[path]
|
||||
end
|
||||
end
|
||||
|
||||
def register_template_from_file(template_file_path)
|
||||
if !@paths[template_relative_path = template_file_path.split("#{@path}/").last] && File.file?(template_file_path)
|
||||
register_template(ReloadableTemplate.new(template_relative_path, self))
|
||||
end
|
||||
end
|
||||
|
||||
def register_template(template)
|
||||
template.accessible_paths.each do |path|
|
||||
@paths[path] = template
|
||||
end
|
||||
end
|
||||
|
||||
# remove (probably deleted) template from cache
|
||||
def unregister_template(template)
|
||||
template.accessible_paths.each do |template_path|
|
||||
@paths.delete(template_path) if @paths[template_path] == template
|
||||
end
|
||||
# fill in any newly created gaps
|
||||
@paths.values.uniq.each do |template|
|
||||
template.accessible_paths.each {|path| @paths[path] ||= template}
|
||||
end
|
||||
end
|
||||
|
||||
# load all templates from the directory of the requested template
|
||||
def load_all_templates_from_dir(dir)
|
||||
# hit disk only once per template-dir/request
|
||||
@disk_cache[dir] ||= template_files_from_dir(dir).each {|template_file| register_template_from_file(template_file)}
|
||||
end
|
||||
|
||||
def templates_dir_from_path(path)
|
||||
dirname = File.dirname(path)
|
||||
File.join(@path, dirname == '.' ? '' : dirname)
|
||||
end
|
||||
|
||||
# get all the template filenames from the dir
|
||||
def template_files_from_dir(dir)
|
||||
Dir.glob(File.join(dir, '*'))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
module Unfreezable
|
||||
def freeze; self; end
|
||||
end
|
||||
|
||||
def initialize(*args)
|
||||
super
|
||||
@compiled_methods = []
|
||||
|
||||
# we don't ever want to get frozen
|
||||
extend Unfreezable
|
||||
end
|
||||
|
||||
def mtime
|
||||
File.mtime(filename)
|
||||
end
|
||||
|
||||
attr_accessor :previously_last_modified
|
||||
|
||||
def stale?
|
||||
previously_last_modified.nil? || previously_last_modified < mtime
|
||||
rescue Errno::ENOENT => e
|
||||
undef_my_compiled_methods!
|
||||
raise TemplateDeleted
|
||||
end
|
||||
|
||||
def reset_cache_if_stale!
|
||||
if stale?
|
||||
flush_cache 'source', 'compiled_source'
|
||||
undef_my_compiled_methods!
|
||||
@previously_last_modified = mtime
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
def undef_my_compiled_methods!
|
||||
@compiled_methods.each {|comp_method| ActionView::Base::CompiledTemplates.send(:remove_method, comp_method)}
|
||||
@compiled_methods.clear
|
||||
end
|
||||
|
||||
def compile!(render_symbol, local_assigns)
|
||||
super
|
||||
@compiled_methods << render_symbol
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
@@ -16,18 +16,8 @@ module ActionView
|
||||
memoize :handler
|
||||
|
||||
def compiled_source
|
||||
@compiled_at = Time.now
|
||||
handler.call(self)
|
||||
end
|
||||
memoize :compiled_source
|
||||
|
||||
def compiled_at
|
||||
@compiled_at
|
||||
end
|
||||
|
||||
def defined_at
|
||||
@defined_at ||= {}
|
||||
end
|
||||
|
||||
def method_name_without_locals
|
||||
['_run', extension, method_segment].compact.join('_')
|
||||
@@ -71,12 +61,8 @@ module ActionView
|
||||
def compile(local_assigns)
|
||||
render_symbol = method_name(local_assigns)
|
||||
|
||||
if self.is_a?(InlineTemplate)
|
||||
if !Base::CompiledTemplates.method_defined?(render_symbol) || recompile?
|
||||
compile!(render_symbol, local_assigns)
|
||||
else
|
||||
if !Base::CompiledTemplates.method_defined?(render_symbol) || recompile?(render_symbol)
|
||||
recompile!(render_symbol, local_assigns)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -93,7 +79,6 @@ module ActionView
|
||||
|
||||
begin
|
||||
ActionView::Base::CompiledTemplates.module_eval(source, filename, 0)
|
||||
defined_at[render_symbol] = Time.now if respond_to?(:reloadable?) && reloadable?
|
||||
rescue Errno::ENOENT => e
|
||||
raise e # Missing template file, re-raise for Base to rescue
|
||||
rescue Exception => e # errors from template code
|
||||
@@ -107,17 +92,8 @@ module ActionView
|
||||
end
|
||||
end
|
||||
|
||||
def recompile?(render_symbol)
|
||||
!cached? || redefine?(render_symbol) || stale?
|
||||
end
|
||||
|
||||
def recompile!(render_symbol, local_assigns)
|
||||
compiled_source(:reload) if compiled_at.nil? || compiled_at < mtime
|
||||
compile!(render_symbol, local_assigns)
|
||||
end
|
||||
|
||||
def redefine?(render_symbol)
|
||||
compiled_at && defined_at[render_symbol] && compiled_at > defined_at[render_symbol]
|
||||
def recompile?
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,14 +6,12 @@ module ActionView #:nodoc:
|
||||
|
||||
def initialize(path)
|
||||
raise ArgumentError, "path already is a Path class" if path.is_a?(Path)
|
||||
@path = path.freeze
|
||||
@path = expand_path(path).freeze
|
||||
end
|
||||
|
||||
def load!
|
||||
@paths = {}
|
||||
templates_in_path do |template|
|
||||
load_template(template)
|
||||
end
|
||||
def expand_path(path)
|
||||
# collapse any directory dots in path ('.' or '..')
|
||||
path.starts_with?('/') ? File.expand_path(path) : File.expand_path(path, '/').from(1)
|
||||
end
|
||||
|
||||
def to_s
|
||||
@@ -46,10 +44,42 @@ module ActionView #:nodoc:
|
||||
# etc. A format must be supplied to match a formated file. +hello/index+
|
||||
# will never match +hello/index.html.erb+.
|
||||
def [](path)
|
||||
load! if @paths.nil?
|
||||
@paths[path] || find_template(path)
|
||||
end
|
||||
|
||||
def load!
|
||||
end
|
||||
|
||||
def self.new_and_loaded(path)
|
||||
returning new(path) do |path|
|
||||
path.load!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class EagerPath < Path
|
||||
def initialize(path)
|
||||
super
|
||||
end
|
||||
|
||||
def load!
|
||||
return if @loaded
|
||||
|
||||
@paths = {}
|
||||
templates_in_path do |template|
|
||||
template.load!
|
||||
template.accessible_paths.each do |path|
|
||||
@paths[path] = template
|
||||
end
|
||||
end
|
||||
@paths.freeze
|
||||
@loaded = true
|
||||
end
|
||||
|
||||
def [](path)
|
||||
load! unless @loaded
|
||||
@paths[path]
|
||||
end
|
||||
|
||||
private
|
||||
def templates_in_path
|
||||
(Dir.glob("#{@path}/**/*/**") | Dir.glob("#{@path}/**")).each do |file|
|
||||
@@ -60,30 +90,6 @@ module ActionView #:nodoc:
|
||||
def create_template(file)
|
||||
Template.new(file.split("#{self}/").last, self)
|
||||
end
|
||||
|
||||
def load_template(template)
|
||||
template.load!
|
||||
template.accessible_paths.each do |path|
|
||||
@paths[path] = template
|
||||
end
|
||||
end
|
||||
|
||||
def matching_templates(template_path)
|
||||
Dir.glob("#{@path}/#{template_path}.*").each do |file|
|
||||
yield create_template(file) unless File.directory?(file)
|
||||
end
|
||||
end
|
||||
|
||||
def find_template(path)
|
||||
return nil if Base.cache_template_loading || ActionController::Base.allow_concurrency
|
||||
matching_templates(path) do |template|
|
||||
if template.accessible_paths.include?(path)
|
||||
load_template(template)
|
||||
return template
|
||||
end
|
||||
end
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
extend TemplateHandlers
|
||||
@@ -171,14 +177,10 @@ module ActionView #:nodoc:
|
||||
@@exempt_from_layout.any? { |exempted| path =~ exempted }
|
||||
end
|
||||
|
||||
def mtime
|
||||
File.mtime(filename)
|
||||
end
|
||||
memoize :mtime
|
||||
|
||||
def source
|
||||
File.read(filename)
|
||||
end
|
||||
memoize :source
|
||||
|
||||
def method_segment
|
||||
relative_path.to_s.gsub(/([^a-zA-Z0-9_])/) { $1.ord }
|
||||
@@ -192,27 +194,13 @@ module ActionView #:nodoc:
|
||||
if TemplateError === e
|
||||
e.sub_template_of(self)
|
||||
raise e
|
||||
elsif Errno::ENOENT === e
|
||||
raise MissingTemplate.new(view.view_paths, filename.sub("#{RAILS_ROOT}/#{load_path}/", ""))
|
||||
else
|
||||
raise TemplateError.new(self, view.assigns, e)
|
||||
end
|
||||
end
|
||||
|
||||
def stale?
|
||||
reloadable? && (mtime < mtime(:reload))
|
||||
end
|
||||
|
||||
def load!
|
||||
reloadable? ? memoize_all : freeze
|
||||
end
|
||||
|
||||
def reloadable?
|
||||
!(Base.cache_template_loading || ActionController::Base.allow_concurrency)
|
||||
end
|
||||
|
||||
def cached?
|
||||
ActionController::Base.perform_caching || !reloadable?
|
||||
freeze
|
||||
end
|
||||
|
||||
private
|
||||
@@ -262,5 +250,5 @@ module ActionView #:nodoc:
|
||||
|
||||
[base_path, name, locale, format, extension]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -38,4 +38,8 @@ I18n.backend.store_translations 'pt-BR', {}
|
||||
ORIGINAL_LOCALES = I18n.available_locales.map(&:to_s).sort
|
||||
|
||||
FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures')
|
||||
ActionView::Base.cache_template_loading = true
|
||||
ActionController::Base.view_paths = FIXTURE_LOAD_PATH
|
||||
CACHED_VIEW_PATHS = ActionView::Base.cache_template_loading? ?
|
||||
ActionController::Base.view_paths :
|
||||
ActionController::Base.view_paths.map {|path| ActionView::Template::EagerPath.new(path.to_s)}
|
||||
|
||||
@@ -41,31 +41,35 @@ class ViewLoadPathsTest < ActionController::TestCase
|
||||
def teardown
|
||||
ActiveSupport::Deprecation.behavior = @old_behavior
|
||||
end
|
||||
|
||||
def assert_view_path_strings_are_equal(expected, actual)
|
||||
assert_equal(expected.map {|path| path.sub(/\.\//, '')}, actual)
|
||||
end
|
||||
|
||||
def test_template_load_path_was_set_correctly
|
||||
assert_equal [FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s)
|
||||
assert_view_path_strings_are_equal [FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s)
|
||||
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_view_path_strings_are_equal [FIXTURE_LOAD_PATH, 'foo'], @controller.view_paths.map(&:to_s)
|
||||
|
||||
@controller.append_view_path(%w(bar baz))
|
||||
assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s)
|
||||
assert_view_path_strings_are_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s)
|
||||
|
||||
@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_view_path_strings_are_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s)
|
||||
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_view_path_strings_are_equal ['baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s)
|
||||
|
||||
@controller.prepend_view_path(%w(foo bar))
|
||||
assert_equal ['foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s)
|
||||
assert_view_path_strings_are_equal ['foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s)
|
||||
|
||||
@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_view_path_strings_are_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s)
|
||||
end
|
||||
|
||||
def test_template_appends_view_path_correctly
|
||||
@@ -73,10 +77,10 @@ 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_view_path_strings_are_equal [FIXTURE_LOAD_PATH, 'foo'], @controller.view_paths.map(&:to_s)
|
||||
|
||||
@controller.append_view_path(%w(bar baz))
|
||||
assert_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s)
|
||||
assert_view_path_strings_are_equal [FIXTURE_LOAD_PATH, 'foo', 'bar', 'baz'], @controller.view_paths.map(&:to_s)
|
||||
assert_equal class_view_paths, TestController.view_paths
|
||||
end
|
||||
|
||||
@@ -85,10 +89,10 @@ 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_view_path_strings_are_equal ['baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s)
|
||||
|
||||
@controller.prepend_view_path(%w(foo bar))
|
||||
assert_equal ['foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s)
|
||||
assert_view_path_strings_are_equal ['foo', 'bar', 'baz', FIXTURE_LOAD_PATH], @controller.view_paths.map(&:to_s)
|
||||
assert_equal class_view_paths, TestController.view_paths
|
||||
end
|
||||
|
||||
|
||||
@@ -2,8 +2,21 @@ require 'abstract_unit'
|
||||
require 'controller/fake_models'
|
||||
|
||||
class CompiledTemplatesTest < Test::Unit::TestCase
|
||||
|
||||
def setup
|
||||
@compiled_templates = ActionView::Base::CompiledTemplates
|
||||
|
||||
# first, if we are running the whole test suite with ReloadableTemplates
|
||||
# try to undef all the methods through ReloadableTemplate's interfaces
|
||||
unless ActionView::Base.cache_template_loading?
|
||||
ActionController::Base.view_paths.each do |view_path|
|
||||
view_path.paths.values.uniq!.each do |reloadable_template|
|
||||
reloadable_template.undef_my_compiled_methods!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# just purge anything that's left
|
||||
@compiled_templates.instance_methods.each do |m|
|
||||
@compiled_templates.send(:remove_method, m) if m =~ /^_run_/
|
||||
end
|
||||
@@ -35,17 +48,6 @@ class CompiledTemplatesTest < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
def test_compiled_template_will_always_be_recompiled_when_template_is_not_cached
|
||||
with_caching(false) do
|
||||
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
|
||||
end
|
||||
end
|
||||
|
||||
def test_template_changes_are_not_reflected_with_cached_template_loading
|
||||
with_caching(true) do
|
||||
with_reloading(false) do
|
||||
@@ -63,9 +65,10 @@ class CompiledTemplatesTest < Test::Unit::TestCase
|
||||
with_reloading(true) do
|
||||
assert_equal "Hello world!", render(:file => "test/hello_world.erb")
|
||||
modify_template "test/hello_world.erb", "Goodbye world!" do
|
||||
reset_mtime_of('test/hello_world.erb')
|
||||
assert_equal "Goodbye world!", render(:file => "test/hello_world.erb")
|
||||
sleep(1) # Need to sleep so that the timestamp actually changes
|
||||
end
|
||||
reset_mtime_of('test/hello_world.erb')
|
||||
assert_equal "Hello world!", render(:file => "test/hello_world.erb")
|
||||
end
|
||||
end
|
||||
@@ -74,10 +77,15 @@ class CompiledTemplatesTest < Test::Unit::TestCase
|
||||
private
|
||||
def render(*args)
|
||||
view_paths = ActionController::Base.view_paths
|
||||
assert_equal ActionView::Template::Path, view_paths.first.class
|
||||
ActionView::Base.new(view_paths, {}).render(*args)
|
||||
end
|
||||
|
||||
def reset_mtime_of(template_name)
|
||||
unless ActionView::Base.cache_template_loading?
|
||||
ActionController::Base.view_paths.find_template(template_name).previously_last_modified = 10.seconds.ago
|
||||
end
|
||||
end
|
||||
|
||||
def modify_template(template, content)
|
||||
filename = "#{FIXTURE_LOAD_PATH}/#{template}"
|
||||
old_content = File.read(filename)
|
||||
@@ -100,12 +108,18 @@ class CompiledTemplatesTest < Test::Unit::TestCase
|
||||
end
|
||||
|
||||
def with_reloading(reload_templates)
|
||||
old_cache_template_loading = ActionView::Base.cache_template_loading
|
||||
old_view_paths, old_cache_templates = ActionController::Base.view_paths, ActionView::Base.cache_template_loading
|
||||
begin
|
||||
ActionView::Base.cache_template_loading = !reload_templates
|
||||
ActionController::Base.view_paths = view_paths_for(reload_templates)
|
||||
yield
|
||||
ensure
|
||||
ActionView::Base.cache_template_loading = old_cache_template_loading
|
||||
ActionController::Base.view_paths, ActionView::Base.cache_template_loading = old_view_paths, old_cache_templates
|
||||
end
|
||||
end
|
||||
|
||||
def view_paths_for(reload_templates)
|
||||
# reloadable paths are cheap to create
|
||||
reload_templates ? ActionView::PathSet.new(CACHED_VIEW_PATHS.map(&:to_s)) : CACHED_VIEW_PATHS
|
||||
end
|
||||
end
|
||||
|
||||
@@ -243,13 +243,34 @@ module RenderTestCases
|
||||
end
|
||||
end
|
||||
|
||||
class CachedRenderTest < Test::Unit::TestCase
|
||||
include RenderTestCases
|
||||
|
||||
# Ensure view path cache is primed
|
||||
def setup
|
||||
view_paths = ActionController::Base.view_paths
|
||||
assert_equal ActionView::Template::Path, view_paths.first.class
|
||||
module TemplatesSetupTeardown
|
||||
def setup_view_paths_for(new_cache_template_loading)
|
||||
@previous_cache_template_loading, ActionView::Base.cache_template_loading = ActionView::Base.cache_template_loading, new_cache_template_loading
|
||||
view_paths = new_cache_template_loading ? CACHED_VIEW_PATHS : ActionView::Base.process_view_paths(CACHED_VIEW_PATHS.map(&:to_s))
|
||||
assert_equal(new_cache_template_loading ? ActionView::Template::EagerPath : ActionView::ReloadableTemplate::ReloadablePath, view_paths.first.class)
|
||||
setup_view(view_paths)
|
||||
end
|
||||
|
||||
def teardown
|
||||
ActionView::Base.cache_template_loading = @previous_cache_template_loading
|
||||
end
|
||||
end
|
||||
|
||||
class CachedRenderTest < Test::Unit::TestCase
|
||||
include TemplatesSetupTeardown
|
||||
include RenderTestCases
|
||||
|
||||
def setup
|
||||
setup_view_paths_for(cache_templates = true)
|
||||
end
|
||||
end
|
||||
|
||||
class ReloadableRenderTest < Test::Unit::TestCase
|
||||
include TemplatesSetupTeardown
|
||||
include RenderTestCases
|
||||
|
||||
def setup
|
||||
setup_view_paths_for(cache_templates = false)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ config.whiny_nils = true
|
||||
# Show full error reports and disable caching
|
||||
config.action_controller.consider_all_requests_local = true
|
||||
config.action_controller.perform_caching = false
|
||||
config.action_view.cache_template_loading = true
|
||||
|
||||
# Disable request forgery protection in test environment
|
||||
config.action_controller.allow_forgery_protection = false
|
||||
|
||||
@@ -369,8 +369,8 @@ Run `rake gems:install` to install the missing gems.
|
||||
|
||||
def load_view_paths
|
||||
if configuration.frameworks.include?(:action_view)
|
||||
ActionController::Base.view_paths.each { |path| path.load! } if configuration.frameworks.include?(:action_controller)
|
||||
ActionMailer::Base.template_root.load! if configuration.frameworks.include?(:action_mailer)
|
||||
ActionController::Base.view_paths.load! if configuration.frameworks.include?(:action_controller)
|
||||
ActionMailer::Base.view_paths.load! if configuration.frameworks.include?(:action_mailer)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -478,7 +478,7 @@ Run `rake gems:install` to install the missing gems.
|
||||
# set to use Configuration#view_path.
|
||||
def initialize_framework_views
|
||||
if configuration.frameworks.include?(:action_view)
|
||||
view_path = ActionView::Template::Path.new(configuration.view_path)
|
||||
view_path = ActionView::PathSet.type_cast(configuration.view_path)
|
||||
ActionMailer::Base.template_root ||= view_path if configuration.frameworks.include?(:action_mailer)
|
||||
ActionController::Base.view_paths = view_path if configuration.frameworks.include?(:action_controller) && ActionController::Base.view_paths.empty?
|
||||
end
|
||||
|
||||
@@ -130,7 +130,7 @@ 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').sub(/\A\.\//, '') ], ActionController::Base.view_paths
|
||||
end
|
||||
|
||||
def test_should_add_plugin_load_paths_to_Dependencies_load_once_paths
|
||||
|
||||
Reference in New Issue
Block a user