Class: Textus::Entry::Json
Overview
JSON entry storage. Top-level must be an object so we can carry _meta.
Class Method Summary collapse
- .enforce_name_match!(path, meta) ⇒ Object
- .extensions ⇒ Object
- .inject_uid(meta, content, existing_uid) ⇒ Object
- .nested_glob ⇒ Object
- .parse(raw, path: nil) ⇒ Object
-
.rewrite_name(path, basename) ⇒ Object
Mutating filesystem op; returns true if a write happened.
- .serialize(meta:, body:, content: nil) ⇒ Object
- .serialize_for_put(meta:, body:, content:, path:) ⇒ Object
- .validate_against(schema, parsed) ⇒ Object
- .validate_path_extension(path, nested) ⇒ Object
Class Method Details
.enforce_name_match!(path, meta) ⇒ Object
76 77 78 79 80 81 82 83 84 |
# File 'lib/textus/entry/json.rb', line 76 def self.enforce_name_match!(path, ) return unless .is_a?(Hash) && ["name"] ext = extensions.first basename = File.basename(path, ext) return if ["name"] == basename raise BadFrontmatter.new(path, "name '#{["name"]}' does not match basename '#{basename}'") end |
.extensions ⇒ Object
44 |
# File 'lib/textus/entry/json.rb', line 44 def self.extensions = [".json"] |
.inject_uid(meta, content, existing_uid) ⇒ Object
86 87 88 89 90 |
# File 'lib/textus/entry/json.rb', line 86 def self.inject_uid(, content, existing_uid) m = .is_a?(Hash) ? .dup : {} m["uid"] = existing_uid || Textus::Store.mint_uid unless m["uid"].is_a?(String) && !m["uid"].empty? [m, content] end |
.nested_glob ⇒ Object
46 |
# File 'lib/textus/entry/json.rb', line 46 def self.nested_glob = "**/*.json" |
.parse(raw, path: nil) ⇒ Object
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# File 'lib/textus/entry/json.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? begin parsed = ::JSON.parse(raw) rescue ::JSON::ParserError => e raise BadFrontmatter.new(path, "JSON parse failed: #{e.}") end raise BadFrontmatter.new(path, "JSON top-level must be an object") unless parsed.is_a?(Hash) = parsed["_meta"] fm = .is_a?(Hash) ? : {} = parsed.except("_meta") { "_meta" => fm, "body" => raw, "content" => } end |
.rewrite_name(path, basename) ⇒ Object
Mutating filesystem op; returns true if a write happened.
65 66 67 68 69 70 71 72 73 74 |
# File 'lib/textus/entry/json.rb', line 65 def self.rewrite_name(path, basename) # rubocop:disable Naming/PredicateMethod raw = File.binread(path) parsed = parse(raw, path: path) = parsed["_meta"] return false unless .is_a?(Hash) && ["name"].is_a?(String) && ["name"] != basename = .merge("name" => basename) File.binwrite(path, serialize(meta: , body: "", content: parsed["content"])) true end |
.serialize(meta:, body:, content: nil) ⇒ Object
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/textus/entry/json.rb', line 24 def self.serialize(meta:, body:, content: nil) if content.is_a?(Hash) # Re-inject _meta as the first key so on-disk shape is stable. on_disk = && !.empty? ? { "_meta" => }.merge(content) : content out = ::JSON.pretty_generate(on_disk) out += "\n" unless out.end_with?("\n") out elsif body && !body.to_s.empty? b = body.to_s b += "\n" unless b.end_with?("\n") b else raise UsageError.new("json serialize requires :content or :body") end end |
.serialize_for_put(meta:, body:, content:, path:) ⇒ Object
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/textus/entry/json.rb', line 48 def self.serialize_for_put(meta:, body:, content:, path:) raise UsageError.new("put for json requires content: or body:") if content.nil? && (body.nil? || body.to_s.empty?) if content.nil? begin parsed = parse(body.to_s, path: path) rescue BadFrontmatter => e raise BadContent.new(path, "bad_content: #{e.}") end [body.to_s, parsed["_meta"], body.to_s, parsed["content"]] else bytes = serialize(meta: , body: "", content: content) [bytes, , bytes, content] end end |
.validate_against(schema, parsed) ⇒ Object
40 41 42 |
# File 'lib/textus/entry/json.rb', line 40 def self.validate_against(schema, parsed) schema.validate!(parsed["content"] || {}) end |
.validate_path_extension(path, nested) ⇒ Object
92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/textus/entry/json.rb', line 92 def self.validate_path_extension(path, nested) ext = File.extname(path) if nested return if ext == "" raise UsageError.new("nested json path must not have an extension") end return if ext == ".json" raise UsageError.new("json format requires '.json' path (got #{ext.inspect})") end |