mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Merge pull request #20904 from kaspth/wildcard-template-dependencies
Add wildcard template dependencies.
This commit is contained in:
commit
c5583cd79c
9 changed files with 121 additions and 12 deletions
|
@ -1,3 +1,21 @@
|
||||||
|
* Add wildcard matching to explicit dependencies.
|
||||||
|
|
||||||
|
Turns:
|
||||||
|
|
||||||
|
```erb
|
||||||
|
<% # Template Dependency: recordings/threads/events/subscribers_changed %>
|
||||||
|
<% # Template Dependency: recordings/threads/events/completed %>
|
||||||
|
<% # Template Dependency: recordings/threads/events/uncompleted %>
|
||||||
|
```
|
||||||
|
|
||||||
|
Into:
|
||||||
|
|
||||||
|
```erb
|
||||||
|
<% # Template Dependency: recordings/threads/events/* %>
|
||||||
|
```
|
||||||
|
|
||||||
|
*Kasper Timm Hansen*
|
||||||
|
|
||||||
* Allow defining explicit collection caching using a `# Template Collection: ...`
|
* Allow defining explicit collection caching using a `# Template Collection: ...`
|
||||||
directive inside templates.
|
directive inside templates.
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
require 'thread_safe'
|
require 'thread_safe'
|
||||||
|
require 'action_view/path_set'
|
||||||
|
|
||||||
module ActionView
|
module ActionView
|
||||||
class DependencyTracker # :nodoc:
|
class DependencyTracker # :nodoc:
|
||||||
@trackers = ThreadSafe::Cache.new
|
@trackers = ThreadSafe::Cache.new
|
||||||
|
|
||||||
def self.find_dependencies(name, template)
|
def self.find_dependencies(name, template, view_paths = nil)
|
||||||
tracker = @trackers[template.handler]
|
tracker = @trackers[template.handler]
|
||||||
|
return [] unless tracker.present?
|
||||||
|
|
||||||
if tracker.present?
|
if tracker.respond_to?(:supports_view_paths?) && tracker.supports_view_paths?
|
||||||
tracker.call(name, template)
|
tracker.call(name, template, view_paths)
|
||||||
else
|
else
|
||||||
[]
|
tracker.call(name, template)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -82,12 +84,16 @@ module ActionView
|
||||||
(?:#{STRING}|#{VARIABLE_OR_METHOD_CHAIN}) # finally, the dependency name of interest
|
(?:#{STRING}|#{VARIABLE_OR_METHOD_CHAIN}) # finally, the dependency name of interest
|
||||||
/xm
|
/xm
|
||||||
|
|
||||||
def self.call(name, template)
|
def self.supports_view_paths? # :nodoc:
|
||||||
new(name, template).dependencies
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(name, template)
|
def self.call(name, template, view_paths = nil)
|
||||||
@name, @template = name, template
|
new(name, template, view_paths).dependencies
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(name, template, view_paths = nil)
|
||||||
|
@name, @template, @view_paths = name, template, view_paths
|
||||||
end
|
end
|
||||||
|
|
||||||
def dependencies
|
def dependencies
|
||||||
|
@ -142,8 +148,22 @@ module ActionView
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def resolve_directories(wildcard_dependencies)
|
||||||
|
return [] unless @view_paths
|
||||||
|
|
||||||
|
wildcard_dependencies.each_with_object([]) do |query, templates|
|
||||||
|
@view_paths.find_all_with_query(query).each do |template|
|
||||||
|
templates << "#{File.dirname(query)}/#{File.basename(template).split('.').first}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def explicit_dependencies
|
def explicit_dependencies
|
||||||
source.scan(EXPLICIT_DEPENDENCY).flatten.uniq
|
dependencies = source.scan(EXPLICIT_DEPENDENCY).flatten.uniq
|
||||||
|
|
||||||
|
wildcards, explicits = dependencies.partition { |dependency| dependency[-1] == '*' }
|
||||||
|
|
||||||
|
(explicits + resolve_directories(wildcards)).uniq
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ module ActionView
|
||||||
end
|
end
|
||||||
|
|
||||||
def dependencies
|
def dependencies
|
||||||
DependencyTracker.find_dependencies(name, template)
|
DependencyTracker.find_dependencies(name, template, finder.view_paths)
|
||||||
rescue ActionView::MissingTemplate
|
rescue ActionView::MissingTemplate
|
||||||
logger.try :error, " '#{name}' file doesn't exist, so no dependencies"
|
logger.try :error, " '#{name}' file doesn't exist, so no dependencies"
|
||||||
[]
|
[]
|
||||||
|
|
|
@ -98,7 +98,19 @@ module ActionView
|
||||||
# <%# Template Dependency: todolists/todolist %>
|
# <%# Template Dependency: todolists/todolist %>
|
||||||
# <%= render_sortable_todolists @project.todolists %>
|
# <%= render_sortable_todolists @project.todolists %>
|
||||||
#
|
#
|
||||||
# The pattern used to match these is <tt>/# Template Dependency: (\S+)/</tt>,
|
# In some cases, like a single table inheritance setup, you might have
|
||||||
|
# a bunch of explicit dependencies. Instead of writing every template out,
|
||||||
|
# you can use a wildcard to match any template in a directory:
|
||||||
|
#
|
||||||
|
# <%# Template Dependency: events/* %>
|
||||||
|
# <%= render_categorizable_events @person.events %>
|
||||||
|
#
|
||||||
|
# This marks every template in the directory as a dependency. To find those
|
||||||
|
# templates, the wildcard path must be absolutely defined from app/views or paths
|
||||||
|
# otherwise added with +prepend_view_path+ or +append_view_path+.
|
||||||
|
# This way the wildcard for `app/views/recordings/events` would be `recordings/events/*` etc.
|
||||||
|
#
|
||||||
|
# The pattern used to match explicit dependencies is <tt>/# Template Dependency: (\S+)/</tt>,
|
||||||
# so it's important that you type it out just so.
|
# so it's important that you type it out just so.
|
||||||
# You can only declare one template dependency per line.
|
# You can only declare one template dependency per line.
|
||||||
#
|
#
|
||||||
|
|
|
@ -61,6 +61,15 @@ module ActionView #:nodoc:
|
||||||
find_all(path, prefixes, *args).any?
|
find_all(path, prefixes, *args).any?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def find_all_with_query(query) # :nodoc:
|
||||||
|
paths.each do |resolver|
|
||||||
|
templates = resolver.find_all_with_query(query)
|
||||||
|
return templates unless templates.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
[]
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def typecast(paths)
|
def typecast(paths)
|
||||||
|
|
|
@ -52,6 +52,7 @@ module ActionView
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@data = SmallCache.new(&KEY_BLOCK)
|
@data = SmallCache.new(&KEY_BLOCK)
|
||||||
|
@query_cache = SmallCache.new
|
||||||
end
|
end
|
||||||
|
|
||||||
# Cache the templates returned by the block
|
# Cache the templates returned by the block
|
||||||
|
@ -70,8 +71,17 @@ module ActionView
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def cache_query(query) # :nodoc:
|
||||||
|
if Resolver.caching?
|
||||||
|
@query_cache[query] ||= canonical_no_templates(yield)
|
||||||
|
else
|
||||||
|
yield
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def clear
|
def clear
|
||||||
@data.clear
|
@data.clear
|
||||||
|
@query_cache.clear
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -116,6 +126,10 @@ module ActionView
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def find_all_with_query(query) # :nodoc:
|
||||||
|
@cache.cache_query(query) { find_template_paths(File.join(@path, query)) }
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
delegate :caching?, to: :class
|
delegate :caching?, to: :class
|
||||||
|
|
0
actionview/test/fixtures/digestor/events/_completed.html.erb
vendored
Normal file
0
actionview/test/fixtures/digestor/events/_completed.html.erb
vendored
Normal file
1
actionview/test/fixtures/digestor/events/index.html.erb
vendored
Normal file
1
actionview/test/fixtures/digestor/events/index.html.erb
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<% # Template Dependency: events/* %>
|
|
@ -1,5 +1,6 @@
|
||||||
require 'abstract_unit'
|
require 'abstract_unit'
|
||||||
require 'fileutils'
|
require 'fileutils'
|
||||||
|
require 'action_view/dependency_tracker'
|
||||||
|
|
||||||
class FixtureTemplate
|
class FixtureTemplate
|
||||||
attr_reader :source, :handler
|
attr_reader :source, :handler
|
||||||
|
@ -15,12 +16,13 @@ end
|
||||||
class FixtureFinder
|
class FixtureFinder
|
||||||
FIXTURES_DIR = "#{File.dirname(__FILE__)}/../fixtures/digestor"
|
FIXTURES_DIR = "#{File.dirname(__FILE__)}/../fixtures/digestor"
|
||||||
|
|
||||||
attr_reader :details
|
attr_reader :details, :view_paths
|
||||||
attr_accessor :formats
|
attr_accessor :formats
|
||||||
attr_accessor :variants
|
attr_accessor :variants
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@details = {}
|
@details = {}
|
||||||
|
@view_paths = ActionView::PathSet.new(['digestor'])
|
||||||
@formats = []
|
@formats = []
|
||||||
@variants = []
|
@variants = []
|
||||||
end
|
end
|
||||||
|
@ -75,6 +77,34 @@ class TemplateDigestorTest < ActionView::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_explicit_dependency_wildcard
|
||||||
|
assert_digest_difference("events/index") do
|
||||||
|
change_template("events/_completed")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_explicit_dependency_wildcard_picks_up_added_file
|
||||||
|
old_caching, ActionView::Resolver.caching = ActionView::Resolver.caching, false
|
||||||
|
|
||||||
|
assert_digest_difference("events/index") do
|
||||||
|
add_template("events/_uncompleted")
|
||||||
|
end
|
||||||
|
ensure
|
||||||
|
remove_template("events/_uncompleted")
|
||||||
|
ActionView::Resolver.caching = old_caching
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_explicit_dependency_wildcard_picks_up_removed_file
|
||||||
|
old_caching, ActionView::Resolver.caching = ActionView::Resolver.caching, false
|
||||||
|
add_template("events/_subscribers_changed")
|
||||||
|
|
||||||
|
assert_digest_difference("events/index") do
|
||||||
|
remove_template("events/_subscribers_changed")
|
||||||
|
end
|
||||||
|
ensure
|
||||||
|
ActionView::Resolver.caching = old_caching
|
||||||
|
end
|
||||||
|
|
||||||
def test_second_level_dependency
|
def test_second_level_dependency
|
||||||
assert_digest_difference("messages/show") do
|
assert_digest_difference("messages/show") do
|
||||||
change_template("comments/_comments")
|
change_template("comments/_comments")
|
||||||
|
@ -319,4 +349,9 @@ class TemplateDigestorTest < ActionView::TestCase
|
||||||
f.write "\nTHIS WAS CHANGED!"
|
f.write "\nTHIS WAS CHANGED!"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
alias_method :add_template, :change_template
|
||||||
|
|
||||||
|
def remove_template(template_name)
|
||||||
|
File.delete("digestor/#{template_name}.html.erb")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue