Module: Lich::Common::HookRegistry

Included in:
DownstreamHook, UpstreamHook
Defined in:
documented/common/hook_registry.rb

Overview

Shared behaviour for the down/upstream hook registries. DownstreamHook and UpstreamHook are otherwise near-identical apart from their backing storage and their per-direction run, so the registration/bookkeeping lives here and a fix (e.g. to source tracking) lands in one place.

An including class is +extend+ed with these as class methods and supplies its own storage via _hooks, _hook_sources, _hook_owners and _hook_persist, keeping its own run.

Instance Method Summary collapse

Instance Method Details

#add(name, action, persist: nil) ⇒ Proc, false

Registers action under name, recording the current script's name as the source (used by #sources for display), its object_id as the owner, and the declared persist disposition (used by #cleanup_on_death).

persist declares what should happen to the hook when the registering script dies:

* +true+  - keep it (it is meant to outlive the script, e.g. ;alias)
* +false+ - remove it (it is scoped to this script's lifetime)
* +nil+   - undeclared: kept for backwards compatibility, but the death
          path warns once so the author can declare intent.

Parameters:

  • name (String)
  • action (Proc)
  • persist (Boolean, nil) (defaults to: nil)

    hook lifetime relative to the script

Returns:

  • (Proc, false)

    the stored proc, or false if action is not a Proc



32
33
34
35
36
37
38
39
40
41
# File 'documented/common/hook_registry.rb', line 32

def add(name, action, persist: nil)
  unless action.is_a?(Proc)
    echo "#{hook_label}: not a Proc (#{action})"
    return false
  end
  _hook_sources[name] = (Script.current&.name || "Unknown")
  _hook_owners[name]  = Script.current&.object_id
  _hook_persist[name] = persist
  _hooks[name] = action
end

#cleanup_on_death(owner_id) ⇒ Integer

Invoked from the ScriptDeath handler when a script dies. For each hook the script registered (matched by object_id, so a force: true sibling sharing its name is unaffected), removes the ones explicitly scoped to the script (+persist: false+), keeps explicitly persistent ones (+persist: true+), and leaves undeclared ones in place but warns once so the author can declare intent. Default behaviour is therefore unchanged (hooks persist) until a script opts in to persist: false.

Parameters:

  • owner_id (Integer)

    the dying script's object_id

Returns:

  • (Integer)

    the number of hooks removed



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'documented/common/hook_registry.rb', line 64

def cleanup_on_death(owner_id)
  owned = _hook_owners.select { |_name, owner| owner == owner_id }.keys
  return 0 if owned.empty?

  removed    = 0
  undeclared = []
  owned.each do |name|
    case _hook_persist[name]
    when false then (remove(name); removed += 1)
    when true  then next
    else undeclared << name
    end
  end
  warn_undeclared(undeclared)
  removed
end

#hook_sourcesHash{String => String}

Returns the live hook-name -> source map.

Returns:



96
97
98
# File 'documented/common/hook_registry.rb', line 96

def hook_sources
  _hook_sources
end

#listArray<String>

Returns a copy of the registered hook names.

Returns:

  • (Array<String>)

    a copy of the registered hook names



82
83
84
# File 'documented/common/hook_registry.rb', line 82

def list
  _hooks.keys.dup
end

#remove(name) ⇒ Proc?

Removes the hook registered under name from every map.

Parameters:

Returns:

  • (Proc, nil)

    the removed proc, if any



47
48
49
50
51
52
# File 'documented/common/hook_registry.rb', line 47

def remove(name)
  _hook_sources.delete(name)
  _hook_owners.delete(name)
  _hook_persist.delete(name)
  _hooks.delete(name)
end

#sourcesvoid

This method returns an undefined value.

Prints a Hook -> Source table via Lich::Messaging.



88
89
90
91
92
93
# File 'documented/common/hook_registry.rb', line 88

def sources
  info_table = Terminal::Table.new :headings => ['Hook', 'Source'],
                                   :rows     => _hook_sources.to_a,
                                   :style    => { :all_separators => true }
  Lich::Messaging.mono(info_table.to_s)
end