Module: Clacky::ApiExtensionLoader
- Defined in:
- lib/clacky/extension/api_loader.rb
Overview
Loads HTTP API extensions from ext.yml containers into the shared
Clacky::ApiExtension registry, keyed by ext_id. Every ext contributes
at most one api unit (contributes.api: <path> in ext.yml), so the
registry key is simply the ext id.
A broken extension (syntax error, missing base class, no routes) is isolated: skipped with a logged warning, never aborts sibling loads.
Defined Under Namespace
Classes: Result
Class Method Summary collapse
-
.ensure_fresh(ext_id) ⇒ Object
Per-request hot path used by the dispatcher.
- .last_result ⇒ Object
- .load_all(reload: false) ⇒ Object
- .load_one(ext_id, handler_path, ext_dir, container, result, reload: false) ⇒ Object
Class Method Details
.ensure_fresh(ext_id) ⇒ Object
Per-request hot path used by the dispatcher. Re-loads the handler only when its file mtime has changed since the last load.
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/clacky/extension/api_loader.rb', line 39 def ensure_fresh(ext_id) loader_result = Clacky::ExtensionLoader.load_all unit = loader_result.api.find { |u| u.ext_id == ext_id.to_s } return unless unit path = unit.spec["handler_abs"] current_mtime = File.mtime(path).to_f cache = handler_mtime_cache return if cache[ext_id.to_s] == current_mtime container = loader_result.containers[unit.ext_id] r = Result.new(loaded: [], skipped: []) load_one(unit.ext_id, path, unit.dir, container, r, reload: true) r.skipped.each { |(id, reason)| log_skip(id, reason) } cache[ext_id.to_s] = current_mtime rescue StandardError => e Clacky::Logger.warn("[ApiExtensionLoader] ensure_fresh(#{ext_id}) failed: #{e.}") end |
.last_result ⇒ Object
33 34 35 |
# File 'lib/clacky/extension/api_loader.rb', line 33 def last_result @last_result || load_all end |
.load_all(reload: false) ⇒ Object
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/clacky/extension/api_loader.rb', line 15 def load_all(reload: false) result = Result.new(loaded: [], skipped: []) Clacky::ApiExtension.reset_registry! handler_mtime_cache.clear loader_result = Clacky::ExtensionLoader.load_all loader_result.api.each do |unit| container = loader_result.containers[unit.ext_id] load_one(unit.ext_id, unit.spec["handler_abs"], unit.dir, container, result, reload: reload) end @last_result = result log_summary(result) result end |
.load_one(ext_id, handler_path, ext_dir, container, result, reload: false) ⇒ Object
62 63 64 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 107 108 109 110 111 112 113 114 115 |
# File 'lib/clacky/extension/api_loader.rb', line 62 def load_one(ext_id, handler_path, ext_dir, container, result, reload: false) before = Clacky::ApiExtension.pending_subclasses.size existing = reload ? Clacky::ApiExtension.registry[ext_id] : nil existing&.reset_routes! if reload old_verbose = $VERBOSE $VERBOSE = nil begin load(handler_path) ensure $VERBOSE = old_verbose end else require(handler_path) end new_subclasses = Clacky::ApiExtension.pending_subclasses[before..] || [] klass = new_subclasses.last || existing unless klass result.skipped << [ext_id, "no Clacky::ApiExtension subclass defined in handler.rb"] log_skip(ext_id, result.skipped.last[1]) return end klass.ext_id = ext_id klass.ext_dir = ext_dir klass. = (container && container[:raw]) || {} if klass.routes.empty? result.skipped << [ext_id, "no routes declared (use get/post/... DSL)"] log_skip(ext_id, result.skipped.last[1]) Clacky::ApiExtension.registry.delete(ext_id) return end if (gap = validate_public_endpoints(klass, container)) result.skipped << [ext_id, gap] log_skip(ext_id, gap) return end Clacky::ApiExtension.register(ext_id, klass) result.loaded << ext_id handler_mtime_cache[ext_id] = File.mtime(handler_path).to_f rescue nil public_count = klass.public_paths.size suffix = public_count > 0 ? " (#{public_count} public)" : "" Clacky::Logger.info("[ApiExtensionLoader] Loaded '#{ext_id}' — #{klass.routes.size} route(s)#{suffix}") rescue StandardError, ScriptError => e result.skipped << [ext_id, e.] log_skip(ext_id, e.) end |