Class: Ucode::CodeChart::Provenance
- Inherits:
-
Lutaml::Model::Serializable
- Object
- Lutaml::Model::Serializable
- Ucode::CodeChart::Provenance
- Defined in:
- lib/ucode/code_chart/provenance.rb
Overview
Per-codepoint provenance value object — every field the REQ (R6) requires in the sidecar JSON next to each extracted SVG.
The single source of truth for the sidecar schema: a
lutaml-model class with an explicit key_value mapping block.
Adding a field = one attribute declaration + one map line
in the mapping block. The Sidecar writer calls to_hash
(framework-provided); no hand-rolled to_h anywhere.
extractor_version reads from Ucode::VERSION at construction
so the field stays in sync with the gem's version bump — single
source of truth.
extracted_at is the extraction event timestamp (UTC ISO8601),
not the file-write timestamp.
Class Method Summary collapse
-
.build(block:, codepoint:, ucd_version:, pdf_path:, pdf_sha: nil, now: nil, base_font: nil, gid: nil, source_page: nil, source_cell: nil) ⇒ Provenance
Builds a Provenance from the inputs the Writer has on hand (block, codepoint, ucd_version, pdf_path).
-
.code_chart_url(block_first_cp) ⇒ String
Computes the source PDF's URL from a block name and first codepoint.
-
.sha256_of(path) ⇒ String
Hex digest, "" when the path doesn't exist (callers can decide how to handle a missing hash).
Class Method Details
.build(block:, codepoint:, ucd_version:, pdf_path:, pdf_sha: nil, now: nil, base_font: nil, gid: nil, source_page: nil, source_cell: nil) ⇒ Provenance
Builds a Provenance from the inputs the Writer has on hand
(block, codepoint, ucd_version, pdf_path). Computes the PDF
hash + URL once. The extracted_at timestamp is fixed at
call time so re-running the same block produces identical
provenance JSON for unchanged codepoints.
The optional base_font, gid, source_page, source_cell
come from the Extractor::Result when available. Nil values
are emitted as JSON null — preserves the audit trail's
honesty about what the extractor actually knew.
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/ucode/code_chart/provenance.rb', line 93 def self.build(block:, codepoint:, ucd_version:, pdf_path:, pdf_sha: nil, now: nil, base_font: nil, gid: nil, source_page: nil, source_cell: nil) path = Pathname.new(pdf_path) new( codepoint: format("U+%04X", codepoint), block: block.id, source_pdf_url: code_chart_url(block.range_first), source_pdf_sha256: pdf_sha || sha256_of(path), ucd_version: ucd_version, extracted_at: (now || Time.now.utc).iso8601, extractor_version: Ucode::VERSION, base_font: base_font, gid: gid, source_page: source_page, source_cell: source_cell, ) end |
.code_chart_url(block_first_cp) ⇒ String
Computes the source PDF's URL from a block name and first
codepoint. Mirrors the per-block URL convention in
Fetch::CodeCharts: the hex representation of the
codepoint, zero-padded to a minimum of 4 digits (e.g.
U0000.pdf for BMP, U10920.pdf for Plane 1,
U100000.pdf for Plane 16 SPUA-B).
62 63 64 65 |
# File 'lib/ucode/code_chart/provenance.rb', line 62 def self.code_chart_url(block_first_cp) slug = block_first_cp.to_s(16).upcase.rjust(4, "0") "#{Ucode.configuration.charts_base_url}/U#{slug}.pdf" end |
.sha256_of(path) ⇒ String
Returns hex digest, "" when the path doesn't exist (callers can decide how to handle a missing hash).
116 117 118 119 120 |
# File 'lib/ucode/code_chart/provenance.rb', line 116 def self.sha256_of(path) return "" unless path.exist? Digest::SHA256.file(path).hexdigest end |