fontist 3.0.30 → 3.0.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/fontist.gemspec +2 -2
- data/lib/fontist/font_file.rb +79 -1
- data/lib/fontist/import/macos_importer.rb +0 -1
- data/lib/fontist/import/sil_importer.rb +3 -3
- data/lib/fontist/system_index.rb +39 -0
- data/lib/fontist/version.rb +1 -1
- metadata +7 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ccd5b693c5cc7ffa551f7a24c4e1366cee390bba84c2cdd2969fda96fdb8798d
|
|
4
|
+
data.tar.gz: 493d3d3683bf368eaa553602084c8a457ddcb911d3e73be0308423263a176a2a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2d13031416210a2c8996623593c27c93bb963dac09b108c55a6a80833262c664c7e478a8e8eb316f69963e73b77c2295790da77e8bad07289ca24ab1865371be
|
|
7
|
+
data.tar.gz: f2e34e0d2946338a0a2ab047ab48dbe5e5701899c2ed2731867d3389fcbc1caa0f92107ba8a8a992db2b74a78920f4b8105f8191d5636e1ec4b2a88952e80bc5
|
data/fontist.gemspec
CHANGED
|
@@ -36,9 +36,9 @@ Gem::Specification.new do |spec|
|
|
|
36
36
|
spec.add_dependency "fontisan", "~> 0.4", ">= 0.4.47"
|
|
37
37
|
spec.add_dependency "fuzzy_match", "~> 2.1"
|
|
38
38
|
spec.add_dependency "git", "~> 6.0"
|
|
39
|
-
spec.add_dependency "lutaml-model", "~> 0.8.
|
|
39
|
+
spec.add_dependency "lutaml-model", "~> 0.8.162"
|
|
40
40
|
spec.add_dependency "marcel", "~> 1.0"
|
|
41
|
-
spec.add_dependency "
|
|
41
|
+
spec.add_dependency "moxml", "~> 0.6"
|
|
42
42
|
spec.add_dependency "octokit", "~> 10.0"
|
|
43
43
|
spec.add_dependency "paint", "~> 2.3"
|
|
44
44
|
spec.add_dependency "parallel", "~> 1.24"
|
data/lib/fontist/font_file.rb
CHANGED
|
@@ -63,14 +63,30 @@ module Fontist
|
|
|
63
63
|
font = validate_and_load_single_font(path)
|
|
64
64
|
end
|
|
65
65
|
names = extract_names_from_font(font)
|
|
66
|
-
#
|
|
66
|
+
# `has_table?` consults the table directory, which survives the
|
|
67
|
+
# metadata-mode load, so the fvar check is cheap; only an actual
|
|
68
|
+
# variable font pays for the follow-up full read. WOFF and WOFF2
|
|
69
|
+
# fonts from Fontisan hold no open file to close.
|
|
70
|
+
variable = font.has_table?("fvar")
|
|
67
71
|
font.close if font.respond_to?(:close)
|
|
72
|
+
names[:variable_instances] = extract_variable_instances_from_path(path) if
|
|
73
|
+
variable && names[:family_name]
|
|
68
74
|
names
|
|
69
75
|
rescue StandardError => e
|
|
70
76
|
raise_font_file_error(e)
|
|
71
77
|
end
|
|
72
78
|
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
|
73
79
|
|
|
80
|
+
def extract_variable_instances_from_path(path)
|
|
81
|
+
# Full mode: the metadata-mode loader gates fvar data out, so the
|
|
82
|
+
# instance pass needs the real table read; this runs only for
|
|
83
|
+
# fonts already identified as variable by the cheap directory check.
|
|
84
|
+
font = Fontisan::FontLoader.load(path, mode: :full, lazy: true)
|
|
85
|
+
extract_variable_instances(font)
|
|
86
|
+
ensure
|
|
87
|
+
font.close if font.respond_to?(:close)
|
|
88
|
+
end
|
|
89
|
+
|
|
74
90
|
# rubocop:disable Metrics/MethodLength
|
|
75
91
|
def validate_and_load_single_font(path)
|
|
76
92
|
# Load font first (we need to validate it, not the file path)
|
|
@@ -183,6 +199,62 @@ module Fontist
|
|
|
183
199
|
end
|
|
184
200
|
# rubocop:enable Metrics/MethodLength
|
|
185
201
|
|
|
202
|
+
# Named instances of a variable font, as `{family:, style:, full_name:}`
|
|
203
|
+
# triples. A variable file carries every named instance in one fvar
|
|
204
|
+
# table, but its name table exposes only the default instance's
|
|
205
|
+
# family, so an index built from the name table alone registers the
|
|
206
|
+
# file under a single family ("Fira Code Light") and every lookup of
|
|
207
|
+
# the other families/styles misses it. The RIBBI mapping follows the
|
|
208
|
+
# convention static families use: Regular/Bold live on the base
|
|
209
|
+
# family, every other weight becomes its own "Base Weight" family.
|
|
210
|
+
#
|
|
211
|
+
# @return [Array<Hash>] empty for a static font
|
|
212
|
+
# rubocop:disable Metrics/MethodLength
|
|
213
|
+
def extract_variable_instances(font)
|
|
214
|
+
return [] unless font.has_table?("fvar")
|
|
215
|
+
|
|
216
|
+
fvar = font.table("fvar")
|
|
217
|
+
name_table = font.table(Fontisan::Constants::NAME_TAG)
|
|
218
|
+
return [] unless name_table
|
|
219
|
+
|
|
220
|
+
base = name_table.english_name(Fontisan::Tables::Name::PREFERRED_FAMILY) ||
|
|
221
|
+
extract_any_name(name_table, Fontisan::Tables::Name::PREFERRED_FAMILY) ||
|
|
222
|
+
name_table.english_name(Fontisan::Tables::Name::FAMILY)
|
|
223
|
+
return [] unless base
|
|
224
|
+
|
|
225
|
+
ribbi = ["regular", "bold", "italic", "bold italic"]
|
|
226
|
+
|
|
227
|
+
fvar.instances.filter_map do |instance|
|
|
228
|
+
# fvar yields plain hashes ({name_id:, flags:, coordinates:,
|
|
229
|
+
# postscript_name_id:}), not message objects.
|
|
230
|
+
style = name_table.english_name(instance[:name_id]) ||
|
|
231
|
+
extract_any_name(name_table, instance[:name_id])
|
|
232
|
+
next unless style
|
|
233
|
+
|
|
234
|
+
if ribbi.include?(style.downcase)
|
|
235
|
+
family = base
|
|
236
|
+
type = style
|
|
237
|
+
full_name = "#{family} #{style}"
|
|
238
|
+
else
|
|
239
|
+
family = "#{base} #{style}"
|
|
240
|
+
type = "Regular"
|
|
241
|
+
full_name = family
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
{
|
|
245
|
+
family: family,
|
|
246
|
+
style: type,
|
|
247
|
+
full_name: full_name,
|
|
248
|
+
}
|
|
249
|
+
end
|
|
250
|
+
rescue StandardError => e
|
|
251
|
+
Fontist.ui.debug(
|
|
252
|
+
"Could not read variable instances: #{e.message}",
|
|
253
|
+
)
|
|
254
|
+
[]
|
|
255
|
+
end
|
|
256
|
+
# rubocop:enable Metrics/MethodLength
|
|
257
|
+
|
|
186
258
|
# Extract any available name for a given name ID by manually decoding the name record
|
|
187
259
|
def extract_any_name(name_table, name_id)
|
|
188
260
|
# Find any name record with the matching name_id
|
|
@@ -256,5 +328,11 @@ module Fontist
|
|
|
256
328
|
def preferred_subfamily_name
|
|
257
329
|
@info[:preferred_subfamily]
|
|
258
330
|
end
|
|
331
|
+
|
|
332
|
+
# Named instances of a variable font (`{family:, style:, full_name:}`
|
|
333
|
+
# triples); empty for a static font.
|
|
334
|
+
def variable_instances
|
|
335
|
+
@info[:variable_instances] || []
|
|
336
|
+
end
|
|
259
337
|
end
|
|
260
338
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require "
|
|
1
|
+
require "moxml"
|
|
2
2
|
require "paint"
|
|
3
3
|
|
|
4
4
|
module Fontist
|
|
@@ -277,7 +277,7 @@ module Fontist
|
|
|
277
277
|
|
|
278
278
|
def font_links
|
|
279
279
|
html = URI.parse(ROOT).open("User-Agent" => Fontist::Utils::UserAgent.random_user_agent).read
|
|
280
|
-
document =
|
|
280
|
+
document = Moxml.new.parse(html)
|
|
281
281
|
links = document.css(CARD_LINK_SELECTOR)
|
|
282
282
|
links = document.css(LEGACY_LINK_SELECTOR) if links.empty?
|
|
283
283
|
links
|
|
@@ -408,7 +408,7 @@ module Fontist
|
|
|
408
408
|
response = uri.open("User-Agent" => Fontist::Utils::UserAgent.random_user_agent)
|
|
409
409
|
current_url = response.base_uri
|
|
410
410
|
html = response.read
|
|
411
|
-
document =
|
|
411
|
+
document = Moxml.new.parse(html)
|
|
412
412
|
|
|
413
413
|
if @verbose
|
|
414
414
|
# Debug: Show what selectors find using standardized method
|
data/lib/fontist/system_index.rb
CHANGED
|
@@ -729,9 +729,48 @@ spinner_index = nil)
|
|
|
729
729
|
def detect_file_font(path)
|
|
730
730
|
font_file = FontFile.from_path(path)
|
|
731
731
|
|
|
732
|
+
entries = variable_font_entries(font_file, path)
|
|
733
|
+
return entries unless entries.empty?
|
|
734
|
+
|
|
732
735
|
parse_font(font_file, path)
|
|
733
736
|
end
|
|
734
737
|
|
|
738
|
+
# One index entry per named instance of a variable font: a variable
|
|
739
|
+
# file answers every lookup only if each family/style pair it carries
|
|
740
|
+
# is indexed separately — the name table alone registers just the
|
|
741
|
+
# default instance ("Fira Code Light"), leaving find_styles blind to
|
|
742
|
+
# the rest of the set.
|
|
743
|
+
def variable_font_entries(font_file, path)
|
|
744
|
+
instances = font_file.variable_instances
|
|
745
|
+
return [] if instances.empty?
|
|
746
|
+
|
|
747
|
+
file_size = begin
|
|
748
|
+
File.size(path)
|
|
749
|
+
rescue StandardError
|
|
750
|
+
0
|
|
751
|
+
end
|
|
752
|
+
file_mtime = begin
|
|
753
|
+
File.mtime(path).to_i
|
|
754
|
+
rescue StandardError
|
|
755
|
+
0
|
|
756
|
+
end
|
|
757
|
+
|
|
758
|
+
base = font_file.preferred_family_name || font_file.family
|
|
759
|
+
instances.map do |instance|
|
|
760
|
+
family = instance[:family]
|
|
761
|
+
SystemIndexFont.new(
|
|
762
|
+
path: path,
|
|
763
|
+
full_name: instance[:full_name],
|
|
764
|
+
family_name: family,
|
|
765
|
+
subfamily: instance[:style],
|
|
766
|
+
preferred_family_name: base,
|
|
767
|
+
preferred_subfamily_name: instance[:style],
|
|
768
|
+
file_size: file_size,
|
|
769
|
+
file_mtime: file_mtime,
|
|
770
|
+
)
|
|
771
|
+
end
|
|
772
|
+
end
|
|
773
|
+
|
|
735
774
|
def detect_collection_fonts(path)
|
|
736
775
|
CollectionFile.from_path(path) do |collection|
|
|
737
776
|
collection.map do |font_file|
|
data/lib/fontist/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fontist
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.0.
|
|
4
|
+
version: 3.0.32
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-11-
|
|
11
|
+
date: 2026-11-04 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: down
|
|
@@ -98,14 +98,14 @@ dependencies:
|
|
|
98
98
|
requirements:
|
|
99
99
|
- - "~>"
|
|
100
100
|
- !ruby/object:Gem::Version
|
|
101
|
-
version: 0.8.
|
|
101
|
+
version: 0.8.162
|
|
102
102
|
type: :runtime
|
|
103
103
|
prerelease: false
|
|
104
104
|
version_requirements: !ruby/object:Gem::Requirement
|
|
105
105
|
requirements:
|
|
106
106
|
- - "~>"
|
|
107
107
|
- !ruby/object:Gem::Version
|
|
108
|
-
version: 0.8.
|
|
108
|
+
version: 0.8.162
|
|
109
109
|
- !ruby/object:Gem::Dependency
|
|
110
110
|
name: marcel
|
|
111
111
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -121,19 +121,19 @@ dependencies:
|
|
|
121
121
|
- !ruby/object:Gem::Version
|
|
122
122
|
version: '1.0'
|
|
123
123
|
- !ruby/object:Gem::Dependency
|
|
124
|
-
name:
|
|
124
|
+
name: moxml
|
|
125
125
|
requirement: !ruby/object:Gem::Requirement
|
|
126
126
|
requirements:
|
|
127
127
|
- - "~>"
|
|
128
128
|
- !ruby/object:Gem::Version
|
|
129
|
-
version: '
|
|
129
|
+
version: '0.6'
|
|
130
130
|
type: :runtime
|
|
131
131
|
prerelease: false
|
|
132
132
|
version_requirements: !ruby/object:Gem::Requirement
|
|
133
133
|
requirements:
|
|
134
134
|
- - "~>"
|
|
135
135
|
- !ruby/object:Gem::Version
|
|
136
|
-
version: '
|
|
136
|
+
version: '0.6'
|
|
137
137
|
- !ruby/object:Gem::Dependency
|
|
138
138
|
name: octokit
|
|
139
139
|
requirement: !ruby/object:Gem::Requirement
|