Add frontmatter parser helper

This commit is contained in:
Max Wofford 2025-05-27 12:20:09 -04:00
parent a462a374f4
commit ab566301e1
3 changed files with 55 additions and 22 deletions

View file

@ -1,4 +1,6 @@
class ProjectsController < ApplicationController
include HasFrontmatter
def index
@projects = Project.all
@ -56,16 +58,6 @@ class ProjectsController < ApplicationController
}
end
def parse_frontmatter(content)
if content =~ /\A(---\s*\n.*?\n?)^(---\s*$\n?)/m
metadata = YAML.safe_load($1)
content = content[$2.size..-1]
[ metadata, content ]
else
[ {}, content ]
end
end
def render_not_found
render file: "#{Rails.root}/public/404.html", status: :not_found
end

View file

@ -0,0 +1,51 @@
module HasFrontmatter
extend ActiveSupport::Concern
class_methods do
def parse_frontmatter(content)
if content =~ /\A(---\s*\n.*?\n?)^(---\s*$\n?)(.*)/m
begin
metadata = YAML.safe_load($1)
metadata = {} unless metadata.is_a?(Hash)
rescue Psych::SyntaxError, StandardError => e
Rails.logger.warn "Failed to parse frontmatter: #{e.message}"
metadata = {}
end
content = $3
[ safe_parse_metadata(metadata), content ]
else
[ {}, content ]
end
end
private
def safe_parse_metadata(metadata)
{
"title" => safe_parse_field(metadata, "title"),
"author" => safe_parse_field(metadata, "author"),
"description" => safe_parse_field(metadata, "description"),
"created_at" => safe_parse_date(metadata, "created_at")
}
end
def safe_parse_field(metadata, field)
return nil unless metadata.is_a?(Hash)
value = metadata[field]
return nil if value.nil?
value.to_s.strip
end
def safe_parse_date(metadata, field)
return nil unless metadata.is_a?(Hash)
value = metadata[field]
return nil if value.nil?
begin
Date.parse(value.to_s)
rescue Date::Error
nil
end
end
end
end

View file

@ -1,5 +1,6 @@
class Project
include MarkdownRenderable
include HasFrontmatter
attr_reader :user, :project_name, :title, :author, :description, :created_at, :content
def initialize(attributes = {})
@ -35,6 +36,7 @@ class Project
def created_at_date
return nil unless created_at
return created_at if created_at.is_a?(Date)
Date.parse(created_at)
rescue Date::Error
nil
@ -128,16 +130,4 @@ class Project
content: render_markdown(markdown_content)
)
end
private
def self.parse_frontmatter(content)
if content =~ /\A(---\s*\n.*?\n?)^(---\s*$\n?)(.*)/m
metadata = YAML.safe_load($1)
content = $3
[ metadata, content ]
else
[ {}, content ]
end
end
end