Class: AdminSuite::DefinitionLoader
- Inherits:
-
Object
- Object
- AdminSuite::DefinitionLoader
- Defined in:
- lib/admin_suite/definition_loader.rb
Overview
Single glob-and-load implementation for the four families of definition files a host app may drop under its configured glob paths: resources, portals, root dashboards, and action handlers.
Replaces five near-duplicate loaders (three in ApplicationController, one
in BaseHelper, one in ActionExecutor) that each re-implemented the same
glob -> require/load shape with three different reload policies and, in
two cases, rescue NameError; retry used as control flow.
Reload policy (uniform across all four kinds -- load! itself no longer
branches on environment except for how a matching file gets loaded):
loaded?gates every call, in every environment: once a kind is loaded,load!(kind)is a no-op until something explicitly clears it.- In development, matching files are loaded with
loadinstead ofrequire; everywhere else,require(loaded once per process, forever). This only matters for kinds that actually get reloaded a second time --:resourcesis excluded from that (see below), so for resourcesloadvsrequireis a distinction without a difference: the file is read exactly once, same as pre-0.4.0. - Live-reload in development comes from outside
load!: the engine's "admin_suite.definition_reload" initializer hooksreset_for_new_request!intoapp.reloader.to_prepare, which Rails runs once at boot and again on any request where it detects a change in a watched path. That clears the loaded flag (and, for kinds where it's safe, the registry) so the nextload!call re-globs and reloads -- at most once per such request, not once per call. Seereset_for_new_request!for why:resourcesis deliberately excluded from that reset (and gets no live-reload at all as a result).
Error policy (generalized from ActionExecutor's pre-existing policy): log the failing file and error, then re-raise in development/test so broken definition files are immediately discoverable; swallow (after logging) elsewhere so one bad file doesn't take down a production boot or request.
Constant Summary collapse
- KINDS =
Maps each kind to:
- glob_key: the AdminSuite::Configuration attribute holding glob patterns for this kind.
- reset: clears this kind's registry/definition state. Used
both by the test-facing
reset!and, fordev_resettablekinds, byreset_for_new_request!. - loaded?: true if this kind's definitions are already loaded.
Gates every
load!call, in every environment. - mark_loaded!: records that a load attempt has completed. A no-op
for kinds whose "loaded" state is self-evident from
their registry (resources, portals): once something
is registered,
loaded?is already true. Kinds with no such registry (dashboards, actions) need an explicit flag so an all-empty-glob load doesn't re-scan the filesystem on every call. - dev_resettable: whether
reset_for_new_request!(the development live-reload hook) is allowed to reset this kind between requests. False only for :resources -- see the comment on that entry.
{ resources: { glob_key: :resource_globs, reset: -> { Admin::Base::Resource.reset_registry! }, loaded?: -> { Admin::Base::Resource.registered_resources.any? }, mark_loaded!: -> {}, # Resource registration happens *only* via `Class#inherited` # (lib/admin/base/resource.rb), which fires on class *creation* and # never on reopening an already-defined class. Resetting the # registry and then `load`ing the same file again reopens the # already-defined class -- `inherited` does not refire, so nothing # re-populates the registry, and it stays empty for the rest of the # process. This bit twice within a single request in production use # (`navigation_items` is re-entered by `portal_color`/`portal_icon` # while building the sidebar), wiping the nav on the very first # request. So :resources is never reset -- not for a dev-mode # reload, not ever. # # Consequence (this is a real cost, not a wash): resources are # loaded once per process. Once `loaded?` is true, `load!(:resources)` # never runs again, so the file is never re-read -- `load` (vs # `require`) buys nothing here, unlike the other three kinds, because # nothing ever calls it a second time. In development, both edits to # an existing resource file and newly added resource files require a # restart, unchanged from pre-0.4.0 behavior (which had no dev reload # path for resources at all). dev_resettable: false }, portals: { glob_key: :portal_globs, reset: -> { AdminSuite::PortalRegistry.reset! }, loaded?: -> { AdminSuite::PortalRegistry.all.any? }, mark_loaded!: -> {}, dev_resettable: true }, dashboards: { glob_key: :dashboard_globs, reset: -> { AdminSuite.reset_root_dashboard! }, loaded?: -> { AdminSuite.config.root_dashboard_loaded }, mark_loaded!: -> { AdminSuite.config.root_dashboard_loaded = true }, dev_resettable: true }, actions: { glob_key: :action_globs, reset: -> { Admin::Base::ActionExecutor.handlers_loaded = false }, loaded?: -> { Admin::Base::ActionExecutor.handlers_loaded }, mark_loaded!: -> { Admin::Base::ActionExecutor.handlers_loaded = true }, dev_resettable: true } }.freeze
Class Method Summary collapse
-
.load!(kind) ⇒ void
Loads the definition files configured for
kind, per the reload policy above. -
.reset!(kind) ⇒ void
Resets
kind's registry/definition state unconditionally. -
.reset_for_new_request! ⇒ void
Clears every
dev_resettablekind's loaded state, so the nextload!call for each re-globs and reloads.
Class Method Details
.load!(kind) ⇒ void
This method returns an undefined value.
Loads the definition files configured for kind, per the reload
policy above. A no-op once kind is loaded, until something resets
it (a test's explicit reset!, or -- in development -- the next
reset_for_new_request! triggered by Rails' reloader).
118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/admin_suite/definition_loader.rb', line 118 def load!(kind) entry = kind_entry(kind) return if entry[:loaded?].call files = glob_files(entry) if files.empty? entry[:mark_loaded!].call return end load_files(files, mode: Rails.env.development? ? :load : :require) entry[:mark_loaded!].call end |
.reset!(kind) ⇒ void
This method returns an undefined value.
Resets kind's registry/definition state unconditionally. Used by
tests that need a clean slate regardless of dev_resettable.
137 138 139 |
# File 'lib/admin_suite/definition_loader.rb', line 137 def reset!(kind) kind_entry(kind)[:reset].call end |
.reset_for_new_request! ⇒ void
This method returns an undefined value.
Clears every dev_resettable kind's loaded state, so the next
load! call for each re-globs and reloads. Wired into
app.reloader.to_prepare by the engine, in development only (see
"admin_suite.definition_reload" in engine.rb) -- this is what turns
"load once, cache forever" into "reload at most once per request"
instead of load! resetting on every single call.
:resources is deliberately skipped: see its KINDS entry.
151 152 153 |
# File 'lib/admin_suite/definition_loader.rb', line 151 def reset_for_new_request! KINDS.each_value { |entry| entry[:reset].call if entry[:dev_resettable] } end |