fontisan 0.1.0 → 0.2.1
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/.rubocop_todo.yml +672 -69
- data/Gemfile +1 -0
- data/LICENSE +5 -1
- data/README.adoc +1477 -297
- data/Rakefile +63 -41
- data/benchmark/variation_quick_bench.rb +47 -0
- data/docs/EXTRACT_TTC_MIGRATION.md +549 -0
- data/fontisan.gemspec +4 -1
- data/lib/fontisan/binary/base_record.rb +22 -1
- data/lib/fontisan/cli.rb +364 -4
- data/lib/fontisan/collection/builder.rb +341 -0
- data/lib/fontisan/collection/offset_calculator.rb +227 -0
- data/lib/fontisan/collection/table_analyzer.rb +204 -0
- data/lib/fontisan/collection/table_deduplicator.rb +317 -0
- data/lib/fontisan/collection/writer.rb +306 -0
- data/lib/fontisan/commands/base_command.rb +24 -1
- data/lib/fontisan/commands/convert_command.rb +218 -0
- data/lib/fontisan/commands/export_command.rb +161 -0
- data/lib/fontisan/commands/info_command.rb +40 -6
- data/lib/fontisan/commands/instance_command.rb +286 -0
- data/lib/fontisan/commands/ls_command.rb +113 -0
- data/lib/fontisan/commands/pack_command.rb +241 -0
- data/lib/fontisan/commands/subset_command.rb +245 -0
- data/lib/fontisan/commands/unpack_command.rb +338 -0
- data/lib/fontisan/commands/validate_command.rb +203 -0
- data/lib/fontisan/commands/variable_command.rb +30 -1
- data/lib/fontisan/config/collection_settings.yml +56 -0
- data/lib/fontisan/config/conversion_matrix.yml +212 -0
- data/lib/fontisan/config/export_settings.yml +66 -0
- data/lib/fontisan/config/subset_profiles.yml +100 -0
- data/lib/fontisan/config/svg_settings.yml +60 -0
- data/lib/fontisan/config/validation_rules.yml +149 -0
- data/lib/fontisan/config/variable_settings.yml +99 -0
- data/lib/fontisan/config/woff2_settings.yml +77 -0
- data/lib/fontisan/constants.rb +79 -0
- data/lib/fontisan/converters/conversion_strategy.rb +96 -0
- data/lib/fontisan/converters/format_converter.rb +408 -0
- data/lib/fontisan/converters/outline_converter.rb +998 -0
- data/lib/fontisan/converters/svg_generator.rb +244 -0
- data/lib/fontisan/converters/table_copier.rb +117 -0
- data/lib/fontisan/converters/woff2_encoder.rb +416 -0
- data/lib/fontisan/converters/woff_writer.rb +391 -0
- data/lib/fontisan/error.rb +203 -0
- data/lib/fontisan/export/exporter.rb +262 -0
- data/lib/fontisan/export/table_serializer.rb +255 -0
- data/lib/fontisan/export/transformers/font_to_ttx.rb +172 -0
- data/lib/fontisan/export/transformers/head_transformer.rb +96 -0
- data/lib/fontisan/export/transformers/hhea_transformer.rb +59 -0
- data/lib/fontisan/export/transformers/maxp_transformer.rb +63 -0
- data/lib/fontisan/export/transformers/name_transformer.rb +63 -0
- data/lib/fontisan/export/transformers/os2_transformer.rb +121 -0
- data/lib/fontisan/export/transformers/post_transformer.rb +51 -0
- data/lib/fontisan/export/ttx_generator.rb +527 -0
- data/lib/fontisan/export/ttx_parser.rb +300 -0
- data/lib/fontisan/font_loader.rb +122 -15
- data/lib/fontisan/font_writer.rb +302 -0
- data/lib/fontisan/formatters/text_formatter.rb +102 -0
- data/lib/fontisan/glyph_accessor.rb +503 -0
- data/lib/fontisan/hints/hint_converter.rb +310 -0
- data/lib/fontisan/hints/postscript_hint_applier.rb +266 -0
- data/lib/fontisan/hints/postscript_hint_extractor.rb +354 -0
- data/lib/fontisan/hints/truetype_hint_applier.rb +117 -0
- data/lib/fontisan/hints/truetype_hint_extractor.rb +289 -0
- data/lib/fontisan/loading_modes.rb +115 -0
- data/lib/fontisan/metrics_calculator.rb +277 -0
- data/lib/fontisan/models/collection_font_summary.rb +52 -0
- data/lib/fontisan/models/collection_info.rb +76 -0
- data/lib/fontisan/models/collection_list_info.rb +37 -0
- data/lib/fontisan/models/font_export.rb +158 -0
- data/lib/fontisan/models/font_summary.rb +48 -0
- data/lib/fontisan/models/glyph_outline.rb +343 -0
- data/lib/fontisan/models/hint.rb +405 -0
- data/lib/fontisan/models/outline.rb +664 -0
- data/lib/fontisan/models/table_sharing_info.rb +40 -0
- data/lib/fontisan/models/ttx/glyph_order.rb +31 -0
- data/lib/fontisan/models/ttx/tables/binary_table.rb +67 -0
- data/lib/fontisan/models/ttx/tables/head_table.rb +74 -0
- data/lib/fontisan/models/ttx/tables/hhea_table.rb +74 -0
- data/lib/fontisan/models/ttx/tables/maxp_table.rb +55 -0
- data/lib/fontisan/models/ttx/tables/name_table.rb +45 -0
- data/lib/fontisan/models/ttx/tables/os2_table.rb +157 -0
- data/lib/fontisan/models/ttx/tables/post_table.rb +50 -0
- data/lib/fontisan/models/ttx/ttfont.rb +49 -0
- data/lib/fontisan/models/validation_report.rb +203 -0
- data/lib/fontisan/open_type_collection.rb +156 -2
- data/lib/fontisan/open_type_font.rb +321 -19
- data/lib/fontisan/open_type_font_extensions.rb +54 -0
- data/lib/fontisan/optimizers/charstring_rewriter.rb +161 -0
- data/lib/fontisan/optimizers/pattern_analyzer.rb +308 -0
- data/lib/fontisan/optimizers/stack_tracker.rb +246 -0
- data/lib/fontisan/optimizers/subroutine_builder.rb +134 -0
- data/lib/fontisan/optimizers/subroutine_generator.rb +207 -0
- data/lib/fontisan/optimizers/subroutine_optimizer.rb +107 -0
- data/lib/fontisan/outline_extractor.rb +423 -0
- data/lib/fontisan/pipeline/format_detector.rb +249 -0
- data/lib/fontisan/pipeline/output_writer.rb +154 -0
- data/lib/fontisan/pipeline/strategies/base_strategy.rb +75 -0
- data/lib/fontisan/pipeline/strategies/instance_strategy.rb +93 -0
- data/lib/fontisan/pipeline/strategies/named_strategy.rb +118 -0
- data/lib/fontisan/pipeline/strategies/preserve_strategy.rb +56 -0
- data/lib/fontisan/pipeline/transformation_pipeline.rb +411 -0
- data/lib/fontisan/pipeline/variation_resolver.rb +165 -0
- data/lib/fontisan/subset/builder.rb +268 -0
- data/lib/fontisan/subset/glyph_mapping.rb +215 -0
- data/lib/fontisan/subset/options.rb +142 -0
- data/lib/fontisan/subset/profile.rb +152 -0
- data/lib/fontisan/subset/table_subsetter.rb +461 -0
- data/lib/fontisan/svg/font_face_generator.rb +278 -0
- data/lib/fontisan/svg/font_generator.rb +264 -0
- data/lib/fontisan/svg/glyph_generator.rb +168 -0
- data/lib/fontisan/svg/view_box_calculator.rb +137 -0
- data/lib/fontisan/tables/cff/cff_glyph.rb +176 -0
- data/lib/fontisan/tables/cff/charset.rb +282 -0
- data/lib/fontisan/tables/cff/charstring.rb +934 -0
- data/lib/fontisan/tables/cff/charstring_builder.rb +356 -0
- data/lib/fontisan/tables/cff/charstring_parser.rb +237 -0
- data/lib/fontisan/tables/cff/charstring_rebuilder.rb +172 -0
- data/lib/fontisan/tables/cff/charstrings_index.rb +162 -0
- data/lib/fontisan/tables/cff/dict.rb +351 -0
- data/lib/fontisan/tables/cff/dict_builder.rb +257 -0
- data/lib/fontisan/tables/cff/encoding.rb +274 -0
- data/lib/fontisan/tables/cff/header.rb +102 -0
- data/lib/fontisan/tables/cff/hint_operation_injector.rb +207 -0
- data/lib/fontisan/tables/cff/index.rb +237 -0
- data/lib/fontisan/tables/cff/index_builder.rb +170 -0
- data/lib/fontisan/tables/cff/offset_recalculator.rb +70 -0
- data/lib/fontisan/tables/cff/private_dict.rb +284 -0
- data/lib/fontisan/tables/cff/private_dict_writer.rb +125 -0
- data/lib/fontisan/tables/cff/table_builder.rb +221 -0
- data/lib/fontisan/tables/cff/top_dict.rb +236 -0
- data/lib/fontisan/tables/cff.rb +489 -0
- data/lib/fontisan/tables/cff2/blend_operator.rb +240 -0
- data/lib/fontisan/tables/cff2/charstring_parser.rb +591 -0
- data/lib/fontisan/tables/cff2/operand_stack.rb +232 -0
- data/lib/fontisan/tables/cff2/private_dict_blend_handler.rb +246 -0
- data/lib/fontisan/tables/cff2/region_matcher.rb +200 -0
- data/lib/fontisan/tables/cff2/table_builder.rb +574 -0
- data/lib/fontisan/tables/cff2/table_reader.rb +419 -0
- data/lib/fontisan/tables/cff2/variation_data_extractor.rb +212 -0
- data/lib/fontisan/tables/cff2.rb +346 -0
- data/lib/fontisan/tables/cvar.rb +203 -0
- data/lib/fontisan/tables/fvar.rb +2 -2
- data/lib/fontisan/tables/glyf/compound_glyph.rb +483 -0
- data/lib/fontisan/tables/glyf/compound_glyph_resolver.rb +136 -0
- data/lib/fontisan/tables/glyf/curve_converter.rb +343 -0
- data/lib/fontisan/tables/glyf/glyph_builder.rb +450 -0
- data/lib/fontisan/tables/glyf/simple_glyph.rb +382 -0
- data/lib/fontisan/tables/glyf.rb +235 -0
- data/lib/fontisan/tables/gvar.rb +231 -0
- data/lib/fontisan/tables/hhea.rb +124 -0
- data/lib/fontisan/tables/hmtx.rb +287 -0
- data/lib/fontisan/tables/hvar.rb +191 -0
- data/lib/fontisan/tables/loca.rb +322 -0
- data/lib/fontisan/tables/maxp.rb +192 -0
- data/lib/fontisan/tables/mvar.rb +185 -0
- data/lib/fontisan/tables/name.rb +99 -30
- data/lib/fontisan/tables/variation_common.rb +346 -0
- data/lib/fontisan/tables/vvar.rb +234 -0
- data/lib/fontisan/true_type_collection.rb +156 -2
- data/lib/fontisan/true_type_font.rb +321 -20
- data/lib/fontisan/true_type_font_extensions.rb +54 -0
- data/lib/fontisan/utilities/brotli_wrapper.rb +159 -0
- data/lib/fontisan/utilities/checksum_calculator.rb +60 -0
- data/lib/fontisan/utils/thread_pool.rb +134 -0
- data/lib/fontisan/validation/checksum_validator.rb +170 -0
- data/lib/fontisan/validation/consistency_validator.rb +197 -0
- data/lib/fontisan/validation/structure_validator.rb +198 -0
- data/lib/fontisan/validation/table_validator.rb +158 -0
- data/lib/fontisan/validation/validator.rb +152 -0
- data/lib/fontisan/validation/variable_font_validator.rb +218 -0
- data/lib/fontisan/variable/axis_normalizer.rb +215 -0
- data/lib/fontisan/variable/delta_applicator.rb +313 -0
- data/lib/fontisan/variable/glyph_delta_processor.rb +218 -0
- data/lib/fontisan/variable/instancer.rb +344 -0
- data/lib/fontisan/variable/metric_delta_processor.rb +282 -0
- data/lib/fontisan/variable/region_matcher.rb +208 -0
- data/lib/fontisan/variable/static_font_builder.rb +213 -0
- data/lib/fontisan/variable/table_updater.rb +219 -0
- data/lib/fontisan/variation/blend_applier.rb +199 -0
- data/lib/fontisan/variation/cache.rb +298 -0
- data/lib/fontisan/variation/cache_key_builder.rb +162 -0
- data/lib/fontisan/variation/converter.rb +375 -0
- data/lib/fontisan/variation/data_extractor.rb +86 -0
- data/lib/fontisan/variation/delta_applier.rb +266 -0
- data/lib/fontisan/variation/delta_parser.rb +228 -0
- data/lib/fontisan/variation/inspector.rb +275 -0
- data/lib/fontisan/variation/instance_generator.rb +273 -0
- data/lib/fontisan/variation/instance_writer.rb +341 -0
- data/lib/fontisan/variation/interpolator.rb +231 -0
- data/lib/fontisan/variation/metrics_adjuster.rb +318 -0
- data/lib/fontisan/variation/optimizer.rb +418 -0
- data/lib/fontisan/variation/parallel_generator.rb +150 -0
- data/lib/fontisan/variation/region_matcher.rb +221 -0
- data/lib/fontisan/variation/subsetter.rb +463 -0
- data/lib/fontisan/variation/table_accessor.rb +105 -0
- data/lib/fontisan/variation/tuple_variation_header.rb +51 -0
- data/lib/fontisan/variation/validator.rb +345 -0
- data/lib/fontisan/variation/variable_svg_generator.rb +268 -0
- data/lib/fontisan/variation/variation_context.rb +211 -0
- data/lib/fontisan/variation/variation_preserver.rb +288 -0
- data/lib/fontisan/version.rb +1 -1
- data/lib/fontisan/version.rb.orig +9 -0
- data/lib/fontisan/woff2/directory.rb +257 -0
- data/lib/fontisan/woff2/glyf_transformer.rb +666 -0
- data/lib/fontisan/woff2/header.rb +101 -0
- data/lib/fontisan/woff2/hmtx_transformer.rb +164 -0
- data/lib/fontisan/woff2/table_transformer.rb +163 -0
- data/lib/fontisan/woff2_font.rb +717 -0
- data/lib/fontisan/woff_font.rb +488 -0
- data/lib/fontisan.rb +132 -0
- data/scripts/compare_stack_aware.rb +187 -0
- data/scripts/measure_optimization.rb +141 -0
- metadata +234 -4
data/Rakefile
CHANGED
|
@@ -9,67 +9,89 @@ require "rubocop/rake_task"
|
|
|
9
9
|
RuboCop::RakeTask.new
|
|
10
10
|
|
|
11
11
|
namespace :fixtures do
|
|
12
|
-
|
|
12
|
+
# Load centralized fixture configuration
|
|
13
|
+
require_relative "spec/support/fixture_fonts"
|
|
14
|
+
|
|
15
|
+
# Helper method to download a single file
|
|
16
|
+
def download_single_file(name, url, target_path)
|
|
17
|
+
require "open-uri"
|
|
18
|
+
|
|
19
|
+
puts "[fixtures:download] Downloading #{name}..."
|
|
20
|
+
FileUtils.mkdir_p(File.dirname(target_path))
|
|
21
|
+
|
|
22
|
+
URI.open(url) do |remote|
|
|
23
|
+
File.binwrite(target_path, remote.read)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
puts "[fixtures:download] #{name} downloaded successfully"
|
|
27
|
+
end
|
|
13
28
|
|
|
14
29
|
# Helper method to download and extract a font archive
|
|
15
30
|
def download_font(name, url, target_dir)
|
|
16
31
|
require "open-uri"
|
|
17
32
|
require "zip"
|
|
18
33
|
|
|
19
|
-
zip_file = "#{target_dir}/#{name}.zip"
|
|
20
|
-
|
|
21
34
|
puts "[fixtures:download] Downloading #{name}..."
|
|
22
35
|
FileUtils.mkdir_p(target_dir)
|
|
23
36
|
|
|
24
|
-
|
|
25
|
-
|
|
37
|
+
# Create a manual temp file path - OS will clean up temp files automatically
|
|
38
|
+
temp_path = File.join(Dir.tmpdir, "fontisan_#{name}_#{Process.pid}_#{rand(10000)}.zip")
|
|
39
|
+
|
|
40
|
+
# Download using IO.copy_stream for better Windows compatibility
|
|
41
|
+
URI.open(url, "rb") do |remote|
|
|
42
|
+
File.open(temp_path, "wb") do |file|
|
|
43
|
+
IO.copy_stream(remote, file)
|
|
44
|
+
end
|
|
26
45
|
end
|
|
27
46
|
|
|
28
47
|
puts "[fixtures:download] Extracting #{name}..."
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
48
|
+
|
|
49
|
+
# Open zip file and ensure it's fully closed before we're done
|
|
50
|
+
zip_file = Zip::File.open(temp_path)
|
|
51
|
+
begin
|
|
52
|
+
zip_file.each do |entry|
|
|
53
|
+
# Skip macOS metadata files and directories
|
|
54
|
+
next if entry.name.start_with?("__MACOSX/") || entry.name.include?("/._")
|
|
55
|
+
next if entry.directory?
|
|
56
|
+
|
|
57
|
+
# Ensure entry.name is relative by stripping leading slashes
|
|
58
|
+
relative_name = entry.name.sub(%r{^/+}, "")
|
|
59
|
+
|
|
60
|
+
dest_path = File.join(target_dir, relative_name)
|
|
32
61
|
FileUtils.mkdir_p(File.dirname(dest_path))
|
|
33
|
-
|
|
62
|
+
|
|
63
|
+
# Skip if file already exists
|
|
64
|
+
next if File.exist?(dest_path)
|
|
65
|
+
|
|
66
|
+
# Write the file content directly using binary mode
|
|
67
|
+
File.open(dest_path, "wb") do |file|
|
|
68
|
+
IO.copy_stream(entry.get_input_stream, file)
|
|
69
|
+
end
|
|
34
70
|
end
|
|
71
|
+
ensure
|
|
72
|
+
# Explicitly close the zip file to release file handle on Windows
|
|
73
|
+
zip_file.close if zip_file
|
|
35
74
|
end
|
|
36
75
|
|
|
37
|
-
|
|
76
|
+
# Temp file left in Dir.tmpdir - OS will clean it up automatically
|
|
77
|
+
|
|
38
78
|
puts "[fixtures:download] #{name} downloaded successfully"
|
|
39
79
|
rescue LoadError => e
|
|
40
80
|
warn "[fixtures:download] Error: Required gem not installed. Please run: gem install rubyzip"
|
|
41
81
|
raise e
|
|
42
82
|
end
|
|
43
83
|
|
|
44
|
-
#
|
|
45
|
-
|
|
46
|
-
fonts = {
|
|
47
|
-
"Libertinus" => {
|
|
48
|
-
url: "https://github.com/alerque/libertinus/releases/download/v7.051/Libertinus-7.051.zip",
|
|
49
|
-
target_dir: "#{fixtures_dir}/libertinus",
|
|
50
|
-
marker: "#{fixtures_dir}/libertinus/Libertinus-7.051/static/OTF/LibertinusSerif-Regular.otf",
|
|
51
|
-
},
|
|
52
|
-
"MonaSans" => {
|
|
53
|
-
url: "https://github.com/github/mona-sans/releases/download/v2.0/MonaSans.zip",
|
|
54
|
-
target_dir: "#{fixtures_dir}/MonaSans",
|
|
55
|
-
marker: "#{fixtures_dir}/MonaSans/MonaSans/variable/MonaSans[wdth,wght].ttf",
|
|
56
|
-
},
|
|
57
|
-
"NotoSerifCJK" => {
|
|
58
|
-
url: "https://github.com/notofonts/noto-cjk/releases/download/Serif2.003/01_NotoSerifCJK.ttc.zip",
|
|
59
|
-
target_dir: "#{fixtures_dir}/NotoSerifCJK",
|
|
60
|
-
marker: "#{fixtures_dir}/NotoSerifCJK/NotoSerifCJK.ttc",
|
|
61
|
-
},
|
|
62
|
-
"NotoSerifCJK-VF" => {
|
|
63
|
-
url: "https://github.com/notofonts/noto-cjk/releases/download/Serif2.003/02_NotoSerifCJK-OTF-VF.zip",
|
|
64
|
-
target_dir: "#{fixtures_dir}/NotoSerifCJK-VF",
|
|
65
|
-
marker: "#{fixtures_dir}/NotoSerifCJK-VF/Variable/OTC/NotoSerifCJK-VF.otf.ttc",
|
|
66
|
-
},
|
|
67
|
-
}
|
|
84
|
+
# Get font configurations from centralized source
|
|
85
|
+
fonts = FixtureFonts.rakefile_config
|
|
68
86
|
|
|
69
87
|
# Create file tasks for each font
|
|
70
88
|
fonts.each do |name, config|
|
|
71
89
|
file config[:marker] do
|
|
72
|
-
|
|
90
|
+
if config[:single_file]
|
|
91
|
+
download_single_file(name, config[:url], config[:marker])
|
|
92
|
+
else
|
|
93
|
+
download_font(name, config[:url], config[:target_dir])
|
|
94
|
+
end
|
|
73
95
|
end
|
|
74
96
|
end
|
|
75
97
|
|
|
@@ -78,12 +100,12 @@ namespace :fixtures do
|
|
|
78
100
|
|
|
79
101
|
desc "Clean downloaded fixtures"
|
|
80
102
|
task :clean do
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
103
|
+
fonts.values.map { |config| config[:target_dir] }.each do |path|
|
|
104
|
+
next unless File.exist?(path)
|
|
105
|
+
|
|
106
|
+
puts "[fixtures:clean] Removing #{path}..."
|
|
107
|
+
FileUtils.rm_rf(path)
|
|
108
|
+
puts "[fixtures:clean] Removed #{path}"
|
|
87
109
|
end
|
|
88
110
|
end
|
|
89
111
|
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'benchmark'
|
|
4
|
+
require 'fontisan'
|
|
5
|
+
|
|
6
|
+
# Load variable font
|
|
7
|
+
FONT_PATH = 'spec/fixtures/SourceSans3VF-Roman.otf'
|
|
8
|
+
|
|
9
|
+
unless File.exist?(FONT_PATH)
|
|
10
|
+
puts "Error: Test font not found at #{FONT_PATH}"
|
|
11
|
+
exit 1
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
font = Fontisan::FontLoader.load(FONT_PATH)
|
|
15
|
+
|
|
16
|
+
puts "=== Variable Font Parallel Performance ==="
|
|
17
|
+
puts "Font: #{FONT_PATH}"
|
|
18
|
+
puts
|
|
19
|
+
|
|
20
|
+
# Test coordinates
|
|
21
|
+
coords = 4.times.map { |i| { "wght" => 300 + i * 200 } }
|
|
22
|
+
puts "Generating #{coords.size} instances"
|
|
23
|
+
puts
|
|
24
|
+
|
|
25
|
+
# Sequential (1 thread)
|
|
26
|
+
seq_gen = Fontisan::Variation::ParallelGenerator.new(font, threads: 1)
|
|
27
|
+
seq_time = Benchmark.realtime do
|
|
28
|
+
seq_gen.generate_batch(coords)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Parallel (4 threads)
|
|
32
|
+
par_gen = Fontisan::Variation::ParallelGenerator.new(font, threads: 4)
|
|
33
|
+
par_time = Benchmark.realtime do
|
|
34
|
+
par_gen.generate_batch(coords)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
puts "Sequential (1 thread): #{format('%.3f', seq_time)}s"
|
|
38
|
+
puts "Parallel (4 threads): #{format('%.3f', par_time)}s"
|
|
39
|
+
puts "Speedup: #{format('%.2f', seq_time / par_time)}x"
|
|
40
|
+
puts
|
|
41
|
+
|
|
42
|
+
# Cache stats
|
|
43
|
+
cache = Fontisan::Variation::ThreadSafeCache.new
|
|
44
|
+
5.times { cache.fetch("test_#{rand(100)}") { rand } }
|
|
45
|
+
|
|
46
|
+
puts "Cache Statistics:"
|
|
47
|
+
puts cache.statistics.inspect
|