samhuri.net/lib/pressa/drafts.rb
Sami Samhuri fc68fc58af Extract bake logic into lib/pressa and fold tasks back into one bake.rb
Pull the pure, testable logic out of the bake tasks into Pressa modules:

- Pressa::Drafts — slugs, ordinal dates, draft paths, and the new-draft template
- Pressa::Coverage — the coverage measurement script, output parsing, and baseline-ref resolution
- Pressa::Publish — the rsync command builder

Each gets its own tests, so this logic now sits under the lib/ coverage gate
instead of being untested glue inside the task files.

With the logic extracted, the namespaced bake/ split no longer earns its keep —
those files were mostly thin task declarations. Collapse build/draft/publish/quality
back into a single bake.rb with the original flat task names (new_draft, coverage,
publish_beta, and so on) and update CI and AGENTS.md to match.
2026-06-07 17:57:01 -07:00

90 lines
2.1 KiB
Ruby

require "etc"
module Pressa
# Draft authoring logic: slugs, paths, ordinal dates, and the new-draft template.
# File mutation (writing, moving, date rewriting) stays in the bake tasks that call this.
class Drafts
class Error < StandardError; end
DEFAULT_DIR = "public/drafts".freeze
def self.slugify(title)
title.downcase
.gsub(/[^a-z0-9\s-]/, "")
.gsub(/\s+/, "-").squeeze("-")
.gsub(/^-|-$/, "")
end
def self.ordinal_date(time)
day = time.day
suffix = case day
when 1, 21, 31
"st"
when 2, 22
"nd"
when 3, 23
"rd"
else
"th"
end
time.strftime("#{day}#{suffix} %B, %Y")
end
def self.current_author
Etc.getlogin || ENV["USER"] || `whoami`.strip
rescue
ENV["USER"] || `whoami`.strip
end
def initialize(dir: DEFAULT_DIR, exists: ->(path) { File.exist?(path) })
@dir = dir
@exists = exists
end
def path(filename)
File.join(@dir, filename)
end
def next_available(base_filename = "untitled.md")
return base_filename unless @exists.call(path(base_filename))
name_without_ext = File.basename(base_filename, ".md")
counter = 1
loop do
numbered_filename = "#{name_without_ext}-#{counter}.md"
return numbered_filename unless @exists.call(path(numbered_filename))
counter += 1
end
end
def resolve_input(input_path)
if input_path.include?("/")
if input_path.start_with?("posts/")
raise Error, "'#{input_path}' is already published in posts/ directory"
end
[input_path, File.basename(input_path)]
else
[path(input_path), input_path]
end
end
def render_template(title, author: self.class.current_author, now: Time.now)
<<~FRONTMATTER
---
Author: #{author}
Title: #{title}
Date: unpublished
Timestamp: #{now.strftime("%Y-%m-%dT%H:%M:%S%:z")}
Tags:
---
# #{title}
TKTK
FRONTMATTER
end
end
end