Created
February 12, 2009 15:37
-
-
Save pixeltrix/62681 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 832c042e2c8eba2200627cc62de2854edcfb07c1 Mon Sep 17 00:00:00 2001 | |
From: thedarkone <nobody> | |
Date: Wed, 11 Feb 2009 21:39:48 +0100 | |
Subject: [PATCH] Port fast reloadable templates from rails-dev-boost. | |
--- | |
actionmailer/test/abstract_unit.rb | 1 + | |
actionmailer/test/mail_service_test.rb | 2 +- | |
actionpack/lib/action_controller/rescue.rb | 2 +- | |
actionpack/lib/action_view.rb | 1 + | |
actionpack/lib/action_view/base.rb | 13 ++- | |
actionpack/lib/action_view/partials.rb | 1 + | |
actionpack/lib/action_view/paths.rb | 21 ++- | |
actionpack/lib/action_view/reloadable_template.rb | 154 ++++++++++++++++++++ | |
actionpack/lib/action_view/renderable.rb | 30 +---- | |
actionpack/lib/action_view/template.rb | 86 +++++------ | |
actionpack/test/abstract_unit.rb | 4 + | |
actionpack/test/controller/view_paths_test.rb | 26 ++-- | |
.../test/template/compiled_templates_test.rb | 26 ++-- | |
actionpack/test/template/render_test.rb | 29 +++- | |
railties/environments/test.rb | 1 + | |
railties/lib/initializer.rb | 6 +- | |
16 files changed, 282 insertions(+), 121 deletions(-) | |
create mode 100644 actionpack/lib/action_view/reloadable_template.rb | |
diff --git a/actionmailer/test/abstract_unit.rb b/actionmailer/test/abstract_unit.rb | |
index 51b375f..81b59f1 100644 | |
--- a/actionmailer/test/abstract_unit.rb | |
+++ b/actionmailer/test/abstract_unit.rb | |
@@ -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 = false | |
FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures') | |
ActionMailer::Base.template_root = FIXTURE_LOAD_PATH | |
diff --git a/actionmailer/test/mail_service_test.rb b/actionmailer/test/mail_service_test.rb | |
index 1e04531..0934d35 100644 | |
--- a/actionmailer/test/mail_service_test.rb | |
+++ b/actionmailer/test/mail_service_test.rb | |
@@ -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) | |
diff --git a/actionpack/lib/action_controller/rescue.rb b/actionpack/lib/action_controller/rescue.rb | |
index 40aa7cd..242c8da 100644 | |
--- a/actionpack/lib/action_controller/rescue.rb | |
+++ b/actionpack/lib/action_controller/rescue.rb | |
@@ -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: | |
diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb | |
index 0b710bd..1f1ff9d 100644 | |
--- a/actionpack/lib/action_view.rb | |
+++ b/actionpack/lib/action_view.rb | |
@@ -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' | |
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb | |
index 3134807..4198725 100644 | |
--- a/actionpack/lib/action_view/base.rb | |
+++ b/actionpack/lib/action_view/base.rb | |
@@ -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] | |
diff --git a/actionpack/lib/action_view/partials.rb b/actionpack/lib/action_view/partials.rb | |
index 6fe4dbf..9e5e0f7 100644 | |
--- a/actionpack/lib/action_view/partials.rb | |
+++ b/actionpack/lib/action_view/partials.rb | |
@@ -235,5 +235,6 @@ module ActionView | |
self.view_paths.find_template(path, self.template_format) | |
end | |
+ memoize :_pick_partial_template | |
end | |
end | |
diff --git a/actionpack/lib/action_view/paths.rb b/actionpack/lib/action_view/paths.rb | |
index e14b212..0995c24 100644 | |
--- a/actionpack/lib/action_view/paths.rb | |
+++ b/actionpack/lib/action_view/paths.rb | |
@@ -2,7 +2,11 @@ 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 | |
@@ -32,8 +36,13 @@ module ActionView #:nodoc: | |
super(*objs.map { |obj| self.class.type_cast(obj) }) | |
end | |
- def find_template(template_path, format = nil) | |
- return template_path if template_path.respond_to?(:render) | |
+ def load! | |
+ each(&:load!) | |
+ end | |
+ | |
+ 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 | |
diff --git a/actionpack/lib/action_view/reloadable_template.rb b/actionpack/lib/action_view/reloadable_template.rb | |
new file mode 100644 | |
index 0000000..6b715dc | |
--- /dev/null | |
+++ b/actionpack/lib/action_view/reloadable_template.rb | |
@@ -0,0 +1,154 @@ | |
+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 ReloadableCompiledTemplates | |
+ | |
+ # Need to monitor when compiled methods are removed | |
+ def register_template(render_symbol, template) | |
+ template_cache[render_symbol] = template | |
+ end | |
+ | |
+ def unregister_template(render_symbol, template) | |
+ template_cache.delete(render_symbol) | |
+ end | |
+ | |
+ def template_cache | |
+ @template_cache ||= {} | |
+ end | |
+ | |
+ def reset_template_cache | |
+ @template_cache = {} | |
+ end | |
+ | |
+ def remove_method(render_symbol) | |
+ super | |
+ if template = template_cache.delete(render_symbol.to_sym) | |
+ template.compiled_methods.delete(render_symbol.to_sym) | |
+ end | |
+ end | |
+ | |
+ end | |
+ | |
+ Base::CompiledTemplates.send :extend, ReloadableCompiledTemplates | |
+ | |
+ 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) } | |
+ end | |
+ | |
+ def compiled_methods | |
+ @compiled_methods | |
+ end | |
+ | |
+ def compile!(render_symbol, local_assigns) | |
+ super | |
+ Base::CompiledTemplates.register_template(render_symbol, self) | |
+ @compiled_methods << render_symbol | |
+ end | |
+ | |
+ end | |
+end | |
diff --git a/actionpack/lib/action_view/renderable.rb b/actionpack/lib/action_view/renderable.rb | |
index 16cdd01..41080ed 100644 | |
--- a/actionpack/lib/action_view/renderable.rb | |
+++ b/actionpack/lib/action_view/renderable.rb | |
@@ -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 | |
diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template.rb | |
index f2d3998..88e5368 100644 | |
--- a/actionpack/lib/action_view/template.rb | |
+++ b/actionpack/lib/action_view/template.rb | |
@@ -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,43 +44,51 @@ 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 | |
- private | |
- def templates_in_path | |
- (Dir.glob("#{@path}/**/*/**") | Dir.glob("#{@path}/**")).each do |file| | |
- yield create_template(file) unless File.directory?(file) | |
- end | |
- end | |
+ def load! | |
+ end | |
- def create_template(file) | |
- Template.new(file.split("#{self}/").last, self) | |
+ 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 | |
- def load_template(template) | |
+ @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 | |
- def matching_templates(template_path) | |
- Dir.glob("#{@path}/#{template_path}.*").each do |file| | |
+ private | |
+ def templates_in_path | |
+ (Dir.glob("#{@path}/**/*/**") | Dir.glob("#{@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 | |
+ def create_template(file) | |
+ Template.new(file.split("#{self}/").last, self) | |
end | |
end | |
@@ -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 | |
diff --git a/actionpack/test/abstract_unit.rb b/actionpack/test/abstract_unit.rb | |
index 07bd7ba..8fbb357 100644 | |
--- a/actionpack/test/abstract_unit.rb | |
+++ b/actionpack/test/abstract_unit.rb | |
@@ -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 = false | |
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)} | |
diff --git a/actionpack/test/controller/view_paths_test.rb b/actionpack/test/controller/view_paths_test.rb | |
index ac84e2d..bf36913 100644 | |
--- a/actionpack/test/controller/view_paths_test.rb | |
+++ b/actionpack/test/controller/view_paths_test.rb | |
@@ -42,30 +42,34 @@ class ViewLoadPathsTest < ActionController::TestCase | |
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 | |
diff --git a/actionpack/test/template/compiled_templates_test.rb b/actionpack/test/template/compiled_templates_test.rb | |
index 55fa346..f7b1541 100644 | |
--- a/actionpack/test/template/compiled_templates_test.rb | |
+++ b/actionpack/test/template/compiled_templates_test.rb | |
@@ -2,6 +2,7 @@ require 'abstract_unit' | |
require 'controller/fake_models' | |
class CompiledTemplatesTest < Test::Unit::TestCase | |
+ | |
def setup | |
@compiled_templates = ActionView::Base::CompiledTemplates | |
@compiled_templates.instance_methods.each do |m| | |
@@ -35,17 +36,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,8 +53,9 @@ 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 | |
+ ActionController::Base.view_paths.find_template('test/hello_world.erb').previously_last_modified = 10.seconds.ago | |
assert_equal "Goodbye world!", render(:file => "test/hello_world.erb") | |
- sleep(1) # Need to sleep so that the timestamp actually changes | |
+ ActionController::Base.view_paths.find_template('test/hello_world.erb').previously_last_modified = 10.seconds.ago | |
end | |
assert_equal "Hello world!", render(:file => "test/hello_world.erb") | |
end | |
@@ -74,7 +65,6 @@ 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 | |
@@ -100,12 +90,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 | |
diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb | |
index 34e7e82..a1670bc 100644 | |
--- a/actionpack/test/template/render_test.rb | |
+++ b/actionpack/test/template/render_test.rb | |
@@ -243,13 +243,34 @@ module RenderTestCases | |
end | |
end | |
+module TemplateRenderTeardown | |
+ 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 TemplateRenderTeardown | |
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 | |
- setup_view(view_paths) | |
+ setup_view_paths_for(cache_templates = true) | |
end | |
end | |
+ | |
+class ReloadableRenderTest < Test::Unit::TestCase | |
+ include TemplateRenderTeardown | |
+ include RenderTestCases | |
+ | |
+ def setup | |
+ setup_view_paths_for(cache_templates = false) | |
+ end | |
+end | |
+ | |
diff --git a/railties/environments/test.rb b/railties/environments/test.rb | |
index 496eb95..d6f80a4 100644 | |
--- a/railties/environments/test.rb | |
+++ b/railties/environments/test.rb | |
@@ -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 | |
diff --git a/railties/lib/initializer.rb b/railties/lib/initializer.rb | |
index c4c55a9..281b074 100644 | |
--- a/railties/lib/initializer.rb | |
+++ b/railties/lib/initializer.rb | |
@@ -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 | |
-- | |
1.5.4.5 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment