2015-06-17 00:30:37 +02:00
|
|
|
# Core Pathname library used for traversal
|
|
|
|
require 'pathname'
|
|
|
|
|
|
|
|
# DbC
|
|
|
|
require 'middleman-core/contracts'
|
|
|
|
|
|
|
|
# Shared util methods
|
|
|
|
require 'middleman-core/util'
|
|
|
|
|
|
|
|
# Parsing YAML data
|
|
|
|
require 'yaml'
|
|
|
|
|
|
|
|
# Parsing JSON data
|
2015-09-17 18:41:17 +02:00
|
|
|
require 'json'
|
2015-06-17 00:30:37 +02:00
|
|
|
|
|
|
|
module Middleman
|
|
|
|
module Util
|
2015-09-17 18:41:17 +02:00
|
|
|
module Data
|
2015-06-17 00:30:37 +02:00
|
|
|
include Contracts
|
|
|
|
|
|
|
|
module_function
|
|
|
|
|
|
|
|
# Get the frontmatter and plain content from a file
|
|
|
|
# @param [String] path
|
2015-08-13 00:24:35 +02:00
|
|
|
# @return [Array<Hash, String>]
|
2015-06-17 00:30:37 +02:00
|
|
|
Contract Pathname, Maybe[Symbol] => [Hash, Maybe[String]]
|
|
|
|
def parse(full_path, known_type=nil)
|
2015-09-19 16:53:12 +02:00
|
|
|
return [{}, nil] if Middleman::Util.binary?(full_path)
|
2015-06-17 00:30:37 +02:00
|
|
|
|
2015-09-19 16:53:12 +02:00
|
|
|
# Avoid weird race condition when a file is renamed
|
2015-06-17 00:30:37 +02:00
|
|
|
begin
|
2015-09-19 16:53:12 +02:00
|
|
|
content = File.read(full_path)
|
|
|
|
rescue EOFError, IOError, Errno::ENOENT
|
|
|
|
return [{}, nil]
|
2015-06-17 00:30:37 +02:00
|
|
|
end
|
|
|
|
|
2015-09-19 16:53:12 +02:00
|
|
|
case known_type
|
|
|
|
when :yaml
|
|
|
|
return [parse_yaml(content, full_path), nil]
|
|
|
|
when :json
|
|
|
|
return [parse_json(content, full_path), nil]
|
|
|
|
end
|
2015-06-17 00:30:37 +02:00
|
|
|
|
2015-09-19 16:53:12 +02:00
|
|
|
/
|
|
|
|
(?<start>^[-;]{3})[ ]*\r?\n
|
|
|
|
(?<frontmatter>.*?)[ ]*\r?\n
|
|
|
|
(?<stop>^[-.;]{3})[ ]*\r?\n?
|
|
|
|
(?<additional_content>.*)
|
|
|
|
/mx =~ content
|
2015-06-17 00:30:37 +02:00
|
|
|
|
2015-09-19 16:53:12 +02:00
|
|
|
return [{}, content] unless frontmatter
|
2015-06-17 00:30:37 +02:00
|
|
|
|
2015-09-19 16:53:12 +02:00
|
|
|
case [start, stop]
|
|
|
|
when %w[--- ---], %w[--- ...]
|
|
|
|
[parse_yaml(frontmatter, full_path), additional_content]
|
|
|
|
when %w[;;; ;;;]
|
|
|
|
[parse_json(frontmatter, full_path), additional_content]
|
2015-06-17 00:30:37 +02:00
|
|
|
else
|
2015-09-19 16:53:12 +02:00
|
|
|
[{}, content]
|
2015-06-17 00:30:37 +02:00
|
|
|
end
|
2015-09-19 16:53:12 +02:00
|
|
|
end
|
2015-06-17 00:30:37 +02:00
|
|
|
|
2015-09-19 16:53:12 +02:00
|
|
|
# Parse YAML frontmatter out of a string
|
|
|
|
# @param [String] content
|
|
|
|
# @return [Array<Hash, String>]
|
|
|
|
Contract String, Pathname, Bool => Hash
|
|
|
|
def parse_yaml(content, full_path)
|
|
|
|
map_value(YAML.load(content))
|
|
|
|
rescue StandardError, Psych::SyntaxError => error
|
|
|
|
warn "YAML Exception parsing #{full_path}: #{error.message}"
|
|
|
|
{}
|
2015-06-17 00:30:37 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
# Parse JSON frontmatter out of a string
|
|
|
|
# @param [String] content
|
|
|
|
# @return [Array<Hash, String>]
|
2015-09-19 16:53:12 +02:00
|
|
|
Contract String, Pathname => Hash
|
2015-06-17 00:30:37 +02:00
|
|
|
def parse_json(content, full_path)
|
2015-09-19 16:53:12 +02:00
|
|
|
map_value(JSON.parse(content))
|
|
|
|
rescue StandardError => error
|
|
|
|
warn "JSON Exception parsing #{full_path}: #{error.message}"
|
|
|
|
{}
|
2015-06-17 00:30:37 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
def symbolize_recursive(hash)
|
|
|
|
{}.tap do |h|
|
|
|
|
hash.each { |key, value| h[key.to_sym] = map_value(value) }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def map_value(thing)
|
|
|
|
case thing
|
|
|
|
when Hash
|
|
|
|
symbolize_recursive(thing)
|
|
|
|
when Array
|
|
|
|
thing.map { |v| map_value(v) }
|
|
|
|
else
|
|
|
|
thing
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|