Class: Ucode::CodeChart::Writer

Inherits:
Object
  • Object
show all
Defined in:
lib/ucode/code_chart/writer.rb

Overview

Orchestrates extraction + provenance sidecar writing for one block. The Writer is the only thing that touches disk in the CodeChart namespace; everything else is composition.

Output layout (per block):

<output_root>/<block_id>/<U+XXXX>.svg
<output_root>/<block_id>/<U+XXXX>.json   # provenance sidecar

One folder per block keeps each block's output self-contained and discoverable — a downstream consumer (fontisan) can iterate a block's folder without scanning the whole tree.

Idempotent: re-running write on the same inputs produces byte-identical files (SVGs via content check; sidecars via Repo::AtomicWrites#write_atomic's canonical-JSON byte-equality). The Summary tally distinguishes "first run" writes from no-op re-writes.

Defined Under Namespace

Classes: Summary

Instance Method Summary collapse

Constructor Details

#initialize(output_root:, pdf_path:, ucd_version: nil, cache_dir: nil, now: nil, pillar3_source: nil, tier1_sources: nil, assigned_only: false, codepoints: nil, extractor: nil) ⇒ Writer

Returns a new instance of Writer.

Parameters:

  • output_root (Pathname, String)

    parent directory. The <block_id>/ subdirectory is created inside it.

  • pdf_path (Pathname, String)

    Code Charts PDF (already downloaded by the caller; Writer doesn't fetch).

  • ucd_version (String, nil) (defaults to: nil)

    UCD version to stamp on provenance. nil = resolved via VersionResolver.resolve(nil).

  • cache_dir (Pathname, String, nil) (defaults to: nil)

    font-stream cache directory for the EmbeddedFonts::PdfSource.

  • now (Time, nil) (defaults to: nil)

    timestamp override (for tests).

  • pillar3_source,

    tier1_sources, assigned_only, codepoints: forwarded to the Extractor.

  • extractor (Ucode::CodeChart::Extractor, nil) (defaults to: nil)

    pre-built Extractor instance. When nil (default), the Writer constructs one from the other parameters. Injecting lets callers (tests) bypass the mutool-dependent default Extractor.



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/ucode/code_chart/writer.rb', line 52

def initialize(output_root:, pdf_path:, ucd_version: nil,
               cache_dir: nil, now: nil,
               pillar3_source: nil, tier1_sources: nil,
               assigned_only: false, codepoints: nil,
               extractor: nil)
  @output_root = Pathname.new(output_root)
  @pdf_path = Pathname.new(pdf_path)
  @ucd_version = ucd_version || VersionResolver.resolve(nil)
  @cache_dir = cache_dir && Pathname.new(cache_dir)
  @now = now
  @pillar3_source = pillar3_source
  @tier1_sources = tier1_sources
  @assigned_only = assigned_only
  @codepoints = codepoints
  @extractor = extractor
end

Instance Method Details

#write(block) ⇒ Summary

Extracts every codepoint in block and writes <block_id>/<cp>.svg

  • <block_id>/<cp>.json under @output_root. Returns a Summary tally.

Parameters:

Returns:



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/ucode/code_chart/writer.rb', line 75

def write(block)
  block_dir = @output_root.join(block.id)
  block_dir.mkpath

  pdf_sha = Provenance.sha256_of(@pdf_path)

  sidecar = Sidecar.new(output_root: block_dir)
  extractor = @extractor || Extractor.new(
    block: block,
    pdf_path: @pdf_path,
    cache_dir: @cache_dir,
    pillar3_source: @pillar3_source,
    tier1_sources: @tier1_sources,
    assigned_only: @assigned_only,
    codepoints: @codepoints,
  )
  results = extractor.extract
  svgs = 0
  sidecars = 0
  results.each do |result|
    write_svg(block_dir, result)
    svgs += 1
    provenance = Provenance.build(
      block: block, codepoint: result.codepoint,
      ucd_version: @ucd_version, pdf_path: @pdf_path,
      pdf_sha: pdf_sha, now: @now,
      base_font: result.base_font, gid: result.gid,
      source_page: result.source_page, source_cell: result.source_cell,
    )
    sidecar.write(provenance)
    sidecars += 1
  end

  Summary.new(
    block: block.id,
    codepoints_extracted: results.size,
    svgs_written: svgs,
    sidecars_written: sidecars,
    pdf_sha256: pdf_sha,
  )
end