fontist 3.0.16 → 3.0.18

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3871228b469c6c8ee43f6bd04d6b9726feddac6fb2245f3f2bf5533b05a2baf9
4
- data.tar.gz: 9e6d136e1ceaa16dd7a3907fe346bbc0a90f46a51458334a5192b5a2dea085e9
3
+ metadata.gz: '0215294c3d206af7354e6fd6f6f4fd0640e0ba68e53c6ef9891d09f646dfc34e'
4
+ data.tar.gz: 35757e455e568ec462f7c9fe9347104ac28b87a2b1140fde946847d5aa283fa1
5
5
  SHA512:
6
- metadata.gz: a201906009471c3844a708096fea687db8aa5a8eb56efc3e13076580dfefd1fea95e12edbbe2707928f5b3ed77db326a5147bf6e043965033fc5b27586166dc2
7
- data.tar.gz: b4ff402ff006a766f1daee41ffbed825f826b24c88997e9ea92a91c435fcf88545ffdf921f7091371a247b489a2dc4d0ee92faad6b11a1dfae5f2967ddcd038d
6
+ metadata.gz: cf6667f140b7437998eb2d5ae2828e98ca5265f326a274ac00519d7be8e274c59615a6a0ca7d94b425f58a6327367d6939d4c18783068d785cde2937ee99d32a
7
+ data.tar.gz: da9ef27ff12d6d8902f295bca6c8965bcf996f6aeb8a89c63c54b629aca16f34e5f9af8be776509dd35a14594ff7996884e0fc5992f7b4713755f4bb013aba42
data/Gemfile CHANGED
@@ -18,6 +18,11 @@ gem "simplecov"
18
18
  gem "vcr"
19
19
  gem "webmock"
20
20
 
21
+ # Optional YAML engine (consumer-side dependency; needs Ruby >= 3.0,
22
+ # which is above fontist's gemspec floor, so it stays out of the
23
+ # gemspec). When installed, model YAML parses route through it.
24
+ gem "yeptris", require: false
25
+
21
26
  # Profiling tools (development only)
22
27
  # gem "ruby-prof", "~> 1.7"
23
28
  # stackprof uses Unix-specific system calls and doesn't compile on Windows
@@ -100,6 +100,39 @@ module Fontist
100
100
  end
101
101
  end
102
102
 
103
+ # Thread-safe progress display for parallel index scans
104
+ class ScanProgress
105
+ SPINNER_CHARS = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"].freeze
106
+
107
+ def initialize(total, verbose:, &on_step)
108
+ @total = total
109
+ @verbose = verbose
110
+ @on_step = on_step
111
+ @mutex = Mutex.new
112
+ @processed = 0
113
+ # Show minimal progress for large collections even in non-verbose mode
114
+ @minimal = !verbose && total > 100
115
+ @interval = total > 1000 ? 100 : 50
116
+ end
117
+
118
+ def step(path)
119
+ @mutex.synchronize do
120
+ @processed += 1
121
+ if @verbose
122
+ @on_step&.call(@processed, path)
123
+ elsif @minimal && report?
124
+ Fontist.ui.say("Scanning fonts: #{@processed}/#{@total}...")
125
+ end
126
+ end
127
+ end
128
+
129
+ private
130
+
131
+ def report?
132
+ (@processed % @interval).zero? || @processed == @total
133
+ end
134
+ end
135
+
103
136
  # {:path=>"/Library/Fonts/Arial Unicode.ttf",
104
137
  # :full_name=>"Arial Unicode MS",
105
138
  # :family_name=>"Arial Unicode MS",
@@ -518,33 +551,38 @@ stats:)
518
551
  if verbose
519
552
  puts Paint["Using parallel processing with #{num_cores} cores",
520
553
  :cyan]
521
- end
522
-
523
- # Thread-safe progress tracking
524
- progress_mutex = Mutex.new
525
- processed_count = 0
526
- spinner_chars = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
527
554
 
528
- # Show minimal progress for large collections even in non-verbose mode
529
- show_minimal_progress = !verbose && sorted_paths.size > 100
530
- progress_interval = sorted_paths.size > 1000 ? 100 : 50
555
+ # Verbose runs keep threads so live progress and per-font stats
556
+ # stay visible; fontisan parsing is GVL-bound, so this mode is
557
+ # slow, but it is the human-attended path
558
+ process_paths_in_threads(sorted_paths, existing_fonts_by_path,
559
+ verbose: verbose, stats: stats,
560
+ num_workers: num_cores)
561
+ else
562
+ # Measured on 600 system fonts: single thread 2.3s, 8 threads
563
+ # 3.3s (GVL-bound, mutex contention), 8 processes 0.6s. The
564
+ # silent build path therefore forks instead of threading
565
+ results = Parallel.map(sorted_paths, in_processes: num_cores) do |path|
566
+ detect_font_with_cache(path, existing_fonts_by_path[path],
567
+ stats: nil)
568
+ end.flatten.compact
569
+
570
+ stats&.total_fonts = results.size
571
+ results
572
+ end
573
+ end
531
574
 
532
- results = Parallel.map(sorted_paths, in_threads: num_cores) do |path|
533
- cached = existing_fonts_by_path[path]
534
- result = detect_font_with_cache(path, cached, stats: stats)
535
-
536
- # Update progress (thread-safe)
537
- progress_mutex.synchronize do
538
- processed_count += 1
539
- if verbose && stats
540
- display_progress(processed_count, sorted_paths.size, path,
541
- spinner_chars)
542
- elsif show_minimal_progress && ((processed_count % progress_interval).zero? || processed_count == sorted_paths.size)
543
- # Show minimal progress every N fonts or at the end
544
- Fontist.ui.say("Scanning fonts: #{processed_count}/#{sorted_paths.size}...")
545
- end
546
- end
575
+ def process_paths_in_threads(sorted_paths, existing_fonts_by_path,
576
+ verbose:, stats:, num_workers:)
577
+ progress = ScanProgress.new(sorted_paths.size, verbose: verbose) do |count, path|
578
+ display_progress(count, sorted_paths.size, path,
579
+ ScanProgress::SPINNER_CHARS)
580
+ end
547
581
 
582
+ results = Parallel.map(sorted_paths, in_threads: num_workers) do |path|
583
+ result = detect_font_with_cache(path, existing_fonts_by_path[path],
584
+ stats: stats)
585
+ progress.step(path)
548
586
  result
549
587
  end.flatten.compact
550
588
 
@@ -1,3 +1,3 @@
1
1
  module Fontist
2
- VERSION = "3.0.16".freeze
2
+ VERSION = "3.0.18".freeze
3
3
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fontist
4
+ module Yaml
5
+ # Model YAML parsing through yeptris's native loader. Measured 4x
6
+ # faster than Psych on formula and index documents (442KB index:
7
+ # 47ms vs 202ms), with parse results verified identical across the
8
+ # full formulas corpus. Dumping stays on the standard adapter.
9
+ class YeptrisAdapter < Lutaml::Yaml::Adapter::StandardAdapter
10
+ def self.parse(yaml, _options = {})
11
+ Yeptris::YAML.load(yaml)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,5 @@
1
+ module Fontist
2
+ module Yaml
3
+ autoload :YeptrisAdapter, "#{__dir__}/yaml/yeptris_adapter"
4
+ end
5
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fontist
4
+ # Model YAML engine selection.
5
+ #
6
+ # When the yeptris gem is available, model YAML (formula and index
7
+ # documents, via lutaml-model) is parsed through its native loader -
8
+ # measured 4x faster than Psych on those artifacts. The gem is an
9
+ # optional consumer-side dependency (it needs Ruby >= 3.0, above
10
+ # fontist's floor), so absence falls back to Psych silently.
11
+ # FONTIST_YAML=psych forces the standard engine.
12
+ module YamlBackend
13
+ ENV_KEY = "FONTIST_YAML"
14
+
15
+ class << self
16
+ # Returns the activated adapter class, or nil when the standard
17
+ # engine stays in place (flag set, or yeptris unavailable)
18
+ def activate!
19
+ return nil if forced_standard?
20
+ return nil unless yeptris_available?
21
+
22
+ adapter = Yaml::YeptrisAdapter
23
+ Lutaml::Model::AdapterResolver.set_adapter_class(:yaml, adapter)
24
+
25
+ adapter
26
+ end
27
+
28
+ def forced_standard?
29
+ ENV[ENV_KEY] == "psych"
30
+ end
31
+
32
+ def yeptris_available?
33
+ require "yeptris"
34
+ true
35
+ rescue LoadError
36
+ false
37
+ end
38
+ end
39
+ end
40
+ end
data/lib/fontist.rb CHANGED
@@ -11,6 +11,8 @@ require_relative "fontist/from_file_cache"
11
11
  require_relative "fontist/memoizable"
12
12
  require_relative "fontist/path_scanning"
13
13
  require_relative "fontist/utils"
14
+ require_relative "fontist/yaml"
15
+ require_relative "fontist/yaml_backend"
14
16
 
15
17
  module Fontist
16
18
  # Core classes
@@ -282,3 +284,5 @@ module Fontist
282
284
  true
283
285
  end
284
286
  end
287
+
288
+ Fontist::YamlBackend.activate!
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fontist
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.16
4
+ version: 3.0.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -512,6 +512,9 @@ files:
512
512
  - lib/fontist/version.rb
513
513
  - lib/fontist/windows_fod_metadata.rb
514
514
  - lib/fontist/windows_import_source.rb
515
+ - lib/fontist/yaml.rb
516
+ - lib/fontist/yaml/yeptris_adapter.rb
517
+ - lib/fontist/yaml_backend.rb
515
518
  - lib/tasks/system_fonts.rake
516
519
  - script/capture_system_fonts
517
520
  - script/download_system_indexes