Module: RivetCms::Hooks
- Defined in:
- lib/rivet_cms/hooks.rb
Overview
Lifecycle event registry: the extension seam host apps (and the Pro engine) attach through. Subscribers must not raise into the publish path; failures are logged and swallowed.
RivetCms::Hooks.on(:publish) { |revision| ... }
Registration is idempotent per key: re-registering with the same key replaces the previous handler instead of adding a duplicate. Anonymous handlers key on their own identity, which is stable when registration happens in an initializer (runs once per boot). Code that registers from a reloadable context (e.g. to_prepare) must pass an explicit key, or every reload adds another copy:
RivetCms::Hooks.on(:publish, key: :sitemap) { |revision| ... }
Subscribers run in registration order; there is no ordering API, so no subscriber may depend on running before or after another.
Extensions can define their own events before subscribing or firing:
RivetCms::Hooks.register_event(:unpublish)
Built-in events:
:publish - a document revision was published (fires after commit,
receives the published snapshot revision)
:prune - a superseded revision is about to be destroyed by retention
(fires inside the publish transaction, before the delete, so
a subscriber can archive it elsewhere first)
:audit - an admin mutation happened (receives a RivetCms::AuditEvent;
see RivetCms::Audit for the payload contract)
Constant Summary collapse
- BUILT_IN_EVENTS =
%i[publish prune audit].freeze
- MUTEX =
Mutex.new
Class Method Summary collapse
- .events ⇒ Object
- .on(event, callable = nil, key: nil, &block) ⇒ Object
- .register_event(event) ⇒ Object
-
.reset! ⇒ Object
Test-only: wipes ALL subscribers including the engine's boot-time registrations (initializers do not rerun).
- .restore(snapshot) ⇒ Object
- .run(event, *args) ⇒ Object
-
.snapshot ⇒ Object
Test-only: capture subscriptions so an example can register handlers and hand the registry back exactly as it found it.
Class Method Details
.events ⇒ Object
42 43 44 |
# File 'lib/rivet_cms/hooks.rb', line 42 def events mutex.synchronize { known_events.to_a } end |
.on(event, callable = nil, key: nil, &block) ⇒ Object
46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/rivet_cms/hooks.rb', line 46 def on(event, callable = nil, key: nil, &block) handler = callable || block raise ArgumentError, "handler required" if handler.nil? mutex.synchronize do raise ArgumentError, "unknown event: #{event} (register_event it first)" unless known_events.include?(event) registry[event][key || handler] = handler end handler end |
.register_event(event) ⇒ Object
37 38 39 40 |
# File 'lib/rivet_cms/hooks.rb', line 37 def register_event(event) mutex.synchronize { known_events << event.to_sym } event.to_sym end |
.reset! ⇒ Object
Test-only: wipes ALL subscribers including the engine's boot-time registrations (initializers do not rerun). Pair with snapshot/restore.
84 85 86 87 88 89 |
# File 'lib/rivet_cms/hooks.rb', line 84 def reset! mutex.synchronize do @registry = nil @known_events = nil end end |
.restore(snapshot) ⇒ Object
73 74 75 76 77 78 79 80 |
# File 'lib/rivet_cms/hooks.rb', line 73 def restore(snapshot) return if snapshot.nil? # never mistake a failed snapshot for "no subscribers" mutex.synchronize do @registry = Hash.new { |hash, event| hash[event] = {} } snapshot&.each { |event, handlers| @registry[event] = handlers.dup } end end |
.run(event, *args) ⇒ Object
58 59 60 61 62 63 64 65 |
# File 'lib/rivet_cms/hooks.rb', line 58 def run(event, *args) handlers = mutex.synchronize { registry.key?(event) ? registry[event].values : [] } handlers.each do |handler| handler.call(*args) rescue => error Rails.logger&.error("[RivetCms] #{event} hook failed: #{error.class}: #{error.}") end end |
.snapshot ⇒ Object
Test-only: capture subscriptions so an example can register handlers and hand the registry back exactly as it found it.
69 70 71 |
# File 'lib/rivet_cms/hooks.rb', line 69 def snapshot mutex.synchronize { registry.transform_values(&:dup) } end |