Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
207 lines (163 sloc) 5.8 KB
module Hardwired
class Index
class << self
@cache = {}
@loaded = false
def cache
@cache ||= {}
end
def loaded
@loaded
end
def load_all
return if loaded
## Find all files with Tilt-registered extensions in every mounted folder
mounted_folders.each_pair do |k,v|
file_pattern = File.join(k, "**", "*.{#{Tilt.mappings.keys.join(',')}}")
Dir.glob(file_pattern).map do |path|
#skip static files
next if path =~ /\.static./i
ext = File.extname(path)
next if ext.nil? || !Tilt[ext[1..-1]]
_ = load_physical(path)
end
end
@loaded = true ##So other threads know when we're done
end
def load_physical(fname, virtual_path = nil)
fname = fname.to_s
return if !File.file?(fname) #Skip directories
url = virtual_path ? ('/' + virtual_path.to_s.sub(/\A\/+/,"")) : virtual_path_for(fname)
begin
#Prevent conflicts
if !cache[url].nil?
other_name = cache[url].filename
raise "Conflicting files #{fname} and #{other_name} share the same url #{url}! Filenames must be unique. #{cache[url].inspect}" if other_name != fname
end
#We must check that this file hasn't already been cached - multiple threads call cache_all simultaneously
if cache[url].nil? || File.mtime(fname) != cache[url].last_modified
cache[url] = Template.load(fname,url)
end
rescue Errno::ENOENT
cache[url] = nil
end
cache[url]
end
def add_common_file(name, virtual_path)
physical_path = Paths.common_path(name)
if !File.file?(physical_path)
Dir.glob("#{physical_path}.{#{Tilt.mappings.keys.join(',')}}").map do |path|
ext = File.extname(path)
next if ext.nil? || !Tilt[ext[1..-1]]
physical_path = path
break
end
end
load_physical(physical_path, virtual_path)
end
def [](path)
load_all
return cache['/' + path.to_s.sub(/\A\/+/,"")]
end
#Searches for the template in multiple folders
#Order (if no leading slash): 1. current_path, 2. root, 3. _layout and other search_paths
#Order (if shortname has leading slash): 1. root
def find(shortname, current_path = nil)
#Return nil if we were provided it
return nil if shortname.nil?
#Support symbols
s = shortname.to_s
#If it starts with a slash, we only search in the root.
return self[s] if s[0] == '/'
#Search in current_path, root, and search paths (includes _layout)
search_these = [current_path, nil, search_paths].flatten
#p "Looking for #{s} in #{search_these.join(', ')}"
search_these.each { |path|
p = path ? Paths.join(path,s) : s
return self[p] if self[p]
}
nil
end
def search_paths
@search_paths ||= [Paths.layout_subfolder]
end
def add_search_path(path)
search_paths << path
end
#Enumerates all indexed files
def files(&block)
load_all
Enumerator.new do |y|
cache.each do |k,v|
y << v
end
end.each(&block)
end
#Enumerates all indexed files, but requires a filtering block
def enum_files
load_all
Enumerator.new do |y|
cache.each do |k,v|
y << v if yield(v)
end
end
end
def pages
@cached_pages ||= enum_files { |p| p.is_page? && p.can_render? }.to_a
end
def posts
@cached_posts ||= enum_files { |p| p.is_page? && p.can_render? && p.is_post? }.sort { |x, y| y.date <=> x.date }
end
def page_tags
pages.map{ |p| p.tags }.flatten.uniq
end
def post_tags
posts.map{ |p| p.tags }.flatten.uniq
end
def pages_tagged(tag)
pages.select { |p| p.tag?(tag)}
end
def posts_tagged(tag)
posts.select { |p| p.tag?(tag)}
end
def mounted_folders
@mounted_folders ||= {Hardwired::Paths.content_path => "/"}
end
#Useful for getting the 'virtual' working directory for a template, for located partials or layouts
def virtual_parent_dir_for(fname, raise_if_outside=true)
path = make_almost_virtual(fname, true, raise_if_outside)
return nil if path.nil?
path.sub(/\/[^\/]+\Z/m,'')
end
#Get the virtual path for any filename within a mounted folder
def virtual_path_for(fname, raise_if_outside=true)
## Reduce "/index" to "/" if present
path = make_almost_virtual(fname,true, raise_if_outside)
return nil if path.nil?
path.sub!(/\/index\Z/im,"/")
(path.length > 1 && path[-1] == ?/) ? path[0..-2] : path
end
def is_outside?(fname)
make_almost_virtual(fname, true, false).nil?
end
def make_almost_virtual(fname, remove_extension=true, raise_if_outside=true)
fname = fname.to_s
mounted_folders.each_pair { |k,v|
if fname.start_with?(k)
#Replace physical portion with 'mount folder'
p = v.gsub(/\/+\Z/m,'') + "/" + fname[k.length..-1].gsub(/\A\/+/m,'')
#Strip extension
if remove_extension
ext = File.extname(p).downcase[1..-1];
p = p[0..-(ext.length + 2)] unless ext.nil? or ext.empty?
end
# Strip leading, trailing slashes, then restore leading slash
return '/' + p.gsub(/^\/+|\/+$/m,"")
end
}
raise "No root directory matches '#{fname}'" if raise_if_outside
nil
end
end
end
end