Class: Textus::Entry::Markdown

Inherits:
Base
  • Object
show all
Defined in:
lib/textus/entry/markdown.rb

Overview

Markdown with YAML frontmatter. Original Entry implementation.

Class Method Summary collapse

Methods inherited from Base

validate_against

Class Method Details

.enforce_name_match!(path, meta) ⇒ Object

Raises:



61
62
63
64
65
66
67
68
69
# File 'lib/textus/entry/markdown.rb', line 61

def self.enforce_name_match!(path, meta)
  return unless meta.is_a?(Hash) && meta["name"]

  ext = extensions.first
  basename = File.basename(path, ext)
  return if meta["name"] == basename

  raise BadFrontmatter.new(path, "name '#{meta["name"]}' does not match basename '#{basename}'")
end

.extensionsObject



36
# File 'lib/textus/entry/markdown.rb', line 36

def self.extensions = [".md"]

.inject_uid(meta, content, existing_uid) ⇒ Object



71
72
73
74
75
# File 'lib/textus/entry/markdown.rb', line 71

def self.inject_uid(meta, content, existing_uid)
  m = meta.is_a?(Hash) ? meta.dup : {}
  m["uid"] = existing_uid || Textus::Store.mint_uid unless m["uid"].is_a?(String) && !m["uid"].empty?
  [m, content]
end

.nested_globObject



38
# File 'lib/textus/entry/markdown.rb', line 38

def self.nested_glob = "**/*.md"

.parse(raw, path: nil) ⇒ Object

Raises:



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/textus/entry/markdown.rb', line 7

def self.parse(raw, path: nil)
  raw = raw.dup.force_encoding(Encoding::UTF_8)
  raise BadFrontmatter.new(path, "entry is not valid UTF-8") unless raw.valid_encoding?
  return { "_meta" => {}, "body" => raw, "content" => nil } unless raw.start_with?("---\n") || raw.start_with?("---\r\n")

  lines = raw.split(/\r?\n/, -1)
  close_idx = lines[1..].index("---")
  raise BadFrontmatter.new(path, "frontmatter not terminated") unless close_idx

  close_idx += 1
  fm_yaml = lines[1...close_idx].join("\n")
  body = lines[(close_idx + 1)..].join("\n")
  begin
    fm = fm_yaml.strip.empty? ? {} : ::YAML.safe_load(fm_yaml, permitted_classes: [Date, Time], aliases: false)
  rescue Psych::SyntaxError => e
    raise BadFrontmatter.new(path, "YAML parse failed: #{e.message}")
  end
  fm = {} unless fm.is_a?(Hash)
  { "_meta" => fm, "body" => body, "content" => nil }
end

.rewrite_name(path, basename) ⇒ Object

Mutating filesystem op; returns true if a write happened (boolean is informational, not a predicate). Rubocop’s predicate-name heuristic disabled here on purpose.



50
51
52
53
54
55
56
57
58
59
# File 'lib/textus/entry/markdown.rb', line 50

def self.rewrite_name(path, basename) # rubocop:disable Naming/PredicateMethod
  raw = File.binread(path)
  parsed = parse(raw, path: path)
  meta = parsed["_meta"] || {}
  return false unless meta.is_a?(Hash) && meta["name"].is_a?(String) && meta["name"] != basename

  new_meta = meta.merge("name" => basename)
  File.binwrite(path, serialize(meta: new_meta, body: parsed["body"]))
  true
end

.serialize(meta:, body:, content: nil) ⇒ Object



28
29
30
31
32
33
34
# File 'lib/textus/entry/markdown.rb', line 28

def self.serialize(meta:, body:, content: nil)
  _ = content # markdown ignores content
  fm_yaml = meta.empty? ? "" : ::YAML.dump(meta).sub(/\A---\n/, "")
  body = body.to_s
  body += "\n" unless body.empty? || body.end_with?("\n")
  "---\n#{fm_yaml}---\n#{body}"
end

.serialize_for_put(meta:, body:, content:, path:) ⇒ Object



40
41
42
43
44
45
# File 'lib/textus/entry/markdown.rb', line 40

def self.serialize_for_put(meta:, body:, content:, path:)
  _ = path
  _ = content
  bytes = serialize(meta: meta || {}, body: body.to_s)
  [bytes, meta, body.to_s, nil]
end

.validate_path_extension(path, _nested) ⇒ Object

Raises:



77
78
79
80
81
82
# File 'lib/textus/entry/markdown.rb', line 77

def self.validate_path_extension(path, _nested)
  ext = File.extname(path)
  return if ["", ".md"].include?(ext)

  raise UsageError.new("markdown format requires '.md' path (got #{ext.inspect})")
end