diff --git a/lib/cache_digests/dependency_tracker.rb b/lib/cache_digests/dependency_tracker.rb index 86eb444..1032d9a 100644 --- a/lib/cache_digests/dependency_tracker.rb +++ b/lib/cache_digests/dependency_tracker.rb @@ -1,66 +1,84 @@ module CacheDigests class DependencyTracker - EXPLICIT_DEPENDENCY = /# Template Dependency: (\S+)/ - - # Matches: - # render partial: "comments/comment", collection: commentable.comments - # render "comments/comments" - # render 'comments/comments' - # render('comments/comments') - # - # render(@topic) => render("topics/topic") - # render(topics) => render("topics/topic") - # render(message.topics) => render("topics/topic") - RENDER_DEPENDENCY = / - render\s* # render, followed by optional whitespace - \(? # start an optional parenthesis for the render call - (partial:|:partial\s+=>)?\s* # naming the partial, used with collection -- 1st capture - ([@a-z"'][@a-z_\/\."']+) # the template name itself -- 2nd capture - /x + @trackers = Hash.new def self.find_dependencies(name, template) - new(name, template).dependencies + @trackers.fetch(template.handler).call(name, template) end - def initialize(name, template) - @name, @template = name, template + def self.register_tracker(handler, tracker) + @trackers[handler] = tracker end - def dependencies - render_dependencies + explicit_dependencies - rescue ActionView::MissingTemplate - [] # File doesn't exist, so no dependencies + def self.unregister_tracker(handler) + @trackers.delete(handler) end - private - attr_reader :name, :template + class ErbTracker + EXPLICIT_DEPENDENCY = /# Template Dependency: (\S+)/ + + # Matches: + # render partial: "comments/comment", collection: commentable.comments + # render "comments/comments" + # render 'comments/comments' + # render('comments/comments') + # + # render(@topic) => render("topics/topic") + # render(topics) => render("topics/topic") + # render(message.topics) => render("topics/topic") + RENDER_DEPENDENCY = / + render\s* # render, followed by optional whitespace + \(? # start an optional parenthesis for the render call + (partial:|:partial\s+=>)?\s* # naming the partial, used with collection -- 1st capture + ([@a-z"'][@a-z_\/\."']+) # the template name itself -- 2nd capture + /x - def source - template.source + def self.call(name, template) + new(name, template).dependencies end - - def directory - name.split("/")[0..-2].join("/") + + def initialize(name, template) + @name, @template = name, template end - def render_dependencies - source.scan(RENDER_DEPENDENCY). - collect(&:second).uniq. + def dependencies + render_dependencies + explicit_dependencies + rescue ActionView::MissingTemplate + [] # File doesn't exist, so no dependencies + end - # render(@topic) => render("topics/topic") - # render(topics) => render("topics/topic") - # render(message.topics) => render("topics/topic") - collect { |name| name.sub(/\A@?([a-z]+\.)*([a-z_]+)\z/) { "#{$2.pluralize}/#{$2.singularize}" } }. + private + attr_reader :name, :template - # render("headline") => render("message/headline") - collect { |name| name.include?("/") ? name : "#{directory}/#{name}" }. - - # replace quotes from string renders - collect { |name| name.gsub(/["']/, "") } - end + def source + template.source + end + + def directory + name.split("/")[0..-2].join("/") + end - def explicit_dependencies - source.scan(EXPLICIT_DEPENDENCY).flatten.uniq - end + def render_dependencies + source.scan(RENDER_DEPENDENCY). + collect(&:second).uniq. + + # render(@topic) => render("topics/topic") + # render(topics) => render("topics/topic") + # render(message.topics) => render("topics/topic") + collect { |name| name.sub(/\A@?([a-z]+\.)*([a-z_]+)\z/) { "#{$2.pluralize}/#{$2.singularize}" } }. + + # render("headline") => render("message/headline") + collect { |name| name.include?("/") ? name : "#{directory}/#{name}" }. + + # replace quotes from string renders + collect { |name| name.gsub(/["']/, "") } + end + + def explicit_dependencies + source.scan(EXPLICIT_DEPENDENCY).flatten.uniq + end + end + + register_tracker(:erb, ErbTracker) end end diff --git a/test/dependency_tracker_test.rb b/test/dependency_tracker_test.rb new file mode 100644 index 0000000..314adda --- /dev/null +++ b/test/dependency_tracker_test.rb @@ -0,0 +1,32 @@ +require 'cache_digests/test_helper' + +class NeckbeardTracker + def self.call(name, template) + ["foo/#{name}"] + end +end + +class DependencyTrackerTest < MiniTest::Unit::TestCase + class FixtureTemplate + attr_reader :source, :handler + + def initialize(source, handler) + @source, @handler = source, handler + end + end + + def setup + CacheDigests::DependencyTracker.register_tracker(:neckbeard, NeckbeardTracker) + end + + def teardown + CacheDigests::DependencyTracker.unregister_tracker(:neckbeard) + end + + def test_finds_tracker_by_template_handler + name = "boo/hoo" + template = FixtureTemplate.new("whatevs", :neckbeard) + dependencies = CacheDigests::DependencyTracker.find_dependencies(name, template) + assert_equal ["foo/boo/hoo"], dependencies + end +end diff --git a/test/template_digestor_test.rb b/test/template_digestor_test.rb index 86df232..a30bf16 100644 --- a/test/template_digestor_test.rb +++ b/test/template_digestor_test.rb @@ -7,10 +7,11 @@ class MissingTemplate < StandardError end class FixtureTemplate - attr_reader :source + attr_reader :source, :handler - def initialize(template_path) + def initialize(template_path, handler = :erb) @source = File.read(template_path) + @handler = handler rescue Errno::ENOENT raise ActionView::MissingTemplate end