Class: Fontist::Validator
- Inherits:
-
Object
- Object
- Fontist::Validator
- Defined in:
- lib/fontist/validator.rb
Overview
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 ValidationReport after completion
-
Cache is updated after validation completes (no shared writes during validation)
Instance Attribute Summary collapse
-
#report ⇒ Object
readonly
Returns the value of attribute report.
Class Method Summary collapse
-
.load_cache(cache_path) ⇒ ValidationCache?
Load validation cache from file.
Instance Method Summary collapse
-
#build_cache(cache_path, options = {}) ⇒ ValidationCache
Build validation cache in parallel.
-
#initialize ⇒ Validator
constructor
A new instance of Validator.
-
#validate_all(options = {}) ⇒ ValidationReport
Validate all system fonts in parallel.
-
#validate_single(path) ⇒ FontValidationResult
Validate a single font and return result with timing.
Constructor Details
#initialize ⇒ Validator
Returns a new instance of Validator.
15 16 17 18 19 |
# File 'lib/fontist/validator.rb', line 15 def initialize @report = ValidationReport.new @report.platform = platform_name @report.generated_at = Time.now.to_i end |
Instance Attribute Details
#report ⇒ Object (readonly)
Returns the value of attribute report.
13 14 15 |
# File 'lib/fontist/validator.rb', line 13 def report @report end |
Class Method Details
.load_cache(cache_path) ⇒ ValidationCache?
Load validation cache from file.
149 150 151 152 153 |
# File 'lib/fontist/validator.rb', line 149 def self.load_cache(cache_path) return nil unless File.exist?(cache_path) ValidationCache.from_yaml(File.read(cache_path)) end |
Instance Method Details
#build_cache(cache_path, options = {}) ⇒ ValidationCache
Build validation cache in parallel.
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/fontist/validator.rb', line 113 def build_cache(cache_path, = {}) verbose = [: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 |
#validate_all(options = {}) ⇒ ValidationReport
Validate all system fonts in parallel.
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/fontist/validator.rb', line 28 def validate_all( = {}) use_parallel = .fetch(:parallel, true) verbose = [:verbose] cache = [: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_single(path) ⇒ FontValidationResult
Validate a single font and return result with timing.
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/fontist/validator.rb', line 65 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., time_taken: time_taken.round(4), file_size: file_size, file_mtime: file_mtime, ) end |