Skip to content

Instantly share code, notes, and snippets.

@mschuerig
Created June 8, 2012 06:44
Show Gist options
  • Save mschuerig/2894015 to your computer and use it in GitHub Desktop.
Save mschuerig/2894015 to your computer and use it in GitHub Desktop.
Display a hierarchical listing of templates and which other templates they include
#! /usr/bin/ruby1.9.1
require 'find'
require 'set'
module Tools
class ViewStructure
include Enumerable
EXTENSIONS = '.erb'
def initialize(*views_roots)
@top_level_templates = Set.new
@inclusions = Hash.new { |h, path|
h[path] = []
}
@removed_prefix = views_roots.size == 1 ? "#{views_roots.first}/" : ''
views_roots.each do |root|
analyze(root)
end
end
def self.show(views_root)
new(views_root).show
end
def self.each(views_root, &block) # :yields: template, level
new(views_root).each(&block)
end
def each(&block) # :yields: template, level
@top_level_templates.sort_by { |t| t.split('/') }.each do |template|
walk_inclusions(template, &block)
end
end
def show
each do |template, level|
puts "#{' ' * level}#{template}"
end
end
private
def analyze(root)
Find.find root do |path|
next unless File.file?(path) && EXTENSIONS.include?(File.extname(path))
File.read(path).scan(%r{
render
\s+
(?::partial\s+=>|partial:)?
\s*
(['"])
(.+?)
\1 # match closing quote
}mx) do |_, partial|
template = unqualified_path(path)
@top_level_templates << template unless partial?(template)
resolved = resolve_template(partial, File.dirname(template))
@inclusions[template] << resolved unless @inclusions[template].include?(resolved)
end
end
end
def partial?(file)
File.basename(file).start_with?('_')
end
def unqualified_path(path, partial = false)
parts = path.sub(%r{^#{@removed_prefix}}, '').split('/')
fn = parts[-1].split('.')[0]
parts[-1] = partial ? "_#{fn}" : fn
parts.shift if parts[0].empty?
parts.join('/')
end
def resolve_template(template, context)
resolved = unqualified_path(template, true)
if !context.empty? && !resolved.include?('/')
resolved = "#{context}/#{resolved}"
end
resolved
end
def walk_inclusions(template, level = 0, &block)
yield template, level
@inclusions[template].each do |partial|
walk_inclusions(partial, level + 1, &block)
end
end
end
end
if __FILE__ == $0
views_root = ARGV[0] || 'app/views'
if File.directory?(views_root)
Tools::ViewStructure.show(views_root)
else
$stderr.puts "#{views_root} does not appear to be a directory."
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment