Class: Fontist::Import::Google::FontDatabase
- Inherits:
-
Object
- Object
- Fontist::Import::Google::FontDatabase
- Defined in:
- lib/fontist/import/google/font_database.rb
Overview
Database for merged font data from API sources
Generates v4 formulas (TTF static only) or v5 formulas (all formats)
Instance Attribute Summary collapse
-
#fonts ⇒ Object
readonly
Returns the value of attribute fonts.
-
#github_data ⇒ Object
readonly
Returns the value of attribute github_data.
-
#ttf_files ⇒ Object
readonly
Returns the value of attribute ttf_files.
-
#version ⇒ Object
readonly
Returns the value of attribute version.
-
#woff2_files ⇒ Object
readonly
Returns the value of attribute woff2_files.
Class Method Summary collapse
-
.build(api_key:, source_path: nil) ⇒ FontDatabase
Generic build method for backward compatibility Delegates to build_v4 by default.
-
.build_v4(api_key:, source_path:) ⇒ FontDatabase
Build database for v4 formulas (production).
-
.build_v5(api_key:, source_path:) ⇒ FontDatabase
Build database for v5 formulas (future).
Instance Method Summary collapse
-
#all_fonts ⇒ Object
Get all font families.
-
#build_fonts_v4(family) ⇒ Object
Build fonts from API variant data with full metadata (v4: TTF only).
-
#build_formula_v4(family) ⇒ Object
Build v4 formula from API data.
-
#build_resources_v4(family) ⇒ Object
Build resources from API URLs (v4: TTF only, no WOFF2).
-
#by_category(category) ⇒ Object
Filter fonts by category.
-
#categories ⇒ Object
Get all unique categories.
-
#create_import_source(family) ⇒ GoogleImportSource?
Create GoogleImportSource for a font family.
-
#current_commit_id ⇒ String?
Get current git commit from google/fonts repository.
-
#default_description(family) ⇒ Object
Generate default description.
-
#default_homepage(family) ⇒ Object
Generate default homepage.
-
#find_font_filename_for_variant(family, variant) ⇒ Object
Find filename for a variant.
-
#font_by_name(family_name) ⇒ Object
Find a specific font family by name.
-
#fonts_count ⇒ Object
Get count of fonts by type.
-
#fonts_with_both_formats ⇒ Object
Get fonts available in both formats.
-
#fonts_with_ttf ⇒ Object
Get fonts available in TTF format.
-
#fonts_with_woff2 ⇒ Object
Get fonts available in WOFF2 format.
-
#formula_name(family) ⇒ Object
Generate formula name from family name.
-
#initialize(ttf_data:, vf_data: nil, woff2_data: nil, github_data: nil, version: 4, source_path: nil) ⇒ FontDatabase
constructor
Initialize database with API data.
-
#last_modified_for(family) ⇒ String
Get last modified timestamp for a font family.
-
#save_formula(formula_hash, family_name, output_dir) ⇒ Object
Save formula to disk.
-
#save_formulas(output_dir, family_name: nil) ⇒ Object
Save formulas to disk.
-
#static_fonts_only ⇒ Object
Get only static fonts (fonts without axes).
-
#stringify_style(style) ⇒ Object
Convert style hash to string keys.
-
#to_formula(family_name) ⇒ Object
Generate formula for a font family.
-
#to_formulas ⇒ Object
Generate formulas for all fonts.
-
#ttf_files_for(family_name) ⇒ Object
Get TTF files for a specific font family.
-
#variable_fonts_only ⇒ Object
Get only variable fonts (fonts with axes).
-
#variant_to_type(variant) ⇒ Object
Convert API variant to style type.
-
#woff2_files_for(family_name) ⇒ Object
Get WOFF2 files for a specific font family.
Constructor Details
#initialize(ttf_data:, vf_data: nil, woff2_data: nil, github_data: nil, version: 4, source_path: nil) ⇒ FontDatabase
Initialize database with API data
97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/fontist/import/google/font_database.rb', line 97 def initialize(ttf_data:, vf_data: nil, woff2_data: nil, github_data: nil, version: 4, source_path: nil) @ttf_data = Array(ttf_data) @vf_data = Array(vf_data) @woff2_data = Array(woff2_data) @github_data_raw = Array(github_data) @version = version @source_path = source_path @ttf_files = {} @woff2_files = {} @github_index = index_github_data @github_data = @github_index # Expose indexed version @fonts = merge_data end |
Instance Attribute Details
#fonts ⇒ Object (readonly)
Returns the value of attribute fonts.
20 21 22 |
# File 'lib/fontist/import/google/font_database.rb', line 20 def fonts @fonts end |
#github_data ⇒ Object (readonly)
Returns the value of attribute github_data.
20 21 22 |
# File 'lib/fontist/import/google/font_database.rb', line 20 def github_data @github_data end |
#ttf_files ⇒ Object (readonly)
Returns the value of attribute ttf_files.
20 21 22 |
# File 'lib/fontist/import/google/font_database.rb', line 20 def ttf_files @ttf_files end |
#version ⇒ Object (readonly)
Returns the value of attribute version.
20 21 22 |
# File 'lib/fontist/import/google/font_database.rb', line 20 def version @version end |
#woff2_files ⇒ Object (readonly)
Returns the value of attribute woff2_files.
20 21 22 |
# File 'lib/fontist/import/google/font_database.rb', line 20 def woff2_files @woff2_files end |
Class Method Details
.build(api_key:, source_path: nil) ⇒ FontDatabase
Generic build method for backward compatibility Delegates to build_v4 by default
79 80 81 82 83 84 85 86 87 |
# File 'lib/fontist/import/google/font_database.rb', line 79 def self.build(api_key:, source_path: nil) if source_path build_v4(api_key: api_key, source_path: source_path) else # Build without GitHub data ttf_data = DataSources::Ttf.new(api_key: api_key).fetch new(ttf_data: ttf_data, version: 4, source_path: nil) end end |
.build_v4(api_key:, source_path:) ⇒ FontDatabase
Build database for v4 formulas (production)
V4 Requirements:
-
TTF format ONLY (no WOFF2)
-
Static fonts ONLY (exclude variable fonts)
-
OFL.txt license from GitHub repository
-
Complete metadata from Fontisan
33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/fontist/import/google/font_database.rb', line 33 def self.build_v4(api_key:, source_path:) ttf_data = DataSources::Ttf.new(api_key: api_key).fetch # NO VF endpoint, NO WOFF2 endpoint for v4 github_data = DataSources::Github.new(source_path: source_path).fetch new( ttf_data: ttf_data, github_data: github_data, version: 4, source_path: source_path, ) end |
.build_v5(api_key:, source_path:) ⇒ FontDatabase
Build database for v5 formulas (future)
V5 will support:
-
TTF + WOFF2 formats
-
Static + Variable fonts
-
Enhanced ‘provides` attribute
-
Per-file resources
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/fontist/import/google/font_database.rb', line 57 def self.build_v5(api_key:, source_path:) ttf_data = DataSources::Ttf.new(api_key: api_key).fetch vf_data = DataSources::Vf.new(api_key: api_key).fetch woff2_data = DataSources::Woff2.new(api_key: api_key).fetch github_data = DataSources::Github.new(source_path: source_path).fetch new( ttf_data: ttf_data, vf_data: vf_data, woff2_data: woff2_data, github_data: github_data, version: 5, source_path: source_path, ) end |
Instance Method Details
#all_fonts ⇒ Object
Get all font families
113 114 115 |
# File 'lib/fontist/import/google/font_database.rb', line 113 def all_fonts @fonts.values end |
#build_fonts_v4(family) ⇒ Object
Build fonts from API variant data with full metadata (v4: TTF only)
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 |
# File 'lib/fontist/import/google/font_database.rb', line 283 def build_fonts_v4(family) parsed_fonts = [] # V4: Download and parse ONLY TTF files to get complete metadata @ttf_files[family.family]&.each_value do |url| sleep(0.05) # Throttle API requests begin # Download font downloaded = Fontist::Utils::Downloader.download(url) # Parse with Fontisan = Fontist::Import::FontMetadataExtractor.new(downloaded.path).extract # V4: Skip variable fonts if .is_variable next end # Get filename from URL filename = url.split("/").last # Create style with complete metadata style_data = { family_name: .family_name, type: .subfamily_name, full_name: .full_name, post_script_name: .postscript_name, version: .version, copyright: .copyright, font: filename, } # Add preferred names if present if .preferred_family_name style_data[:preferred_family_name] = .preferred_family_name end if .preferred_subfamily_name style_data[:preferred_type] = .preferred_subfamily_name end # Add description if present if .description style_data[:description] = .description end parsed_fonts << style_data rescue StandardError => e warn "Warning: Failed to download/parse #{url}: #{e.}" end end return [] if parsed_fonts.empty? # Group by subfamily (family_name from font, not API family) fonts_by_subfamily = parsed_fonts.group_by { |f| f[:family_name] } fonts_by_subfamily.map do |subfamily_name, styles| { "name" => subfamily_name, "styles" => styles.map { |s| stringify_style(s) }, } end end |
#build_formula_v4(family) ⇒ Object
Build v4 formula from API data
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 |
# File 'lib/fontist/import/google/font_database.rb', line 205 def build_formula_v4(family) github_family = @github_index[family.family] # Read license from GitHub if available license_url, license_text = if github_family&.license_text [ "https://scripts.sil.org/OFL", github_family.license_text, ] else [ "https://scripts.sil.org/OFL", "SIL Open Font License v1.1", ] end # Build fonts first to get copyright fonts_data = build_fonts_v4(family) # Extract copyright from first font style, or use license_text as fallback copyright = fonts_data.dig(0, "styles", 0, "copyright") || github_family&.license_text # Use GitHub description if available description = github_family&.description || default_description(family) # Create import_source if available import_source = create_import_source(family) formula = { name: formula_name(family), description: description, homepage: default_homepage(family), resources: build_resources_v4(family), fonts: fonts_data, extract: {}, copyright: copyright, license_url: license_url, license: license_text, # Changed from open_license open_license: license_text, } # Add import_source if available formula[:import_source] = import_source if import_source formula.compact end |
#build_resources_v4(family) ⇒ Object
Build resources from API URLs (v4: TTF only, no WOFF2)
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 |
# File 'lib/fontist/import/google/font_database.rb', line 254 def build_resources_v4(family) files = [] # V4: Collect ONLY TTF URLs from API (no WOFF2) @ttf_files[family.family]&.each_value do |url| files << url end return nil if files.empty? # V4: Always use "ttf" format (no variable fonts in v4) format = "ttf" resource = { "source" => "google", "family" => family.family, "files" => files, "format" => format, } # Add variable_axes if present if family.variable_font? && family.axes resource["variable_axes"] = family.axes.map(&:tag) end { family.family => resource } end |
#by_category(category) ⇒ Object
Filter fonts by category
123 124 125 |
# File 'lib/fontist/import/google/font_database.rb', line 123 def by_category(category) all_fonts.select { |font| font.category == category } end |
#categories ⇒ Object
Get all unique categories
147 148 149 |
# File 'lib/fontist/import/google/font_database.rb', line 147 def categories all_fonts.map(&:category).compact.uniq.sort end |
#create_import_source(family) ⇒ GoogleImportSource?
Create GoogleImportSource for a font family
441 442 443 444 445 446 447 448 449 450 451 452 |
# File 'lib/fontist/import/google/font_database.rb', line 441 def create_import_source(family) # Only create import_source if we have a commit_id commit = current_commit_id return nil unless commit Fontist::GoogleImportSource.new( commit_id: commit, api_version: "v1", last_modified: last_modified_for(family), family_id: family.family.downcase.tr(" ", "_"), ) end |
#current_commit_id ⇒ String?
Get current git commit from google/fonts repository
418 419 420 421 422 423 424 425 426 |
# File 'lib/fontist/import/google/font_database.rb', line 418 def current_commit_id return @commit_id if defined?(@commit_id) @commit_id = if @source_path && File.directory?(@source_path) get_git_commit(@source_path) end @commit_id end |
#default_description(family) ⇒ Object
Generate default description
386 387 388 |
# File 'lib/fontist/import/google/font_database.rb', line 386 def default_description(family) "#{family.family} font family" end |
#default_homepage(family) ⇒ Object
Generate default homepage
391 392 393 |
# File 'lib/fontist/import/google/font_database.rb', line 391 def default_homepage(family) "https://fonts.google.com/specimen/#{family.family.gsub(/\s+/, '+')}" end |
#find_font_filename_for_variant(family, variant) ⇒ Object
Find filename for a variant
357 358 359 360 361 362 363 364 365 366 367 |
# File 'lib/fontist/import/google/font_database.rb', line 357 def find_font_filename_for_variant(family, variant) # Try TTF first url = @ttf_files[family.family]&.[](variant) return url.split("/").last if url # Try WOFF2 url = @woff2_files[family.family]&.[](variant) return url.split("/").last if url nil end |
#font_by_name(family_name) ⇒ Object
Find a specific font family by name
118 119 120 |
# File 'lib/fontist/import/google/font_database.rb', line 118 def font_by_name(family_name) @fonts[family_name] end |
#fonts_count ⇒ Object
Get count of fonts by type
138 139 140 141 142 143 144 |
# File 'lib/fontist/import/google/font_database.rb', line 138 def fonts_count { total: all_fonts.count, variable: variable_fonts_only.count, static: static_fonts_only.count, } end |
#fonts_with_both_formats ⇒ Object
Get fonts available in both formats
162 163 164 165 166 |
# File 'lib/fontist/import/google/font_database.rb', line 162 def fonts_with_both_formats all_fonts.select do |font| @ttf_files.key?(font.family) && @woff2_files.key?(font.family) end end |
#fonts_with_ttf ⇒ Object
Get fonts available in TTF format
152 153 154 |
# File 'lib/fontist/import/google/font_database.rb', line 152 def fonts_with_ttf all_fonts.select { |font| @ttf_files.key?(font.family) } end |
#fonts_with_woff2 ⇒ Object
Get fonts available in WOFF2 format
157 158 159 |
# File 'lib/fontist/import/google/font_database.rb', line 157 def fonts_with_woff2 all_fonts.select { |font| @woff2_files.key?(font.family) } end |
#formula_name(family) ⇒ Object
Generate formula name from family name
381 382 383 |
# File 'lib/fontist/import/google/font_database.rb', line 381 def formula_name(family) family.family.downcase.gsub(/\s+/, "_") end |
#last_modified_for(family) ⇒ String
Get last modified timestamp for a font family
432 433 434 435 |
# File 'lib/fontist/import/google/font_database.rb', line 432 def last_modified_for(family) # Use last_modified from API metadata if available family.last_modified || Time.now.utc.iso8601 end |
#save_formula(formula_hash, family_name, output_dir) ⇒ Object
Save formula to disk
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 |
# File 'lib/fontist/import/google/font_database.rb', line 396 def save_formula(formula_hash, family_name, output_dir) FileUtils.mkdir_p(output_dir) # Google Fonts formulas always use simple filenames # (Google Fonts is a live service, always pointing to latest version) base_name = family_name.downcase.gsub(/\s+/, "_") filename = "#{base_name}.yml" path = File.join(output_dir, filename) # Use HashHelper to convert keys to strings (preserves import_source object) require_relative "../helpers/hash_helper" formula_with_string_keys = Helpers::HashHelper.stringify_keys(formula_hash) File.write(path, YAML.dump(formula_with_string_keys)) path end |
#save_formulas(output_dir, family_name: nil) ⇒ Object
Save formulas to disk
192 193 194 195 196 197 198 199 200 201 202 |
# File 'lib/fontist/import/google/font_database.rb', line 192 def save_formulas(output_dir, family_name: nil) families = family_name ? [font_by_name(family_name)] : all_fonts families = families.compact families.map do |family| formula = to_formula(family.family) next unless formula save_formula(formula, family.family, output_dir) end.compact end |
#static_fonts_only ⇒ Object
Get only static fonts (fonts without axes)
133 134 135 |
# File 'lib/fontist/import/google/font_database.rb', line 133 def static_fonts_only all_fonts.reject(&:variable_font?) end |
#stringify_style(style) ⇒ Object
Convert style hash to string keys
350 351 352 353 354 |
# File 'lib/fontist/import/google/font_database.rb', line 350 def stringify_style(style) style.transform_keys(&:to_s).transform_values do |v| v.is_a?(Symbol) ? v.to_s : v end end |
#to_formula(family_name) ⇒ Object
Generate formula for a font family
179 180 181 182 183 184 |
# File 'lib/fontist/import/google/font_database.rb', line 179 def to_formula(family_name) family = font_by_name(family_name) return nil unless family build_formula_v4(family) end |
#to_formulas ⇒ Object
Generate formulas for all fonts
187 188 189 |
# File 'lib/fontist/import/google/font_database.rb', line 187 def to_formulas all_fonts.map { |f| to_formula(f.family) }.compact end |
#ttf_files_for(family_name) ⇒ Object
Get TTF files for a specific font family
169 170 171 |
# File 'lib/fontist/import/google/font_database.rb', line 169 def ttf_files_for(family_name) @ttf_files[family_name] end |
#variable_fonts_only ⇒ Object
Get only variable fonts (fonts with axes)
128 129 130 |
# File 'lib/fontist/import/google/font_database.rb', line 128 def variable_fonts_only all_fonts.select(&:variable_font?) end |
#variant_to_type(variant) ⇒ Object
Convert API variant to style type
370 371 372 373 374 375 376 377 378 |
# File 'lib/fontist/import/google/font_database.rb', line 370 def variant_to_type(variant) case variant when "regular" then "Regular" when "italic" then "Italic" when /^(\d+)italic$/ then "#{$1} Italic" when /^(\d+)$/ then variant else variant.capitalize end end |
#woff2_files_for(family_name) ⇒ Object
Get WOFF2 files for a specific font family
174 175 176 |
# File 'lib/fontist/import/google/font_database.rb', line 174 def woff2_files_for(family_name) @woff2_files[family_name] end |