Class: Fontist::Formula

Inherits:
Lutaml::Model::Serializable
  • Object
show all
Defined in:
lib/fontist/formula.rb

Constant Summary collapse

NAMESPACES =
{
  "sil" => "SIL",
  "macos" => "macOS",
}.freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.allObject



123
124
125
126
127
128
129
# File 'lib/fontist/formula.rb', line 123

def self.all
  formulas = Dir[Fontist.formulas_path.join("**/*.yml").to_s].map do |path|
    Formula.from_file(path)
  end.compact

  FormulaCollection.new(formulas)
end

.all_keysObject



131
132
133
134
135
# File 'lib/fontist/formula.rb', line 131

def self.all_keys
  Dir[Fontist.formulas_path.join("**/*.yml").to_s].map do |path|
    path.sub("#{Fontist.formulas_path}/", "").sub(".yml", "")
  end
end

.find(font_name) ⇒ Object



137
138
139
# File 'lib/fontist/formula.rb', line 137

def self.find(font_name)
  Indexes::FontIndex.from_file.load_formulas(font_name).first
end

.find_by_font_file(font_file) ⇒ Object



188
189
190
191
192
193
194
195
# File 'lib/fontist/formula.rb', line 188

def self.find_by_font_file(font_file)
  key = Indexes::FilenameIndex.from_file
    .load_index_formulas(File.basename(font_file))
    .flat_map(&:name)
    .first

  find_by_key(key)
end

.find_by_key(key) ⇒ Object



171
172
173
174
175
176
# File 'lib/fontist/formula.rb', line 171

def self.find_by_key(key)
  path = Fontist.formulas_path.join("#{key}.yml")
  return unless File.exist?(path)

  from_file(path)
end

.find_by_key_or_name(name) ⇒ Object



167
168
169
# File 'lib/fontist/formula.rb', line 167

def self.find_by_key_or_name(name)
  find_by_key(name) || find_by_name(name)
end

.find_by_name(name) ⇒ Object



178
179
180
181
182
# File 'lib/fontist/formula.rb', line 178

def self.find_by_name(name)
  key = name_to_key(name)

  find_by_key(key)
end

.find_fonts(font_name) ⇒ Object



145
146
147
148
149
150
151
152
153
# File 'lib/fontist/formula.rb', line 145

def self.find_fonts(font_name)
  formulas = Indexes::FontIndex.from_file.load_formulas(font_name)

  formulas.map do |formula|
    formula.all_fonts.select do |f|
      f.name.casecmp?(font_name)
    end
  end.flatten
end

.find_many(font_name) ⇒ Object



141
142
143
# File 'lib/fontist/formula.rb', line 141

def self.find_many(font_name)
  Indexes::FontIndex.from_file.load_formulas(font_name)
end

.find_styles(font_name, style_name) ⇒ Object



155
156
157
158
159
160
161
162
163
164
165
# File 'lib/fontist/formula.rb', line 155

def self.find_styles(font_name, style_name)
  formulas = Indexes::FontIndex.from_file.load_formulas(font_name)

  formulas.map do |formula|
    formula.all_fonts.map do |f|
      f.styles.select do |s|
        f.name.casecmp?(font_name) && s.type.casecmp?(style_name)
      end
    end
  end.flatten
end

.from_file(path) ⇒ Object



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/fontist/formula.rb', line 197

def self.from_file(path)
  unless File.exist?(path)
    raise Fontist::Errors::FormulaNotFoundError,
          "Formula file not found: #{path}"
  end

  content = File.read(path)

  from_yaml(content).tap do |formula|
    formula.path = path
    formula.name = titleize(formula.key_from_path) if formula.name.nil?
  end
rescue Lutaml::Model::Error, TypeError, ArgumentError => e
  # Handle schema mismatch errors (e.g., nil values in polymorphic attributes)
  Fontist.ui.error("WARN: Could not load formula #{path}: #{e.message}")
  nil
end

.name_to_key(name) ⇒ Object



184
185
186
# File 'lib/fontist/formula.rb', line 184

def self.name_to_key(name)
  name.downcase.gsub(" ", "_")
end

.titleize(str) ⇒ Object



215
216
217
218
219
# File 'lib/fontist/formula.rb', line 215

def self.titleize(str)
  str.split("/").map do |part|
    part.tr("_", " ").split.map(&:capitalize).join(" ")
  end.join("/")
end

.update_formulas_repoObject



119
120
121
# File 'lib/fontist/formula.rb', line 119

def self.update_formulas_repo
  Update.call
end

Instance Method Details

#all_fontsObject



368
369
370
# File 'lib/fontist/formula.rb', line 368

def all_fonts
  Array(fonts) + collection_fonts
end

#collection_fontsObject



372
373
374
375
376
377
378
379
380
381
382
383
384
385
# File 'lib/fontist/formula.rb', line 372

def collection_fonts
  Array(font_collections).flat_map do |c|
    { "font" => c.filename,
      "source_font" => c.source_filename }

    c.fonts.flat_map do |f|
      f.styles.each do |s|
        s.font = c.filename
        s.source_font = c.source_filename
      end
      f
    end
  end
end

#compatible_with_current_platform?Boolean

Returns:

  • (Boolean)


246
247
248
249
250
251
252
253
# File 'lib/fontist/formula.rb', line 246

def compatible_with_current_platform?
  return true unless macos_import?

  current_macos = Utils::System.macos_version
  return true unless current_macos

  import_source.compatible_with_macos?(current_macos)
end

#compatible_with_platform?(platform = nil) ⇒ Boolean

Returns:

  • (Boolean)


261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'lib/fontist/formula.rb', line 261

def compatible_with_platform?(platform = nil)
  target = platform || Utils::System.user_os.to_s

  # No platform restrictions = compatible with all
  return true if platforms.nil? || platforms.empty?

  # Check if platform matches - support both exact matches and prefixed matches
  # e.g., "macos" matches "macos", "macos-font7", "macos-font8"
  platform_matches = platforms.any? do |p|
    p == target || p.start_with?("#{target}-")
  end

  return false unless platform_matches

  # For macOS platform-tagged formulas, check framework support
  if target == "macos" && macos_import?
    current_macos = Utils::System.macos_version
    return true unless current_macos

    # Check if framework exists for this macOS version
    framework = Utils::System.catalog_version_for_macos
    if framework.nil?
      require_relative "macos_framework_metadata"
      raise Errors::UnsupportedMacOSVersionError.new(
        current_macos,
        MacosFrameworkMetadata.,
      )
    end

    return import_source.compatible_with_macos?(current_macos)
  end

  true
end

#downloadable?Boolean

Returns:

  • (Boolean)


225
226
227
# File 'lib/fontist/formula.rb', line 225

def downloadable?
  !resources.nil? && !resources.empty?
end

#file_sizeObject



350
351
352
353
354
# File 'lib/fontist/formula.rb', line 350

def file_size
  return nil if resources.nil? || resources.empty?

  resources.first.file_size
end

#font_by_name(name) ⇒ Object



356
357
358
359
360
# File 'lib/fontist/formula.rb', line 356

def font_by_name(name)
  all_fonts.find do |font|
    font.name.casecmp?(name)
  end
end

#fonts_by_name(name) ⇒ Object



362
363
364
365
366
# File 'lib/fontist/formula.rb', line 362

def fonts_by_name(name)
  all_fonts.select do |font|
    font.name.casecmp?(name)
  end
end

#google_import?Boolean

Returns:

  • (Boolean)


234
235
236
# File 'lib/fontist/formula.rb', line 234

def google_import?
  import_source.is_a?(GoogleImportSource)
end

#keyObject



331
332
333
# File 'lib/fontist/formula.rb', line 331

def key
  @key ||= key_from_path
end

#key_from_pathObject



335
336
337
338
339
340
# File 'lib/fontist/formula.rb', line 335

def key_from_path
  return "" unless @path

  escaped = Regexp.escape("#{Fontist.formulas_path}/")
  @path.sub(Regexp.new("^#{escaped}"), "").sub(/\.yml$/, "").to_s
end

#licenseObject



342
343
344
# File 'lib/fontist/formula.rb', line 342

def license
  open_license || requires_license_agreement
end

#license_required?Boolean

Returns:

  • (Boolean)


346
347
348
# File 'lib/fontist/formula.rb', line 346

def license_required?
  requires_license_agreement ? true : false
end

#macos_import?Boolean

Convenience methods for import source type checking

Returns:

  • (Boolean)


230
231
232
# File 'lib/fontist/formula.rb', line 230

def macos_import?
  import_source.is_a?(MacosImportSource)
end

#manual?Boolean

Returns:

  • (Boolean)


221
222
223
# File 'lib/fontist/formula.rb', line 221

def manual?
  !downloadable?
end

#manual_formula?Boolean

Returns:

  • (Boolean)


242
243
244
# File 'lib/fontist/formula.rb', line 242

def manual_formula?
  import_source.nil?
end

#platform_restriction_messageObject



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
# File 'lib/fontist/formula.rb', line 296

def platform_restriction_message
  return nil if compatible_with_platform?

  current = Utils::System.user_os

  # Build base message
  message = "Font '#{name}' is only available for: #{platforms.join(', ')}. "
  message += "Your current platform is: #{current}."

  # Add version information for macOS using import source
  if current == :macos && macos_import?
    current_version = Utils::System.macos_version
    if current_version
      message += " Your macOS version is: #{current_version}."
    end

    min_version = import_source.min_macos_version
    max_version = import_source.max_macos_version

    if min_version && max_version
      message += " This font requires macOS #{min_version} to #{max_version}."
    elsif min_version
      message += " This font requires macOS #{min_version} or later."
    elsif max_version
      message += " This font requires macOS #{max_version} or earlier."
    end
  end

  "#{message} This font cannot be installed on your system."
end

#requires_system_installation?Boolean

Returns:

  • (Boolean)


327
328
329
# File 'lib/fontist/formula.rb', line 327

def requires_system_installation?
  source == "apple_cdn" && platforms&.include?("macos")
end

#sil_import?Boolean

Returns:

  • (Boolean)


238
239
240
# File 'lib/fontist/formula.rb', line 238

def sil_import?
  import_source.is_a?(SilImportSource)
end

#sourceObject



255
256
257
258
259
# File 'lib/fontist/formula.rb', line 255

def source
  return nil if resources.empty?

  resources.first.source
end

#style_override(font) ⇒ Object



387
388
389
390
391
392
# File 'lib/fontist/formula.rb', line 387

def style_override(font)
  all_fonts
    .map(&:styles)
    .flatten
    .detect { |s| s.family_name == font }&.override || {}
end