class Fontist::Validator
Parallel font validator using non-shared state principle.
Validates fonts in parallel without mutex contention:
-
Map: Each thread validates independently using read-only cache lookup
-
Reduce: Results are merged into
ValidationReportafter completion -
Cacheis updated after validation completes (no shared writes during validation)
Attributes
Public Class Methods
Source
# File lib/fontist/validator.rb, line 151 def self.load_cache(cache_path) return nil unless File.exist?(cache_path) ValidationCache.from_yaml(File.read(cache_path)) end
Load validation cache from file.
@param cache_path [String] Path to cache file @return [ValidationCache, nil] Loaded cache or nil if not found
Source
# File lib/fontist/validator.rb, line 17 def initialize @report = ValidationReport.new @report.platform = platform_name @report.generated_at = Time.now.to_i end
Public Instance Methods
Source
# File lib/fontist/validator.rb, line 115 def build_cache(cache_path, options = {}) verbose = options[:verbose] if verbose Fontist.ui.say("Building validation cache...") end start_time = Time.now # Load existing cache (if any) for incremental updates cache = load_cache_if_exists(cache_path) # Validate using cache (non-shared state during validation) validate_all(parallel: true, verbose: verbose, cache: cache) # Update cache with new/changed results update_cache_from_report(cache, @report.results) # Save to file save_cache(cache, cache_path) elapsed = Time.now - start_time if verbose Fontist.ui.success("Validation cache built in #{elapsed.round(2)}s") Fontist.ui.success("Cached #{cache.entries.size} font validations") Fontist.ui.success("Cache saved to: #{cache_path}") end cache end
Build validation cache in parallel.
@param cache_path [String] Path to save/load cache file @param options [Hash] Options @return [ValidationCache] The validation cache
Source
# File lib/fontist/validator.rb, line 30 def validate_all(options = {}) use_parallel = options.fetch(:parallel, true) verbose = options[:verbose] cache = options[:cache] # Get all font paths font_paths = scan_font_paths if verbose Fontist.ui.say("Found #{font_paths.size} font files to validate") if cache Fontist.ui.say("Using cache with #{cache.entries.size} entries") end end # Build read-only lookup from cache (non-shared state) cache_lookup = cache&.to_lookup || {} # Validate in parallel or sequential results = if use_parallel && font_paths.size > 10 validate_parallel(font_paths, cache_lookup: cache_lookup, verbose: verbose) else validate_sequential(font_paths, cache_lookup: cache_lookup, verbose: verbose) end @report.results = results @report.calculate_summary! @report end
Validate all system fonts in parallel.
@param options [Hash] Validation options @option options [Boolean] :parallel Use parallel processing (default: true) @option options [Boolean] :verbose Show detailed progress @option options [ValidationCache] :cache Pre-loaded cache to reuse results @return [ValidationReport] Validation report with timing information
Source
# File lib/fontist/validator.rb, line 67 def validate_single(path) start_time = Time.now # Get file metadata file_size = begin File.size(path) rescue StandardError 0 end file_mtime = begin File.mtime(path).to_i rescue StandardError 0 end # Validate the font font_file = FontFile.from_path(path, validate: true, check_extension: false) time_taken = Time.now - start_time FontValidationResult.new( path: path, valid: true, family_name: font_file.family, full_name: font_file.full_name, time_taken: time_taken.round(4), file_size: file_size, file_mtime: file_mtime, ) rescue Errors::FontFileError => e time_taken = Time.now - start_time FontValidationResult.new( path: path, valid: false, error_message: e.message, time_taken: time_taken.round(4), file_size: file_size, file_mtime: file_mtime, ) end
Validate a single font and return result with timing.
@param path [String] Font file path @return [FontValidationResult] Validation result