fontisan 0.2.22 → 0.2.23

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.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +6 -0
  3. data/.rubocop_todo.yml +93 -17
  4. data/CHANGELOG.md +12 -2
  5. data/README.adoc +6 -210
  6. data/fontisan.gemspec +48 -0
  7. data/lib/fontisan/cldr/unicode_set_parser.rb +23 -6
  8. data/lib/fontisan/cldr/version_resolver.rb +1 -1
  9. data/lib/fontisan/cli.rb +0 -170
  10. data/lib/fontisan/commands.rb +0 -3
  11. data/lib/fontisan/formatters/text_formatter.rb +0 -6
  12. data/lib/fontisan/formatters.rb +0 -3
  13. data/lib/fontisan/hints.rb +6 -3
  14. data/lib/fontisan/models.rb +4 -4
  15. data/lib/fontisan/pipeline/strategies.rb +4 -2
  16. data/lib/fontisan/pipeline.rb +2 -1
  17. data/lib/fontisan/tables/cff.rb +2 -1
  18. data/lib/fontisan/tables.rb +2 -1
  19. data/lib/fontisan/version.rb +1 -1
  20. data/lib/fontisan.rb +0 -3
  21. metadata +7 -70
  22. data/lib/fontisan/audit/codepoint_range_coalescer.rb +0 -41
  23. data/lib/fontisan/audit/context.rb +0 -122
  24. data/lib/fontisan/audit/differ.rb +0 -124
  25. data/lib/fontisan/audit/extractors/aggregations.rb +0 -54
  26. data/lib/fontisan/audit/extractors/base.rb +0 -26
  27. data/lib/fontisan/audit/extractors/color_capabilities.rb +0 -141
  28. data/lib/fontisan/audit/extractors/coverage.rb +0 -48
  29. data/lib/fontisan/audit/extractors/hinting.rb +0 -197
  30. data/lib/fontisan/audit/extractors/identity.rb +0 -52
  31. data/lib/fontisan/audit/extractors/language_coverage.rb +0 -37
  32. data/lib/fontisan/audit/extractors/licensing.rb +0 -79
  33. data/lib/fontisan/audit/extractors/metrics.rb +0 -103
  34. data/lib/fontisan/audit/extractors/opentype_layout.rb +0 -69
  35. data/lib/fontisan/audit/extractors/provenance.rb +0 -29
  36. data/lib/fontisan/audit/extractors/style.rb +0 -32
  37. data/lib/fontisan/audit/extractors/variation_detail.rb +0 -99
  38. data/lib/fontisan/audit/extractors.rb +0 -27
  39. data/lib/fontisan/audit/library_aggregator.rb +0 -83
  40. data/lib/fontisan/audit/library_auditor.rb +0 -90
  41. data/lib/fontisan/audit/registry.rb +0 -60
  42. data/lib/fontisan/audit/style_extractor.rb +0 -80
  43. data/lib/fontisan/audit.rb +0 -20
  44. data/lib/fontisan/cli/ucd_cli.rb +0 -97
  45. data/lib/fontisan/commands/audit_command.rb +0 -123
  46. data/lib/fontisan/commands/audit_compare_command.rb +0 -66
  47. data/lib/fontisan/commands/audit_library_command.rb +0 -46
  48. data/lib/fontisan/config/ucd.yml +0 -23
  49. data/lib/fontisan/formatters/audit_diff_text_renderer.rb +0 -122
  50. data/lib/fontisan/formatters/audit_text_renderer.rb +0 -324
  51. data/lib/fontisan/formatters/library_summary_text_renderer.rb +0 -99
  52. data/lib/fontisan/models/audit/audit_axis.rb +0 -30
  53. data/lib/fontisan/models/audit/audit_block.rb +0 -32
  54. data/lib/fontisan/models/audit/audit_diff.rb +0 -77
  55. data/lib/fontisan/models/audit/audit_report.rb +0 -153
  56. data/lib/fontisan/models/audit/codepoint_range.rb +0 -40
  57. data/lib/fontisan/models/audit/codepoint_set_diff.rb +0 -34
  58. data/lib/fontisan/models/audit/color_capabilities.rb +0 -93
  59. data/lib/fontisan/models/audit/duplicate_group.rb +0 -23
  60. data/lib/fontisan/models/audit/embedding_type.rb +0 -76
  61. data/lib/fontisan/models/audit/field_change.rb +0 -28
  62. data/lib/fontisan/models/audit/fs_selection_flags.rb +0 -61
  63. data/lib/fontisan/models/audit/gasp_range.rb +0 -63
  64. data/lib/fontisan/models/audit/hinting.rb +0 -93
  65. data/lib/fontisan/models/audit/library_summary.rb +0 -40
  66. data/lib/fontisan/models/audit/licensing.rb +0 -48
  67. data/lib/fontisan/models/audit/metrics.rb +0 -111
  68. data/lib/fontisan/models/audit/named_instance.rb +0 -41
  69. data/lib/fontisan/models/audit/opentype_layout.rb +0 -40
  70. data/lib/fontisan/models/audit/script_coverage_row.rb +0 -26
  71. data/lib/fontisan/models/audit/script_features.rb +0 -28
  72. data/lib/fontisan/models/audit/variation_detail.rb +0 -44
  73. data/lib/fontisan/models/audit.rb +0 -33
  74. data/lib/fontisan/models/ucd/ucd.rb +0 -38
  75. data/lib/fontisan/models/ucd/ucd_char.rb +0 -67
  76. data/lib/fontisan/models/ucd.rb +0 -19
  77. data/lib/fontisan/ucd/aggregator.rb +0 -73
  78. data/lib/fontisan/ucd/cache_manager.rb +0 -111
  79. data/lib/fontisan/ucd/config.rb +0 -59
  80. data/lib/fontisan/ucd/download_error.rb +0 -9
  81. data/lib/fontisan/ucd/downloader.rb +0 -88
  82. data/lib/fontisan/ucd/error.rb +0 -8
  83. data/lib/fontisan/ucd/index.rb +0 -103
  84. data/lib/fontisan/ucd/index_builder.rb +0 -107
  85. data/lib/fontisan/ucd/range_entry.rb +0 -56
  86. data/lib/fontisan/ucd/unknown_version_error.rb +0 -9
  87. data/lib/fontisan/ucd/version_resolver.rb +0 -79
  88. data/lib/fontisan/ucd.rb +0 -23
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 215de38977d0c94ac54def7b0aef0cc200e326172fd71b30912f6484ae122320
4
- data.tar.gz: da89a4c238f617179e0da73377b83ae088d292c9e337cbc5c18832308864d970
3
+ metadata.gz: f84b59fae400f9db9dd05b2ddebce11bedb865138026f7a3a6d1b7ce0b3d8f2a
4
+ data.tar.gz: 563b27ed9dc91412fb83d7769a72a0d618109e3a6394236c7648524a60ad4fb6
5
5
  SHA512:
6
- metadata.gz: 5e18eef08d7be3ddd02e465497971cc020c7c5b03f40e4d92f02cf1c696d6553c9aa75b75cbea5ce4a5e43f0a7d683e57d7f1efada42b8d02b0b55da91837221
7
- data.tar.gz: '02830dec034211c50cad0d5ebef7c771276808f815e5487e0a012bf08cd0b820eac0570befc0eb5a1b0bc518f5f906b5bfa3012de5d13ebe20a67cd42fb79a7c'
6
+ metadata.gz: 7f2d94e40b9444414113ebf842a4a84e2188199829b4caf8b9e707bea6bca89c07b5e11fa04ba2f4aff1ce7ea658004385a5e2ae2ae4b4d4094d5bb90c4d5345
7
+ data.tar.gz: becf5ccba115f938caeb23d29e3cc0685edc9e0cb8452f8b1ed8b7e76cc8e742adcf3f9d1f5c8b1f01c1631fcb28a4ff2305068ce6b9677ef339d8f5fb4765b9
data/.rubocop.yml CHANGED
@@ -114,3 +114,9 @@ Layout/LineEndStringConcatenationIndentation:
114
114
  # Bitwise AND checks with != 0 are clearer for font bitmasks
115
115
  Style/BitwisePredicate:
116
116
  Enabled: false
117
+
118
+ # Allow short math-conventional parameter names in font geometry code.
119
+ # Point#x / Point#y are domain-standard coordinate names; renaming to
120
+ # x_coord/y_coord adds noise without aiding readers.
121
+ Naming/MethodParameterName:
122
+ AllowedNames: ["x", "y", "cp", "gid", "n"]
data/.rubocop_todo.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2026-06-24 11:12:20 UTC using RuboCop version 1.86.1.
3
+ # on 2026-06-29 07:08:46 UTC using RuboCop version 1.86.1.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
@@ -12,13 +12,77 @@ Gemspec/RequiredRubyVersion:
12
12
  - 'docs/node_modules/speakingurl/speakingurl-rails.gemspec'
13
13
  - 'fontisan.gemspec'
14
14
 
15
- # Offense count: 1606
15
+ # Offense count: 21
16
+ # This cop supports safe autocorrection (--autocorrect).
17
+ # Configuration parameters: EnforcedStyle, IndentationWidth.
18
+ # SupportedStyles: with_first_argument, with_fixed_indentation
19
+ Layout/ArgumentAlignment:
20
+ Exclude:
21
+ - 'lib/fontisan/cldr/unicode_set_parser.rb'
22
+ - 'lib/fontisan/hints.rb'
23
+ - 'lib/fontisan/models.rb'
24
+ - 'lib/fontisan/pipeline.rb'
25
+ - 'lib/fontisan/pipeline/strategies.rb'
26
+ - 'lib/fontisan/tables.rb'
27
+ - 'lib/fontisan/tables/cff.rb'
28
+ - 'spec/fontisan/cldr/config_spec.rb'
29
+ - 'spec/fontisan/cldr/unicode_set_parser_spec.rb'
30
+ - 'spec/fontisan/cli/cldr_cli_spec.rb'
31
+
32
+ # Offense count: 2
33
+ # This cop supports safe autocorrection (--autocorrect).
34
+ # Configuration parameters: EnforcedStyleAlignWith.
35
+ # SupportedStylesAlignWith: either, start_of_block, start_of_line
36
+ Layout/BlockAlignment:
37
+ Exclude:
38
+ - 'lib/fontisan/cldr/unicode_set_parser.rb'
39
+ - 'spec/fontisan/cldr/index_spec.rb'
40
+
41
+ # Offense count: 2
42
+ # This cop supports safe autocorrection (--autocorrect).
43
+ Layout/BlockEndNewline:
44
+ Exclude:
45
+ - 'lib/fontisan/cldr/unicode_set_parser.rb'
46
+ - 'spec/fontisan/cldr/index_spec.rb'
47
+
48
+ # Offense count: 2
49
+ # This cop supports safe autocorrection (--autocorrect).
50
+ Layout/EmptyLines:
51
+ Exclude:
52
+ - 'lib/fontisan/cli.rb'
53
+
54
+ # Offense count: 4
55
+ # This cop supports safe autocorrection (--autocorrect).
56
+ # Configuration parameters: Width, EnforcedStyleAlignWith, AllowedPatterns.
57
+ # SupportedStylesAlignWith: start_of_line, relative_to_receiver
58
+ Layout/IndentationWidth:
59
+ Exclude:
60
+ - 'lib/fontisan/cldr/unicode_set_parser.rb'
61
+ - 'spec/fontisan/cldr/index_spec.rb'
62
+
63
+ # Offense count: 1641
16
64
  # This cop supports safe autocorrection (--autocorrect).
17
65
  # Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
18
66
  # URISchemes: http, https
19
67
  Layout/LineLength:
20
68
  Enabled: false
21
69
 
70
+ # Offense count: 21
71
+ # This cop supports safe autocorrection (--autocorrect).
72
+ # Configuration parameters: AllowInHeredoc.
73
+ Layout/TrailingWhitespace:
74
+ Exclude:
75
+ - 'lib/fontisan/cldr/unicode_set_parser.rb'
76
+ - 'lib/fontisan/hints.rb'
77
+ - 'lib/fontisan/models.rb'
78
+ - 'lib/fontisan/pipeline.rb'
79
+ - 'lib/fontisan/pipeline/strategies.rb'
80
+ - 'lib/fontisan/tables.rb'
81
+ - 'lib/fontisan/tables/cff.rb'
82
+ - 'spec/fontisan/cldr/config_spec.rb'
83
+ - 'spec/fontisan/cldr/unicode_set_parser_spec.rb'
84
+ - 'spec/fontisan/cli/cldr_cli_spec.rb'
85
+
22
86
  # Offense count: 2
23
87
  Lint/CopDirectiveSyntax:
24
88
  Exclude:
@@ -97,7 +161,7 @@ Lint/UselessConstantScoping:
97
161
  - 'lib/fontisan/conversion_options.rb'
98
162
  - 'lib/fontisan/type1/charstrings.rb'
99
163
 
100
- # Offense count: 552
164
+ # Offense count: 557
101
165
  # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
102
166
  Metrics/AbcSize:
103
167
  Enabled: false
@@ -120,12 +184,12 @@ Metrics/CollectionLiteralLength:
120
184
  - 'lib/fontisan/type1/agl.rb'
121
185
  - 'lib/fontisan/type1/encodings.rb'
122
186
 
123
- # Offense count: 304
187
+ # Offense count: 308
124
188
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
125
189
  Metrics/CyclomaticComplexity:
126
190
  Enabled: false
127
191
 
128
- # Offense count: 844
192
+ # Offense count: 849
129
193
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
130
194
  Metrics/MethodLength:
131
195
  Max: 135
@@ -136,22 +200,16 @@ Metrics/ParameterLists:
136
200
  Max: 39
137
201
  MaxOptionalParameters: 4
138
202
 
139
- # Offense count: 229
203
+ # Offense count: 231
140
204
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
141
205
  Metrics/PerceivedComplexity:
142
206
  Enabled: false
143
207
 
144
- # Offense count: 24
208
+ # Offense count: 166
145
209
  # Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
146
210
  # AllowedNames: as, at, by, cc, db, id, if, in, io, ip, of, on, os, pp, to
147
211
  Naming/MethodParameterName:
148
- Exclude:
149
- - 'lib/fontisan/optimizers/subroutine_optimizer.rb'
150
- - 'lib/fontisan/tables/cff2/blend_operator.rb'
151
- - 'lib/fontisan/tables/glyf/curve_converter.rb'
152
- - 'lib/fontisan/type1/seac_expander.rb'
153
- - 'lib/fontisan/type1/ttf_to_type1_converter.rb'
154
- - 'lib/fontisan/variation/optimizer.rb'
212
+ Enabled: false
155
213
 
156
214
  # Offense count: 13
157
215
  # Configuration parameters: Mode, AllowedMethods, AllowedPatterns, AllowBangMethods, WaywardPredicates.
@@ -229,7 +287,7 @@ RSpec/DescribeMethod:
229
287
  - 'spec/fontisan/type1/seac_expander_spec.rb'
230
288
  - 'spec/fontisan/type1_real_fonts_spec.rb'
231
289
 
232
- # Offense count: 1446
290
+ # Offense count: 1458
233
291
  # Configuration parameters: CountAsOne.
234
292
  RSpec/ExampleLength:
235
293
  Max: 66
@@ -306,7 +364,7 @@ RSpec/MultipleDescribes:
306
364
  - 'spec/fontisan/utils/thread_pool_spec.rb'
307
365
  - 'spec/fontisan/variation/cache_spec.rb'
308
366
 
309
- # Offense count: 1868
367
+ # Offense count: 1902
310
368
  RSpec/MultipleExpectations:
311
369
  Max: 19
312
370
 
@@ -338,7 +396,7 @@ RSpec/RepeatedExample:
338
396
  - 'spec/fontisan/metrics_calculator_spec.rb'
339
397
  - 'spec/fontisan/tables/os2_spec.rb'
340
398
 
341
- # Offense count: 22
399
+ # Offense count: 23
342
400
  # Configuration parameters: CustomTransform, IgnoreMethods, IgnoreMetadata, InflectorPath, EnforcedInflector.
343
401
  # SupportedInflectors: default, active_support
344
402
  RSpec/SpecFilePathFormat:
@@ -374,6 +432,18 @@ Security/Open:
374
432
  Exclude:
375
433
  - 'Rakefile'
376
434
 
435
+ # Offense count: 2
436
+ # This cop supports safe autocorrection (--autocorrect).
437
+ # Configuration parameters: EnforcedStyle, ProceduralMethods, FunctionalMethods, AllowedMethods, AllowedPatterns, AllowBracesOnProceduralOneLiners, BracesRequiredMethods.
438
+ # SupportedStyles: line_count_based, semantic, braces_for_chaining, always_braces
439
+ # ProceduralMethods: benchmark, bm, bmbm, create, each_with_object, measure, new, realtime, tap, with_object
440
+ # FunctionalMethods: let, let!, subject, watch
441
+ # AllowedMethods: lambda, proc, it
442
+ Style/BlockDelimiters:
443
+ Exclude:
444
+ - 'lib/fontisan/cldr/unicode_set_parser.rb'
445
+ - 'spec/fontisan/cldr/index_spec.rb'
446
+
377
447
  # Offense count: 6
378
448
  # This cop supports safe autocorrection (--autocorrect).
379
449
  Style/ComparableClamp:
@@ -408,6 +478,12 @@ Style/HashLikeCase:
408
478
  - 'lib/fontisan/commands/unpack_command.rb'
409
479
  - 'lib/fontisan/models/validation_report.rb'
410
480
 
481
+ # Offense count: 9
482
+ # This cop supports safe autocorrection (--autocorrect).
483
+ Style/MultilineIfModifier:
484
+ Exclude:
485
+ - 'lib/fontisan/cldr/unicode_set_parser.rb'
486
+
411
487
  # Offense count: 1
412
488
  # Configuration parameters: AllowedMethods.
413
489
  # AllowedMethods: respond_to_missing?
data/CHANGELOG.md CHANGED
@@ -7,7 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
- ### Added
10
+ ### Removed
11
+
12
+ - Audit subsystem (`Fontisan::Audit`, `Fontisan::Commands::Audit*`,
13
+ `Formatters::AuditTextRenderer` / `AuditDiffTextRenderer` /
14
+ `LibrarySummaryTextRenderer`, `Models::Audit::*`) — moved to ucode.
15
+ Never had external consumers.
16
+ - UCD/UCDXML subsystem (`Fontisan::Ucd`, `config/ucd.yml`) — moved to
17
+ ucode. Never released in a published gem version.
18
+ - `fontisan audit` and `fontisan ucd` CLI subcommands.
19
+
20
+ ### Added (documentation)
11
21
  - Comprehensive documentation for WOFF/WOFF2 format support
12
22
  - Color fonts documentation (COLR/CPAL, sbix, SVG tables)
13
23
  - Font validation framework documentation
@@ -16,7 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
16
26
  - Updated font hinting documentation
17
27
  - Enhanced README with all v0.2.1-v0.2.7 features
18
28
 
19
- ### Changed
29
+ ### Changed (documentation)
20
30
  - Improved documentation organization with dedicated feature guides
21
31
  - Added more examples for command-line and Ruby API usage
22
32
 
data/README.adoc CHANGED
@@ -61,7 +61,7 @@ Color fonts and collections::
61
61
  * Font collection validation with per-font reporting (see link:docs/COLLECTION_VALIDATION.adoc[Collection Validation Guide])
62
62
 
63
63
  Font analysis and information::
64
- * Comprehensive per-face font audit (replaces `otfinfo`) covering identity, style, metrics, codepoint coverage, licensing, hinting, color capabilities, variable-font detail, OpenType layout features, UCD block/script aggregation, and CLDR language coverage — plus `--compare` mode and whole-library `--recursive --summary` mode
64
+ * Comprehensive per-face font metadata extraction (replaces `otfinfo`) covering identity, style, metrics, codepoint coverage, licensing, hinting, color capabilities, variable-font detail, and OpenType layout features
65
65
  * Bidirectional font hint conversion (see link:docs/FONT_HINTING.adoc[Font Hinting Guide])
66
66
  * Extract comprehensive font metadata (name, version, designer, license, etc.)
67
67
  * Brief mode for fast font indexing (5x faster, metadata-only loading)
@@ -107,215 +107,11 @@ Export and interfaces::
107
107
 
108
108
  == Font audit
109
109
 
110
- === General
111
-
112
- The `audit` command produces a complete per-face font audit report
113
- the successor to `otfinfo`, covering everything `otfinfo` reports plus
114
- codepoint coverage, licensing, hinting, color capabilities, variable-font
115
- detail, OpenType layout, UCD block/script aggregation, and CLDR language
116
- coverage. It also supports collections, `--compare` mode, and whole-
117
- library `--recursive --summary` mode.
118
-
119
- For each face, audit reports:
120
-
121
- Identity & provenance:: `family_name`, `subfamily_name`, `full_name`,
122
- `postscript_name`, `version`, `font_revision`, `source_sha256`,
123
- `source_format`, `fontisan_version`, `generated_at`.
124
- Style:: `weight_class` (+ human label), `width_class`, `bold`, `italic`,
125
- `panose`, `fs_selection_flags`.
126
- Coverage:: `total_codepoints`, `total_glyphs`, `cmap_subtables`,
127
- `codepoint_ranges` (compact by default; `--all-codepoints` for the
128
- flat list).
129
- Licensing:: `license_url`, `license_description`, `embedding_type`
130
- (decoded `fsType`).
131
- Metrics:: `units_per_em`, ascender/descender/etc., x-height, cap height,
132
- `metrics_consistent?` flag.
133
- Hinting:: `has_fpgm`, `has_prep`, `gasp_ranges`, TrueType vs PostScript
134
- hint presence.
135
- Color capabilities:: COLR/CPAL, sbix, CBDT/CBLC, SVG table presence.
136
- Variable-font detail:: axes (`fvar`), named instances.
137
- OpenType layout:: scripts/features in GSUB and GPOS.
138
- Aggregations (UCD):: per-block coverage rows, per-script roll-up.
139
- Language coverage (opt-in via `--with-language-coverage`):: per-language
140
- coverage % using CLDR exemplar sets.
141
-
142
- [source,shell]
143
- ----
144
- $ fontisan audit PATH [--compare LEFT RIGHT] [--recursive] [--summary]
145
- [--brief] [--all-codepoints]
146
- [--ucd-version VERSION] [--with-language-coverage]
147
- [--cldr-version VERSION]
148
- [--font-index N] [--output PATH] [--format FORMAT]
149
- ----
150
-
151
- Where,
152
-
153
- `PATH`:: Path to a font file (single-face audit), collection
154
- (`TTC`/`OTC`/`dfont` — one report per face), or directory
155
- (library mode with `--recursive`/`--summary`).
156
- `--compare`:: Diff two inputs (each is a font file or a saved
157
- `.yaml`/`.yml`/`.json` audit report). Requires exactly two paths.
158
- `--recursive`:: Library mode: walk subdirectories.
159
- `--summary`:: Library mode: produce a `LibrarySummary`.
160
- `--brief`:: Fast inventory: skip metrics, hinting, color, variation,
161
- OpenType layout, and UCD/CLDR aggregation. Note: distinct from
162
- `info --brief` — `audit --brief` still loads the full font.
163
- `--all-codepoints`:: Include the full per-codepoint list (default is a
164
- compact range view).
165
- `--ucd-version VERSION`:: Aggregate against this UCD version
166
- (`latest` probes upstream).
167
- `--with-language-coverage`:: Compute CLDR per-language coverage %
168
- (auto-downloads CLDR on first use).
169
- `--cldr-version VERSION`:: CLDR version (`latest` probes upstream).
170
- `--font-index N`:: Audit only face N of a collection.
171
- `--output PATH`:: Write to a directory (collection/library), file
172
- (single/compare), or stdout.
173
- `--format FORMAT`:: `text` (default), `yaml`, or `json`.
174
-
175
- === Command-line usage
176
-
177
- Single face:
178
-
179
- [source,shell]
180
- ----
181
- $ fontisan audit NotoSans-Regular.ttf
182
- $ fontisan audit NotoSans-Regular.ttf --format yaml
183
- $ fontisan audit NotoSans-Regular.ttf --brief
184
- $ fontisan audit NotoSans-Regular.ttf --with-language-coverage
185
- ----
186
-
187
- Collection (one report per face):
188
-
189
- [source,shell]
190
- ----
191
- $ fontisan audit Family.ttc
192
- $ fontisan audit Family.ttc --font-index 2
193
- $ fontisan audit Family.ttc --output reports/
194
- ----
195
-
196
- Compare two fonts or saved reports:
197
-
198
- [source,shell]
199
- ----
200
- $ fontisan audit --compare a.ttf b.ttf
201
- $ fontisan audit --compare baseline.yaml new.ttf
202
- $ fontisan audit --compare v1.yaml v2.yaml --output diff.yaml
203
- ----
204
-
205
- Library summary:
206
-
207
- [source,shell]
208
- ----
209
- $ fontisan audit lib/ --summary
210
- $ fontisan audit lib/ --recursive --summary
211
- $ fontisan audit lib/ --recursive --summary --format yaml --output library.yaml
212
- ----
213
-
214
- The library summary includes:
215
-
216
- * `root_path`, `total_files`, `total_faces`, `scanned_extensions`
217
- * `aggregate_metrics` — summed codepoints/glyphs/bytes
218
- * `script_coverage` — per-script face counts and face lists
219
- * `duplicate_groups` — files grouped by `source_sha256` (size > 1)
220
- * `license_distribution` — face counts per `license_url`
221
- * `per_face_reports` — the full per-face reports
222
-
223
- Files that fail to load (corrupt, unsupported) are reported on stderr
224
- as `skipped <path>` and excluded from the summary.
225
-
226
- UCD/CLDR cache management:
227
-
228
- [source,shell]
229
- ----
230
- $ fontisan ucd status
231
- $ fontisan ucd list
232
- $ fontisan ucd download 17.0.0
233
- $ fontisan cldr status
234
- $ fontisan cldr list
235
- $ fontisan cldr download 45
236
- ----
237
-
238
- === Ruby API usage
239
-
240
- Single face:
241
-
242
- [source,ruby]
243
- ----
244
- require "fontisan"
245
-
246
- # Returns an AuditReport for a single font, or an Array<AuditReport>
247
- # for a collection (one per face, in source order).
248
- report = Fontisan::Commands::AuditCommand.new(
249
- "NotoSans-Regular.ttf", ucd_version: "17.0.0"
250
- ).run
251
-
252
- report.family_name # => "Noto Sans"
253
- report.licensing.license_url # => "https://scripts.sil.org/OFL"
254
- report.blocks.first.fill_ratio # => 0.742
255
- report.opentype_layout.features # => ["c2sc", "calt", "case", ...]
256
- ----
257
-
258
- Compare:
259
-
260
- [source,ruby]
261
- ----
262
- diff = Fontisan::Commands::AuditCompareCommand.new(
263
- "baseline.yaml", "new.ttf", ucd_version: "17.0.0"
264
- ).run
265
-
266
- diff.field_changes.each { |c| puts "#{c.field}: #{c.left} -> #{c.right}" }
267
- puts "added codepoints: #{diff.codepoints.added_count}"
268
- ----
269
-
270
- Library summary:
271
-
272
- [source,ruby]
273
- ----
274
- cmd = Fontisan::Commands::AuditLibraryCommand.new(
275
- "lib/", recursive: true, options: { ucd_version: "17.0.0" }
276
- )
277
- summary = cmd.run
278
- cmd.skipped.each { |path| warn "skipped #{path}" }
279
-
280
- summary.script_coverage.each do |row|
281
- puts "#{row.script}: #{row.face_count} faces"
282
- end
283
-
284
- summary.duplicate_groups.each do |group|
285
- puts "duplicate #{group.source_sha256[0, 8]}: #{group.files.join(', ')}"
286
- end
287
- ----
288
-
289
- Brief mode (note the `audit_brief:` key — `brief:` would trigger
290
- metadata-only font loading via `BaseCommand`):
291
-
292
- [source,ruby]
293
- ----
294
- report = Fontisan::Commands::AuditCommand.new(
295
- "NotoSans-Regular.ttf", audit_brief: true, ucd_version: "17.0.0"
296
- ).run
297
- ----
298
-
299
- === Architecture
300
-
301
- Each audit concern is implemented as a small extractor class
302
- registered in `Fontisan::Audit::Registry`. `AuditCommand` builds an
303
- `Audit::Context` and iterates the registry, merging each extractor's
304
- output into a single `Models::Audit::AuditReport`. Adding a new field
305
- group means adding one extractor class and one line in the registry —
306
- `AuditCommand` itself never changes (open/closed).
307
-
308
- Two extractor sets are defined:
309
-
310
- * `ORDERED_EXTRACTORS` — the full set (default).
311
- * `BRIEF_EXTRACTORS` — a cheap subset for `--brief` (provenance,
312
- identity, style, licensing, coverage).
313
-
314
- Sub-models (`Licensing`, `Metrics`, `Hinting`, `ColorCapabilities`,
315
- `VariationDetail`, `OpenTypeLayout`, `CodepointRange`, `AuditBlock`,
316
- `NamedInstance`, `AuditAxis`, `ScriptFeatures`) group related fields
317
- on `AuditReport` (MECE). Compare mode produces an `AuditDiff`; library
318
- mode produces a `LibrarySummary`.
110
+ [NOTE]
111
+ ====
112
+ The `audit` and `ucd` subsystems have moved to the `ucode` gem. See
113
+ the `ucode` documentation for the equivalent commands.
114
+ ====
319
115
 
320
116
 
321
117
  == Font information
data/fontisan.gemspec ADDED
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/fontisan/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "fontisan"
7
+ spec.version = Fontisan::VERSION
8
+ spec.authors = ["Ribose Inc."]
9
+ spec.email = ["open.source@ribose.com"]
10
+
11
+ spec.summary = "Font analysis tools and utilities for OpenType fonts"
12
+ spec.description = <<~HEREDOC
13
+ Fontisan provides font analysis tools and utilities. It is
14
+ designed as a pure Ruby implementation with full object-oriented architecture,
15
+ supporting extraction of information from OpenType and TrueType fonts (OTF, TTF, OTC, TTC).
16
+
17
+ The gem provides both a Ruby library API and a command-line interface,
18
+ with structured output formats (YAML, JSON, text).
19
+ HEREDOC
20
+
21
+ spec.homepage = "https://github.com/fontist/fontisan"
22
+ spec.license = "BSD-2-Clause"
23
+ spec.required_ruby_version = ">= 3.0.0"
24
+
25
+ spec.metadata["homepage_uri"] = spec.homepage
26
+ spec.metadata["source_code_uri"] = "https://github.com/fontist/fontisan"
27
+ spec.metadata["changelog_uri"] = "https://github.com/fontist/fontisan/blob/main/CHANGELOG.md"
28
+ spec.metadata["rubygems_mfa_required"] = "true"
29
+
30
+ # Specify which files should be added to the gem when it is released.
31
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
32
+ spec.files = Dir.chdir(__dir__) do
33
+ `git ls-files -z`.split("\x0").reject do |f|
34
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
35
+ end
36
+ end
37
+ spec.bindir = "exe"
38
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
39
+ spec.require_paths = ["lib"]
40
+
41
+ spec.add_dependency "base64"
42
+ spec.add_dependency "bindata", "~> 2.5"
43
+ spec.add_dependency "brotli", "~> 0.5"
44
+ spec.add_dependency "logger"
45
+ spec.add_dependency "lutaml-model", "~> 0.8"
46
+ spec.add_dependency "nokogiri", "~> 1.16"
47
+ spec.add_dependency "thor", "~> 1.3"
48
+ end
@@ -28,7 +28,10 @@ module Fontisan
28
28
  # @param set_string [String] bracketed ICU UnicodeSet, e.g. "[a-zà]"
29
29
  # @return [Array<Integer>] sorted, deduplicated codepoints
30
30
  def call(set_string)
31
- raise ParseError, "input must be bracketed" unless set_string.start_with?("[") && set_string.end_with?("]")
31
+ unless set_string.start_with?("[") && set_string.end_with?("]")
32
+ raise ParseError,
33
+ "input must be bracketed"
34
+ end
32
35
 
33
36
  body = set_string[1..-2]
34
37
  negate = body.start_with?("^")
@@ -125,8 +128,13 @@ module Fontisan
125
128
  return nil unless chars[start + 2] == "{"
126
129
 
127
130
  # \u{XXX...} variable hex
128
- end_idx = (start + 3..).find { |j| j >= chars.length || chars[j] == "}" }
129
- raise ParseError, "unclosed \\u{ escape" if end_idx.nil? || chars[end_idx] != "}"
131
+ end_idx = (start + 3..).find do |j|
132
+ j >= chars.length || chars[j] == "}"
133
+ end
134
+ if end_idx.nil? || chars[end_idx] != "}"
135
+ raise ParseError,
136
+ "unclosed \\u{ escape"
137
+ end
130
138
 
131
139
  hex = chars[(start + 3)...end_idx].join
132
140
  cp = hex.to_i(16)
@@ -139,10 +147,16 @@ module Fontisan
139
147
  def four_hex(chars, start, marker)
140
148
  # \uXXXX — exactly 4 hex digits
141
149
  hex = chars[(start + 2), 4]&.join
142
- raise ParseError, "truncated \\#{marker} escape" if hex.nil? || hex.length < 4
150
+ if hex.nil? || hex.length < 4
151
+ raise ParseError,
152
+ "truncated \\#{marker} escape"
153
+ end
143
154
 
144
155
  cp = hex.to_i(16)
145
- raise ParseError, "\\#{marker} escape with non-hex digits" if cp.zero? && !hex.match?(/\A0+\z/)
156
+ if cp.zero? && !hex.match?(/\A0+\z/)
157
+ raise ParseError,
158
+ "\\#{marker} escape with non-hex digits"
159
+ end
146
160
 
147
161
  [cp, 6]
148
162
  end
@@ -154,7 +168,10 @@ module Fontisan
154
168
  raise ParseError, "truncated \\U escape" if hex.nil? || hex.length < 8
155
169
 
156
170
  cp = hex.to_i(16)
157
- raise ParseError, "\\U escape with non-hex digits" if cp.zero? && !hex.match?(/\A0+\z/)
171
+ if cp.zero? && !hex.match?(/\A0+\z/)
172
+ raise ParseError,
173
+ "\\U escape with non-hex digits"
174
+ end
158
175
 
159
176
  [cp, 10]
160
177
  end
@@ -9,7 +9,7 @@ module Fontisan
9
9
  module Cldr
10
10
  # Resolves a user-supplied version intent to a concrete CLDR version.
11
11
  #
12
- # Mirrors {Ucd::VersionResolver}. Three input modes:
12
+ # Three input modes:
13
13
  #
14
14
  # resolve(nil) # default_version from config
15
15
  # resolve(:default) # default_version from config