2015-06-17 00:30:37 +02:00
|
|
|
require 'yaml'
|
2015-09-17 18:41:17 +02:00
|
|
|
require 'json'
|
2015-09-20 14:23:47 +02:00
|
|
|
require 'pathname'
|
|
|
|
require 'middleman-core/util'
|
|
|
|
require 'middleman-core/contracts'
|
2015-06-17 00:30:37 +02:00
|
|
|
|
2015-09-20 14:23:47 +02:00
|
|
|
module Middleman::Util::Data
|
|
|
|
include Contracts
|
2015-06-17 00:30:37 +02:00
|
|
|
|
2015-09-20 14:23:47 +02:00
|
|
|
module_function
|
2015-06-17 00:30:37 +02:00
|
|
|
|
2015-09-20 14:23:47 +02:00
|
|
|
# Get the frontmatter and plain content from a file
|
|
|
|
# @param [String] path
|
|
|
|
# @return [Array<Hash, String>]
|
|
|
|
Contract Pathname, Maybe[Symbol] => [Hash, Maybe[String]]
|
|
|
|
def parse(full_path, known_type=nil)
|
|
|
|
return [{}, nil] if Middleman::Util.binary?(full_path)
|
2015-06-17 00:30:37 +02:00
|
|
|
|
2015-09-20 14:23:47 +02:00
|
|
|
# Avoid weird race condition when a file is renamed
|
|
|
|
begin
|
|
|
|
content = File.read(full_path)
|
|
|
|
rescue EOFError, IOError, Errno::ENOENT
|
|
|
|
return [{}, nil]
|
|
|
|
end
|
2015-06-17 00:30:37 +02:00
|
|
|
|
2015-09-20 14:23:47 +02:00
|
|
|
/
|
2015-09-23 22:06:11 +02:00
|
|
|
\A(.*?coding:.*?\n)?
|
|
|
|
(?<start>[-;]{3})[ ]*\r?\n
|
|
|
|
(?<frontmatter>.*?)[ ]*\r?\n?
|
2015-09-24 00:40:42 +02:00
|
|
|
(?<stop>^[-.;]{3})[ ]*\r?\n?
|
2015-09-20 14:23:47 +02:00
|
|
|
(?<additional_content>.*)
|
|
|
|
/mx =~ content
|
|
|
|
|
2015-09-23 22:06:11 +02:00
|
|
|
unless frontmatter
|
|
|
|
case known_type
|
|
|
|
when :yaml
|
|
|
|
return [parse_yaml(content, full_path), nil]
|
|
|
|
when :json
|
|
|
|
return [parse_json(content, full_path), nil]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-09-20 14:23:47 +02:00
|
|
|
case [start, stop]
|
|
|
|
when %w[--- ---], %w[--- ...]
|
|
|
|
[parse_yaml(frontmatter, full_path), additional_content]
|
|
|
|
when %w[;;; ;;;]
|
|
|
|
[parse_json(frontmatter, full_path), additional_content]
|
|
|
|
else
|
|
|
|
[{}, content]
|
|
|
|
end
|
|
|
|
end
|
2015-06-17 00:30:37 +02:00
|
|
|
|
2015-09-20 14:23:47 +02:00
|
|
|
# Parse YAML frontmatter out of a string
|
|
|
|
# @param [String] content
|
2015-09-23 22:06:11 +02:00
|
|
|
# @return [Hash]
|
2015-09-20 14:23:47 +02:00
|
|
|
Contract String, Pathname, Bool => Hash
|
|
|
|
def parse_yaml(content, full_path)
|
2015-09-23 22:06:11 +02:00
|
|
|
symbolize_recursive(YAML.load(content) || {})
|
2015-09-20 14:23:47 +02:00
|
|
|
rescue StandardError, Psych::SyntaxError => error
|
|
|
|
warn "YAML Exception parsing #{full_path}: #{error.message}"
|
|
|
|
{}
|
|
|
|
end
|
2015-06-17 00:30:37 +02:00
|
|
|
|
2015-09-20 14:23:47 +02:00
|
|
|
# Parse JSON frontmatter out of a string
|
|
|
|
# @param [String] content
|
2015-09-23 22:06:11 +02:00
|
|
|
# @return [Hash]
|
2015-09-20 14:23:47 +02:00
|
|
|
Contract String, Pathname => Hash
|
|
|
|
def parse_json(content, full_path)
|
2015-09-23 22:06:11 +02:00
|
|
|
symbolize_recursive(JSON.parse(content) || {})
|
2015-09-20 14:23:47 +02:00
|
|
|
rescue StandardError => error
|
|
|
|
warn "JSON Exception parsing #{full_path}: #{error.message}"
|
|
|
|
{}
|
|
|
|
end
|
2015-06-17 00:30:37 +02:00
|
|
|
|
2015-09-20 14:23:47 +02:00
|
|
|
def symbolize_recursive(value)
|
|
|
|
case value
|
|
|
|
when Hash
|
|
|
|
value.map { |k, v| [k.to_sym, symbolize_recursive(v)] }.to_h
|
|
|
|
when Array
|
|
|
|
value.map { |v| symbolize_recursive(v) }
|
|
|
|
else
|
|
|
|
value
|
2015-06-17 00:30:37 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|