Class: Fontico::Lockfile

Inherits:
Object
  • Object
show all
Defined in:
lib/fontico/lockfile.rb

Overview

icons.lock pins two things that must never drift:

codepoints 

Constant Summary collapse

PUA_START =
0xE001
FORMAT =
1

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path) ⇒ Lockfile

Returns a new instance of Lockfile.



24
25
26
27
28
29
30
# File 'lib/fontico/lockfile.rb', line 24

def initialize(path)
  @path = path
  data = File.exist?(path) ? (YAML.safe_load_file(path) || {}) : {}
  @codepoints = data["codepoints"] || {}
  @retired    = data["retired"]    || {}
  @entries    = data["icons"]      || {}
end

Instance Attribute Details

#path ⇒ Object (readonly)

Returns the value of attribute path.



22
23
24
# File 'lib/fontico/lockfile.rb', line 22

def path
  @path
end

Instance Method Details

#allocate(name) ⇒ Object

Append-only reservation. store is the production caller; tests use it to pin order without going through a full build.



38
39
40
# File 'lib/fontico/lockfile.rb', line 38

def allocate(name)
  @codepoints[name] ||= next_free
end

#body(name) ⇒ Object



68
# File 'lib/fontico/lockfile.rb', line 68

def body(name) = entry(name)&.fetch("body", nil)

#codepoint_for(name) ⇒ Object

Lookup only. A missing name is nil — callers that draw a glyph must not invent a codepoint, or a typo silently becomes a .notdef.



34
# File 'lib/fontico/lockfile.rb', line 34

def codepoint_for(name) = @codepoints[name]

#entry(name) ⇒ Object



42
# File 'lib/fontico/lockfile.rb', line 42

def entry(name) = @entries[name]

#fresh?(name, source) ⇒ Boolean

Returns:

  • (Boolean)


64
65
66
# File 'lib/fontico/lockfile.rb', line 64

def fresh?(name, source)
  entry(name)&.fetch("source", nil) == source && entry(name)["body"]
end

#multicolor?(name) ⇒ Boolean

Returns:

  • (Boolean)


69
# File 'lib/fontico/lockfile.rb', line 69

def multicolor?(name) = !!entry(name)&.fetch("multicolor", false)

#retire_missing!(names) ⇒ Object

Names present in the lock but absent from the manifest keep their codepoint reserved so it is never handed to a different icon.



57
58
59
60
61
62
# File 'lib/fontico/lockfile.rb', line 57

def retire_missing!(names)
  (@codepoints.keys - names).each do |gone|
    @retired[gone] = @codepoints.delete(gone)
    @entries.delete(gone)
  end
end

#save! ⇒ Object



75
76
77
78
79
80
81
82
# File 'lib/fontico/lockfile.rb', line 75

def save!
  File.write(@path, {
    "format"     => FORMAT,
    "codepoints" => @codepoints.sort.to_h,
    "retired"    => @retired.sort.to_h,
    "icons"      => @entries.sort.to_h
  }.to_yaml)
end

#store(name, source:, body:, multicolor: false, warnings: []) ⇒ Object



44
45
46
47
48
49
50
51
52
53
# File 'lib/fontico/lockfile.rb', line 44

def store(name, source:, body:, multicolor: false, warnings: [])
  @entries[name] = {
    "source"     => source,
    "digest"     => Digest::SHA256.hexdigest(body)[0, 16],
    "multicolor" => multicolor,
    "warnings"   => warnings,
    "body"       => body
  }
  allocate(name)
end

#warnings(name) ⇒ Object

Replayed on cached builds so a hard failure keeps being reported until the source file is actually fixed.



73
# File 'lib/fontico/lockfile.rb', line 73

def warnings(name) = entry(name)&.fetch("warnings", nil) || []