diff --git a/lib/jbuilder/dependency_tracker.rb b/lib/jbuilder/dependency_tracker.rb new file mode 100644 index 0000000..7c16c60 --- /dev/null +++ b/lib/jbuilder/dependency_tracker.rb @@ -0,0 +1,47 @@ +require 'jbuilder' +require 'action_view' +require 'action_view/dependency_tracker' + +class Jbuilder + class DependencyTracker < ::ActionView::DependencyTracker::ERBTracker + # Matches: + # json.partial! "messages/message" + DIRECT_RENDERS = / + \w+\.partial! # json.partial! + \(?\s* # optional parenthesis + (['"])([^""]+)\1 # quoted value + /x + + + # Matches: + # json.partial! partial: "comments/comment" + # json.comments @post.comments, partial: "comments/comment", as: :comment + # json.array! @posts, partial: "posts/post", as: :post + # = render partial: "account" + # + INDIRECT_RENDERS = / + (?::partial\s*=>|partial:) + \s* + (['"])([^'"]+)\1 + /x + + def dependencies + direct_dependencies + indirect_dependencies + explicit_dependencies + end + + def direct_dependencies + source.scan(DIRECT_RENDERS).map(&:second) + end + + def indirect_dependencies + source.scan(INDIRECT_RENDERS).map(&:second) + end + end +end + + +ActiveSupport.on_load :action_view do + ActiveSupport.on_load :after_initialize do + ActionView::DependencyTracker.register_tracker :jbuilder, Jbuilder::DependencyTracker + end +end diff --git a/test/jbuilder_dependency_tracker_test.rb b/test/jbuilder_dependency_tracker_test.rb new file mode 100644 index 0000000..35fe576 --- /dev/null +++ b/test/jbuilder_dependency_tracker_test.rb @@ -0,0 +1,63 @@ +require 'test/unit' +require 'active_support/test_case' +require 'jbuilder/dependency_tracker' + + +class FakeTemplate + attr_reader :source, :handler + def initialize(source, handler = :jbuilder) + @source, @handler = source, handler + end +end + + +class JbuilderDependencyTrackerTest < ActiveSupport::TestCase + def make_tracker(name, source) + template = FakeTemplate.new(source) + Jbuilder::DependencyTracker.new(name, template) + end + + def track_dependencies(source) + make_tracker('jbuilder_template', source).dependencies + end + + test 'detects dependency via direct partial! call' do + dependencies = track_dependencies <<-RUBY + json.partial! 'path/to/partial' + RUBY + + assert_equal %w[path/to/partial], dependencies + end + + test 'detects dependency via direct partial! call with parens' do + dependencies = track_dependencies <<-RUBY + json.partial!("path/to/partial") + RUBY + + assert_equal %w[path/to/partial], dependencies + end + + test 'detects partial with options (1.9 style)' do + dependencies = track_dependencies <<-RUBY + json.partial! hello: 'world', partial: 'path/to/partial', foo: :bar + RUBY + + assert_equal %w[path/to/partial], dependencies + end + + test 'detects partial with options (1.8 style)' do + dependencies = track_dependencies <<-RUBY + json.partial! :hello => 'world', :partial => 'path/to/partial', :foo => :bar + RUBY + + assert_equal %w[path/to/partial], dependencies + end + + test 'detects partial in indirect collecton calls' do + dependencies = track_dependencies <<-RUBY + json.comments @post.comments, partial: 'comments/comment', as: :comment + RUBY + + assert_equal %w[comments/comment], dependencies + end +end