samhuri.net/lib/pressa/link_post.rb

61 lines
2 KiB
Ruby

require "pressa/drafts"
module Pressa
# Builds a fully-formed, ready-to-publish link post (front matter + body) from
# the handful of fields a phone Shortcut can collect. Pure: returns the target
# path and content; writing the file is the caller's job.
class LinkPost
class Error < StandardError; end
Result = Data.define(:filename, :target_path, :content)
def self.build(title:, link:, body: nil, tags: nil, author: Drafts.current_author, now: Time.now)
title = title.to_s.strip
raise Error, "title cannot be empty" if title.empty?
link = link.to_s.strip
raise Error, "link cannot be empty" if link.empty?
slug = Drafts.slugify(title)
raise Error, "title cannot be converted to a filename: #{title.inspect}" if slug.empty?
filename = "#{slug}.md"
target_path = "posts/#{now.strftime("%Y/%m")}/#{filename}"
content = render(title:, link:, body:, tags:, author:, now:)
Result.new(filename:, target_path:, content:)
end
def self.render(title:, link:, body:, tags:, author:, now:)
lines = [
"---",
"Title: #{yaml_quote(title)}",
"Author: #{author}",
"Date: #{yaml_quote(Drafts.ordinal_date(now))}",
"Timestamp: #{now.strftime("%Y-%m-%dT%H:%M:%S%:z")}"
]
tag_list = normalize_tags(tags)
lines << "Tags: #{tag_list.join(", ")}" unless tag_list.empty?
lines << "Link: #{link}"
lines << "---"
front_matter = lines.join("\n")
body = body.to_s.strip
body.empty? ? "#{front_matter}\n" : "#{front_matter}\n\n#{body}\n"
end
def self.normalize_tags(tags)
return [] if tags.nil?
list = tags.is_a?(Array) ? tags : tags.to_s.split(",")
list.map(&:strip).reject(&:empty?)
end
# YAML double-quoted scalar so titles with colons, quotes, or backslashes
# round-trip cleanly through the front-matter parser.
def self.yaml_quote(value)
escaped = value.gsub("\\", "\\\\\\\\").gsub('"', '\\"')
%("#{escaped}")
end
end
end