Class: Fontist::Import::Google::Models::Metadata

Inherits:
Lutaml::Model::Serializable
  • Object
show all
Defined in:
lib/fontist/import/google/models/metadata.rb

Overview

Rich domain model for Google Fonts metadata from METADATA.pb

This class represents complete font family metadata with:

  • Validation methods

  • Business logic for font classification

  • Query methods for font properties

  • Transformation methods for formula generation

Examples:

Basic usage

 = Metadata.new(name: "Roboto", designer: "Google")
.valid? # => true
.variable_font? # => false

With validation

 = Metadata.new(name: "")
.validate! # raises ValidationError

Loading from file

 = Metadata.from_file("/path/to/METADATA.pb")

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.from_content(content) ⇒ Metadata

Load metadata from content string

Parameters:

  • content (String)

    METADATA.pb file content

Returns:

Raises:

  • (ParseError)

    if content cannot be parsed



89
90
91
92
93
94
95
# File 'lib/fontist/import/google/models/metadata.rb', line 89

def self.from_content(content)
  require "unibuf"
  require_relative "../metadata_adapter"

  unibuf_message = Unibuf.parse_textproto(content)
  MetadataAdapter.adapt(unibuf_message)
end

.from_file(file_path) ⇒ Metadata

Load metadata from METADATA.pb file

Parameters:

  • file_path (String)

    Path to METADATA.pb file

Returns:

Raises:

  • (ParseError)

    if file cannot be parsed



76
77
78
79
80
81
82
# File 'lib/fontist/import/google/models/metadata.rb', line 76

def self.from_file(file_path)
  require "unibuf"
  require_relative "../metadata_adapter"

  unibuf_message = Unibuf.parse_textproto_file(file_path)
  MetadataAdapter.adapt(unibuf_message)
end

Instance Method Details

#==(other) ⇒ Boolean Also known as: eql?

Compare with another metadata object

Parameters:

  • other (Metadata)

    other metadata object

Returns:

  • (Boolean)

    true if same family



412
413
414
415
416
# File 'lib/fontist/import/google/models/metadata.rb', line 412

def ==(other)
  return false unless other.is_a?(Metadata)

  name == other.name && designer == other.designer
end

#axis_countInteger

Get number of variable font axes

Returns:

  • (Integer)

    count of axes (0 for static fonts)



201
202
203
# File 'lib/fontist/import/google/models/metadata.rb', line 201

def axis_count
  axes_array.count
end

#axis_tagsArray<String>

Get all variable font axis tags

Returns:

  • (Array<String>)

    array of axis tags (e.g., [“wght”, “wdth”])



187
188
189
# File 'lib/fontist/import/google/models/metadata.rb', line 187

def axis_tags
  axes_array.map(&:tag)
end

#bold_fontFontFileMetadata?

Get bold font

Returns:



268
269
270
# File 'lib/fontist/import/google/models/metadata.rb', line 268

def bold_font
  find_font(style: "normal", weight: 700)
end

#complete?Boolean

Check if metadata is complete (has all optional fields filled)

Returns:

  • (Boolean)

    true if has source, axes, languages, etc.



160
161
162
163
164
# File 'lib/fontist/import/google/models/metadata.rb', line 160

def complete?
  !source.nil? &&
    !subsets.nil? && !subsets.empty? &&
    (!variable_font? || !axes.nil?)
end

#filenamesArray<String>

Get all font filenames

Returns:

  • (Array<String>)

    array of font filenames



180
181
182
# File 'lib/fontist/import/google/models/metadata.rb', line 180

def filenames
  fonts_array.map(&:filename)
end

#find_axis(tag) ⇒ AxisMetadata?

Find axis by tag

Parameters:

  • tag (String)

    axis tag (e.g., “wght”, “wdth”)

Returns:



306
307
308
# File 'lib/fontist/import/google/models/metadata.rb', line 306

def find_axis(tag)
  axes_array.find { |a| a.tag == tag }
end

#find_font(style:, weight:) ⇒ FontFileMetadata?

Find font by style and weight

Parameters:

  • style (String)

    font style (“normal”, “italic”)

  • weight (Integer)

    font weight (100-900)

Returns:



254
255
256
# File 'lib/fontist/import/google/models/metadata.rb', line 254

def find_font(style:, weight:)
  fonts_array.find { |f| f.style == style && f.weight == weight }
end

#font_countInteger

Get number of font files

Returns:

  • (Integer)

    count of font files



194
195
196
# File 'lib/fontist/import/google/models/metadata.rb', line 194

def font_count
  fonts_array.count
end

#font_stylesArray<String>

Get all font styles

Returns:

  • (Array<String>)

    unique font styles



282
283
284
# File 'lib/fontist/import/google/models/metadata.rb', line 282

def font_styles
  fonts_array.map(&:style).uniq
end

#font_weightsArray<Integer>

Get all font weights

Returns:

  • (Array<Integer>)

    unique font weights



289
290
291
# File 'lib/fontist/import/google/models/metadata.rb', line 289

def font_weights
  fonts_array.map(&:weight).uniq.sort
end

#has_italics?Boolean

Check if has italic variants

Returns:

  • (Boolean)

    true if has any italic fonts



296
297
298
# File 'lib/fontist/import/google/models/metadata.rb', line 296

def has_italics?
  fonts_array.any? { |f| f.style == "italic" }
end

#has_registry_overrides?Boolean

Check if has registry overrides

Returns:

  • (Boolean)

    true if has any overrides



365
366
367
# File 'lib/fontist/import/google/models/metadata.rb', line 365

def has_registry_overrides?
  !registry_default_overrides.nil? && !registry_default_overrides.empty?
end

#hashInteger

Hash code for using as hash key

Returns:

  • (Integer)

    hash code



421
422
423
# File 'lib/fontist/import/google/models/metadata.rb', line 421

def hash
  [name, designer].hash
end

#italic_fontFontFileMetadata?

Get italic font

Returns:



275
276
277
# File 'lib/fontist/import/google/models/metadata.rb', line 275

def italic_font
  find_font(style: "italic", weight: 400)
end

#language_countInteger

Get number of supported languages

Returns:

  • (Integer)

    count of languages



208
209
210
# File 'lib/fontist/import/google/models/metadata.rb', line 208

def language_count
  languages_array.count
end

#license_nameString

Get license name

Returns:

  • (String)

    human-readable license name



238
239
240
241
242
243
244
245
# File 'lib/fontist/import/google/models/metadata.rb', line 238

def license_name
  case license
  when "OFL" then "SIL Open Font License"
  when "APACHE" then "Apache License 2.0"
  when "UFL" then "Ubuntu Font License"
  else license
  end
end

#minimal?Boolean

Check if metadata is minimal (only required fields)

Returns:

  • (Boolean)

    true if only has required fields



169
170
171
172
173
# File 'lib/fontist/import/google/models/metadata.rb', line 169

def minimal?
  source.nil? &&
    (subsets.nil? || subsets.empty?) &&
    (languages.nil? || languages.empty?)
end

#noto_font?Boolean

Check if font is a Noto font

Returns:

  • (Boolean)

    true if is_noto flag is set or name starts with “Noto”



153
154
155
# File 'lib/fontist/import/google/models/metadata.rb', line 153

def noto_font?
  is_noto == true || name&.start_with?("Noto")
end

#open_license?Boolean

Check if license is open source

Returns:

  • (Boolean)

    true if OFL or Apache license



224
225
226
# File 'lib/fontist/import/google/models/metadata.rb', line 224

def open_license?
  %w[OFL APACHE].include?(license)
end

#registry_override(axis_tag) ⇒ Float?

Get registry default override for axis

Parameters:

  • axis_tag (String)

    axis tag

Returns:

  • (Float, nil)

    override value or nil



356
357
358
359
360
# File 'lib/fontist/import/google/models/metadata.rb', line 356

def registry_override(axis_tag)
  return nil unless registry_default_overrides

  registry_default_overrides[axis_tag]
end

#regular_fontFontFileMetadata?

Get regular/normal font

Returns:



261
262
263
# File 'lib/fontist/import/google/models/metadata.rb', line 261

def regular_font
  find_font(style: "normal", weight: 400)
end

#requires_license_agreement?Boolean

Check if license requires acceptance

Returns:

  • (Boolean)

    true if UFL or other non-open license



231
232
233
# File 'lib/fontist/import/google/models/metadata.rb', line 231

def requires_license_agreement?
  !open_license?
end

#slant_axisAxisMetadata?

Get slant axis

Returns:



327
328
329
# File 'lib/fontist/import/google/models/metadata.rb', line 327

def slant_axis
  find_axis("slnt")
end

#static_font?Boolean

Check if this is a static font

Returns:

  • (Boolean)

    true if has no variable font axes



146
147
148
# File 'lib/fontist/import/google/models/metadata.rb', line 146

def static_font?
  !variable_font?
end

#subset_countInteger

Get number of supported subsets

Returns:

  • (Integer)

    count of subsets



215
216
217
# File 'lib/fontist/import/google/models/metadata.rb', line 215

def subset_count
  subsets_array.count
end

#to_formula_hashHash

Convert to hash for formula generation

Returns:

  • (Hash)

    hash representation suitable for formulas



374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
# File 'lib/fontist/import/google/models/metadata.rb', line 374

def to_formula_hash
  {
    name: name,
    designer: designer,
    license: license,
    license_url: source&.repository_url,
    open_license: open_license?,
    category: category,
    date_added: date_added,
    fonts: fonts_array.map(&:to_h),
    subsets: subsets_array,
    axes: axes_array.map(&:to_h),
    source: source&.to_h,
    registry_default_overrides: registry_default_overrides,
    languages: languages_array,
    primary_script: primary_script,
  }
end

#to_sString

Convert to display format

Returns:

  • (String)

    human-readable representation



396
397
398
399
400
401
402
403
404
# File 'lib/fontist/import/google/models/metadata.rb', line 396

def to_s
  parts = ["#{name} by #{designer}"]
  parts << "(Variable Font)" if variable_font?
  parts << "(Noto)" if noto_font?
  parts << "- #{font_count} files"
  parts << "- #{axis_count} axes" if variable_font?
  parts << "- #{language_count} languages" if language_count.positive?
  parts.join(" ")
end

#valid?Boolean

Check if metadata is valid

Returns:

  • (Boolean)

    true if valid, false otherwise



113
114
115
# File 'lib/fontist/import/google/models/metadata.rb', line 113

def valid?
  validation_errors.empty?
end

#validate!true

Validate metadata completeness and correctness

Returns:

  • (true)

    if valid

Raises:



103
104
105
106
107
108
# File 'lib/fontist/import/google/models/metadata.rb', line 103

def validate!
  errors = validation_errors
  raise ValidationError, errors.join(", ") unless errors.empty?

  true
end

#validation_errorsArray<String>

Get all validation errors

Returns:

  • (Array<String>)

    array of error messages



120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/fontist/import/google/models/metadata.rb', line 120

def validation_errors
  errors = []
  errors << "name is required" if name.nil? || name.empty?
  errors << "designer is required" if designer.nil? || designer.empty?
  errors << "license is required" if license.nil? || license.empty?
  errors << "category is required" if category.nil? || category.empty?
  errors << "date_added is required" if date_added.nil? || date_added.empty?
  errors << "at least one font file is required" if fonts.nil? || fonts_array.empty?
  errors << "invalid license type" unless valid_license?
  errors << "invalid category" unless valid_category?
  errors << "invalid date format" unless valid_date_format?
  errors
end

#variable_font?Boolean

Check if this is a variable font

Returns:

  • (Boolean)

    true if has variable font axes



139
140
141
# File 'lib/fontist/import/google/models/metadata.rb', line 139

def variable_font?
  !axes.nil? && !axes_array.empty?
end

#variable_slant?Boolean

Check if has slant/italic axis

Returns:

  • (Boolean)

    true if has slnt axis



348
349
350
# File 'lib/fontist/import/google/models/metadata.rb', line 348

def variable_slant?
  !slant_axis.nil?
end

#variable_weight?Boolean

Check if has weight axis

Returns:

  • (Boolean)

    true if has wght axis



334
335
336
# File 'lib/fontist/import/google/models/metadata.rb', line 334

def variable_weight?
  !weight_axis.nil?
end

#variable_width?Boolean

Check if has width axis

Returns:

  • (Boolean)

    true if has wdth axis



341
342
343
# File 'lib/fontist/import/google/models/metadata.rb', line 341

def variable_width?
  !width_axis.nil?
end

#weight_axisAxisMetadata?

Get weight axis

Returns:



313
314
315
# File 'lib/fontist/import/google/models/metadata.rb', line 313

def weight_axis
  find_axis("wght")
end

#width_axisAxisMetadata?

Get width axis

Returns:



320
321
322
# File 'lib/fontist/import/google/models/metadata.rb', line 320

def width_axis
  find_axis("wdth")
end