2012-01-08 02:21:26 +01:00
|
|
|
# Parsing YAML frontmatter
|
2011-06-06 20:39:57 +02:00
|
|
|
require "yaml"
|
2012-01-08 02:21:26 +01:00
|
|
|
|
|
|
|
# Looking up Tilt extensions
|
2011-06-06 20:39:57 +02:00
|
|
|
require "tilt"
|
|
|
|
|
2012-01-08 02:21:26 +01:00
|
|
|
# Frontmatter namespace
|
2012-05-07 23:41:39 +02:00
|
|
|
module Middleman
|
|
|
|
module CoreExtensions
|
|
|
|
module FrontMatter
|
2012-01-08 02:21:26 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
# Setup extension
|
|
|
|
class << self
|
2012-01-08 02:21:26 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
# Once registered
|
|
|
|
def registered(app)
|
|
|
|
app.set :frontmatter_extensions, %w(.htm .html .php)
|
|
|
|
app.extend ClassMethods
|
|
|
|
app.send :include, InstanceMethods
|
|
|
|
app.delegate :frontmatter_changed, :to => :"self.class"
|
2012-04-04 19:26:07 +02:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
::Middleman::Sitemap::Resource.send :include, ResourceInstanceMethods
|
|
|
|
end
|
|
|
|
alias :included :registered
|
|
|
|
end
|
2011-11-18 09:34:56 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
# Frontmatter class methods
|
|
|
|
module ClassMethods
|
2012-01-08 02:21:26 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
# Register callback on frontmatter updates
|
|
|
|
# @param [Regexp] matcher
|
|
|
|
# @return [Array<Array<Proc, Regexp>>]
|
|
|
|
def frontmatter_changed(matcher=nil, &block)
|
|
|
|
@_frontmatter_changed ||= []
|
|
|
|
@_frontmatter_changed << [block, matcher] if block_given?
|
|
|
|
@_frontmatter_changed
|
|
|
|
end
|
|
|
|
end
|
2011-12-04 20:58:45 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
module ResourceInstanceMethods
|
2012-04-04 19:26:07 +02:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
# This page's frontmatter
|
|
|
|
# @return [Hash]
|
|
|
|
def data
|
|
|
|
app.frontmatter(source_file).first
|
|
|
|
end
|
2012-04-04 19:26:07 +02:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
end
|
2012-04-04 19:26:07 +02:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
# Frontmatter instance methods
|
|
|
|
module InstanceMethods
|
2012-01-08 02:21:26 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
# Override init
|
|
|
|
def initialize
|
|
|
|
exts = frontmatter_extensions.join("|").gsub(".", "\.")
|
2011-12-29 00:29:19 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
static_path = source_dir.sub(root, "").sub(/^\//, "").sub(/\/$/, "") + "/"
|
2011-12-29 00:29:19 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
matcher = %r{#{static_path}.*(#{exts})}
|
2011-12-12 01:22:38 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
files.changed matcher do |file|
|
|
|
|
frontmatter_extension.touch_file(file)
|
|
|
|
end
|
2011-11-28 07:04:19 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
files.deleted matcher do |file|
|
|
|
|
frontmatter_extension.remove_file(file)
|
|
|
|
end
|
2011-11-28 07:04:19 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
sitemap.provides_metadata matcher do |path|
|
|
|
|
fmdata = if self.frontmatter_extension.has_data?(path)
|
|
|
|
self.frontmatter(path)[0]
|
|
|
|
else
|
|
|
|
{}
|
|
|
|
end
|
2011-11-28 07:04:19 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
data = {}
|
|
|
|
%w(layout layout_engine).each do |opt|
|
|
|
|
data[opt.to_sym] = fmdata[opt] if fmdata.has_key?(opt)
|
|
|
|
end
|
2011-11-28 07:04:19 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
{ :options => data, :page => fmdata }
|
|
|
|
end
|
2012-04-21 08:38:59 +02:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
# Initialize class
|
|
|
|
frontmatter_extension
|
2012-04-21 08:38:59 +02:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
super
|
|
|
|
end
|
2011-11-28 07:04:19 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
# Notify callbacks that the frontmatter changed
|
|
|
|
# @param [String] path
|
|
|
|
# @return [void]
|
|
|
|
def frontmatter_did_change(path)
|
|
|
|
frontmatter_changed.each do |callback, matcher|
|
|
|
|
next if path.match(%r{^#{build_dir}/})
|
|
|
|
next if !matcher.nil? && !path.match(matcher)
|
|
|
|
instance_exec(path, &callback)
|
|
|
|
end
|
|
|
|
end
|
2011-11-18 09:34:56 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
# Get the frontmatter object
|
|
|
|
# @return [Middleman::CoreExtensions::FrontMatter::FrontMatter]
|
|
|
|
def frontmatter_extension
|
|
|
|
@_frontmatter_extension ||= FrontMatter.new(self)
|
|
|
|
end
|
2011-12-26 20:24:33 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
# Get the frontmatter for a given path
|
|
|
|
# @param [String] path
|
|
|
|
# @return [Hash]
|
|
|
|
def frontmatter(path)
|
|
|
|
frontmatter_extension.data(path)
|
|
|
|
end
|
|
|
|
end
|
2011-11-10 21:26:20 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
# Core Frontmatter class
|
|
|
|
class FrontMatter
|
2012-01-08 02:21:26 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
# Initialize frontmatter with current app
|
|
|
|
# @param [Middleman::Application] app
|
|
|
|
def initialize(app)
|
|
|
|
@app = app
|
|
|
|
@source = File.expand_path(@app.source, @app.root)
|
|
|
|
@local_data = {}
|
2012-01-08 02:21:26 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
# Setup ignore callback
|
|
|
|
@app.ignore do |path|
|
|
|
|
if p = @app.sitemap.find_resource_by_path(path)
|
|
|
|
!p.proxy? && p.data && p.data["ignored"] == true
|
|
|
|
else
|
|
|
|
false
|
|
|
|
end
|
|
|
|
end
|
2012-01-08 02:21:26 +01:00
|
|
|
end
|
2011-11-10 21:26:20 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
# Whether the frontmatter knows about a path
|
|
|
|
# @param [String] path
|
|
|
|
# @return [Boolean]
|
|
|
|
def has_data?(path)
|
|
|
|
@local_data.has_key?(path.to_s)
|
|
|
|
end
|
2011-11-10 21:26:20 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
# Update frontmatter if a file changes
|
|
|
|
# @param [String] file
|
|
|
|
# @return [void]
|
|
|
|
def touch_file(file)
|
|
|
|
extension = File.extname(file).sub(/\./, "")
|
|
|
|
return unless ::Tilt.mappings.has_key?(extension)
|
2011-11-17 20:43:04 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
file = File.expand_path(file, @app.root)
|
|
|
|
content = File.read(file)
|
2011-11-17 20:43:04 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
result = parse_front_matter(content)
|
2011-11-10 21:26:20 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
if result
|
|
|
|
data, content = result
|
2012-04-21 08:38:59 +02:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
data = ::Middleman::Util.recursively_enhance(data).freeze
|
|
|
|
@local_data[file] = [data, content]
|
|
|
|
@app.cache.set([:raw_template, file], result[1])
|
|
|
|
@app.frontmatter_did_change(file)
|
|
|
|
end
|
|
|
|
end
|
2011-11-10 21:26:20 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
# Update frontmatter if a file is delted
|
|
|
|
# @param [String] file
|
|
|
|
# @return [void]
|
|
|
|
def remove_file(file)
|
|
|
|
file = File.expand_path(file, @app.root)
|
2011-11-17 20:43:04 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
if @local_data.has_key?(file)
|
|
|
|
@app.cache.remove(:raw_template, file)
|
|
|
|
@local_data.delete(file)
|
|
|
|
end
|
|
|
|
end
|
2011-07-14 02:48:31 +02:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
# Get the frontmatter for a given path
|
|
|
|
# @param [String] path
|
|
|
|
# @return [Hash]
|
|
|
|
def data(path)
|
|
|
|
if @local_data.has_key?(path.to_s)
|
|
|
|
@local_data[path.to_s]
|
|
|
|
else
|
|
|
|
[ ::Middleman::Util.recursively_enhance({}).freeze, nil ]
|
|
|
|
end
|
|
|
|
end
|
2011-11-10 21:26:20 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
private
|
|
|
|
# Parse frontmatter out of a string
|
|
|
|
# @param [String] content
|
|
|
|
# @return [Array<Hash, String>]
|
|
|
|
def parse_front_matter(content)
|
|
|
|
yaml_regex = /^(---\s*\n.*?\n?)^(---\s*$\n?)/m
|
|
|
|
if content =~ yaml_regex
|
|
|
|
content = content[($1.size + $2.size)..-1]
|
2012-02-12 19:10:59 +01:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
begin
|
|
|
|
data = YAML.load($1)
|
|
|
|
rescue => e
|
|
|
|
puts "YAML Exception: #{e.message}"
|
|
|
|
return false
|
|
|
|
end
|
2011-07-13 09:38:04 +02:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
else
|
|
|
|
return false
|
|
|
|
end
|
2011-07-14 02:48:31 +02:00
|
|
|
|
2012-05-07 23:41:39 +02:00
|
|
|
[data, content]
|
|
|
|
end
|
|
|
|
end
|
2011-06-06 20:39:57 +02:00
|
|
|
end
|
|
|
|
end
|
2011-12-01 07:06:00 +01:00
|
|
|
end
|