Merge pull request #1647 from middleman/frontmatter_delims

Frontmatter delims
This commit is contained in:
Thomas Reynolds 2015-11-11 13:20:15 -08:00
commit b4457c98d2
9 changed files with 54 additions and 18 deletions

View file

@ -28,13 +28,18 @@ Feature: YAML Front Matter
Then I should not see "layout: false" Then I should not see "layout: false"
Then I should not see "title: Pandoc likes trailing dots..." Then I should not see "title: Pandoc likes trailing dots..."
Scenario: Rendering Haml (yaml)
Given the Server is running at "frontmatter-app"
When I go to "/front-matter-haml.html"
Then I should see "<h1>This is the title</h1>"
Then I should not see "---"
Scenario: YAML not on first line, no encoding Scenario: YAML not on first line, no encoding
Given the Server is running at "frontmatter-app" Given the Server is running at "frontmatter-app"
When I go to "/front-matter-line-2.html" When I go to "/front-matter-line-2.html"
Then I should see "<h1></h1>" Then I should see "<h1></h1>"
Then I should see "---" Then I should see "---"
Scenario: YAML not on first line, with encoding Scenario: YAML not on first line, with encoding
Given the Server is running at "frontmatter-app" Given the Server is running at "frontmatter-app"
When I go to "/front-matter-encoding.html" When I go to "/front-matter-encoding.html"

View file

@ -0,0 +1 @@
config[:frontmatter_delims][:yaml] << %w(\\--- \\---)

View file

@ -0,0 +1,6 @@
\---
layout: false
title: This is the title
\---
%h1= current_page.data.title

View file

@ -15,7 +15,7 @@ class NeighborFrontmatter < ::Middleman::Extension
next unless file next unless file
fmdata = ::Middleman::Util::Data.parse(file[:full_path], :yaml).first fmdata = ::Middleman::Util::Data.parse(file[:full_path], app.config[:frontmatter_delims], :yaml).first
opts = fmdata.extract!(:layout, :layout_engine, :renderer_options, :directory_index, :content_type) opts = fmdata.extract!(:layout, :layout_engine, :renderer_options, :directory_index, :content_type)
opts[:renderer_options].symbolize_keys! if opts.key?(:renderer_options) opts[:renderer_options].symbolize_keys! if opts.key?(:renderer_options)
ignored = fmdata.delete(:ignored) ignored = fmdata.delete(:ignored)

View file

@ -26,7 +26,7 @@ class NeighborFrontmatter < ::Middleman::Extension
end end
def apply_neighbor_data(resource, file) def apply_neighbor_data(resource, file)
fmdata = ::Middleman::Util::Data.parse(file[:full_path], :yaml).first fmdata = ::Middleman::Util::Data.parse(file[:full_path], app.config[:frontmatter_delims], :yaml).first
opts = fmdata.extract!(:layout, :layout_engine, :renderer_options, :directory_index, :content_type) opts = fmdata.extract!(:layout, :layout_engine, :renderer_options, :directory_index, :content_type)
opts[:renderer_options].symbolize_keys! if opts.key?(:renderer_options) opts[:renderer_options].symbolize_keys! if opts.key?(:renderer_options)
ignored = fmdata.delete(:ignored) ignored = fmdata.delete(:ignored)

View file

@ -185,6 +185,12 @@ module Middleman
end end
}, 'Callbacks that can exclude paths from the sitemap' }, 'Callbacks that can exclude paths from the sitemap'
# Set textual delimiters that denote the start and end of frontmatter
define_setting :frontmatter_delims, {
json: [%w(;;; ;;;)],
yaml: [%w(--- ---), %w(--- ...)]
}, 'Allowed frontmatter delimiters'
define_setting :watcher_disable, false, 'If the Listen watcher should not run' define_setting :watcher_disable, false, 'If the Listen watcher should not run'
define_setting :watcher_force_polling, false, 'If the Listen watcher should run in polling mode' define_setting :watcher_force_polling, false, 'If the Listen watcher should run in polling mode'
define_setting :watcher_latency, nil, 'The Listen watcher latency' define_setting :watcher_latency, nil, 'The Listen watcher latency'

View file

@ -99,10 +99,10 @@ module Middleman
basename = File.basename(data_path, extension) basename = File.basename(data_path, extension)
if %w(.yaml .yml).include?(extension) if %w(.yaml .yml).include?(extension)
data, postscript = ::Middleman::Util::Data.parse(file[:full_path], :yaml) data, postscript = ::Middleman::Util::Data.parse(file[:full_path], @app.config[:frontmatter_delims], :yaml)
data[:postscript] = postscript if !postscript.nil? && data.is_a?(Hash) data[:postscript] = postscript if !postscript.nil? && data.is_a?(Hash)
elsif extension == '.json' elsif extension == '.json'
data, _postscript = ::Middleman::Util::Data.parse(file[:full_path], :json) data, _postscript = ::Middleman::Util::Data.parse(file[:full_path], @app.config[:frontmatter_delims], :json)
else else
return return
end end

View file

@ -65,7 +65,10 @@ module Middleman::CoreExtensions
return [{}, nil] unless file return [{}, nil] unless file
@cache[file[:full_path]] ||= ::Middleman::Util::Data.parse(file[:full_path]) @cache[file[:full_path]] ||= ::Middleman::Util::Data.parse(
file[:full_path],
app.config[:frontmatter_delims]
)
end end
Contract ArrayOf[IsA['Middleman::SourceFile']], ArrayOf[IsA['Middleman::SourceFile']] => Any Contract ArrayOf[IsA['Middleman::SourceFile']], ArrayOf[IsA['Middleman::SourceFile']] => Any

View file

@ -14,7 +14,7 @@ module Middleman::Util::Data
# @param [String] path # @param [String] path
# @return [Array<Hash, String>] # @return [Array<Hash, String>]
Contract Pathname, Maybe[Symbol] => [Hash, Maybe[String]] Contract Pathname, Maybe[Symbol] => [Hash, Maybe[String]]
def parse(full_path, known_type=nil) def parse(full_path, frontmatter_delims, known_type=nil)
return [{}, nil] if Middleman::Util.binary?(full_path) return [{}, nil] if Middleman::Util.binary?(full_path)
# Avoid weird race condition when a file is renamed # Avoid weird race condition when a file is renamed
@ -24,16 +24,22 @@ module Middleman::Util::Data
return [{}, nil] return [{}, nil]
end end
/ start_delims, stop_delims = frontmatter_delims
.values
.flatten(1)
.transpose
.map(&Regexp.method(:union))
match = /
\A(?:[^\r\n]*coding:[^\r\n]*\r?\n)? \A(?:[^\r\n]*coding:[^\r\n]*\r?\n)?
(?<start>---|;;;)[ ]*\r?\n (?<start>#{start_delims})[ ]*\r?\n
(?<frontmatter>.*?)[ ]*\r?\n? (?<frontmatter>.*?)[ ]*\r?\n?
^(?<stop>---|\.\.\.|;;;)[ ]*\r?\n? ^(?<stop>#{stop_delims})[ ]*\r?\n?
\r?\n? \r?\n?
(?<additional_content>.*) (?<additional_content>.*)
/mx =~ content /mx.match(content) || {}
unless frontmatter unless match[:frontmatter]
case known_type case known_type
when :yaml when :yaml
return [parse_yaml(content, full_path), nil] return [parse_yaml(content, full_path), nil]
@ -42,13 +48,22 @@ module Middleman::Util::Data
end end
end end
case [start, stop] case [match[:start], match[:stop]]
when %w(--- ---), %w(--- ...) when *frontmatter_delims[:yaml]
[parse_yaml(frontmatter, full_path), additional_content] [
when %w(;;; ;;;) parse_yaml(match[:frontmatter], full_path),
[parse_json("{#{frontmatter}}", full_path), additional_content] match[:additional_content]
]
when *frontmatter_delims[:json]
[
parse_json("{#{match[:frontmatter]}}", full_path),
match[:additional_content]
]
else else
[{}, content] [
{},
content
]
end end
end end