Module: Bridgetown::Hooks

Defined in:
lib/bridgetown-core/hooks.rb

Defined Under Namespace

Classes: HookRegistration

Constant Summary collapse

DEFAULT_PRIORITY =
20
PRIORITY_MAP =
{
  low: 10,
  normal: 20,
  high: 30,
}.freeze
Uncallable =
Class.new(RuntimeError)

Class Method Summary collapse

Class Method Details

.clear_reloadable_hooksObject

Clear all hooks marked as reloadable from the registry



104
105
106
107
108
109
110
# File 'lib/bridgetown-core/hooks.rb', line 104

def self.clear_reloadable_hooks
  Bridgetown.logger.debug("Clearing reloadable hooks")

  @registry.each_value do |hooks|
    hooks.delete_if(&:reloadable)
  end
end

.prioritized_hooks(hooks) ⇒ Object

Sort registered hooks according to priority and load order



38
39
40
41
# File 'lib/bridgetown-core/hooks.rb', line 38

def self.prioritized_hooks(hooks)
  grouped_hooks = hooks.group_by(&:priority)
  grouped_hooks.keys.sort.reverse.map { |priority| grouped_hooks[priority] }.flatten
end

.priority_value(priority) ⇒ Object



29
30
31
32
33
# File 'lib/bridgetown-core/hooks.rb', line 29

def self.priority_value(priority)
  return priority if priority.is_a?(Integer)

  PRIORITY_MAP[priority] || DEFAULT_PRIORITY
end

.register(owners, event, priority: DEFAULT_PRIORITY, reloadable: true) {|obj| ... } ⇒ Object

Register one or more hooks which may be triggered later for a particular event

Yields:

  • the block will be called when the event is triggered. Typically it receives at least one argument.

Yield Parameters:

  • obj

    the object which triggered the event hook



54
55
56
57
58
# File 'lib/bridgetown-core/hooks.rb', line 54

def self.register(owners, event, priority: DEFAULT_PRIORITY, reloadable: true, &block)
  Array(owners).each do |owner|
    register_one(owner, event, priority:, reloadable:, &block)
  end
end

.register_one(owner, event, priority: DEFAULT_PRIORITY, reloadable: true) {|obj| ... } ⇒ Proc

Register a hook which may be triggered later for a particular event

Yields:

  • the block will be called when the event is triggered. Typically it receives at least one argument.

Yield Parameters:

  • obj

    the object which triggered the event hook

Raises:



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/bridgetown-core/hooks.rb', line 72

def self.register_one(owner, event, priority: DEFAULT_PRIORITY, reloadable: true, &block)
  @registry[owner] ||= []

  raise Uncallable, "Hooks must respond to :call" unless block.respond_to? :call

  @registry[owner] << HookRegistration.new(
    owner:,
    event:,
    priority: priority_value(priority),
    reloadable:,
    block:
  )
  if ENV["BRIDGETOWN_LOG_LEVEL"] == "debug"
    if Bridgetown.respond_to?(:logger)
      Bridgetown.logger.debug("Registering hook:", @registry[owner].last.to_s)
    else
      p "Registering hook:", @registry[owner].last.to_s
    end
  end

  block
end

.remove_hook(owner, block) ⇒ Object

Delete a previously-registered hook



99
100
101
# File 'lib/bridgetown-core/hooks.rb', line 99

def self.remove_hook(owner, block)
  @registry[owner].delete_if { |item| item.block == block }
end

.trigger(owner, event, *args) ⇒ Object

Trigger all registered hooks for a particular owner and event. Any arguments after the initial two will be directly passed along to the hooks.



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/bridgetown-core/hooks.rb', line 117

def self.trigger(owner, event, *args) # rubocop:disable Metrics/CyclomaticComplexity
  # proceed only if there are hooks to call
  hooks = @registry[owner]&.select { |item| item.event == event }
  return if hooks.nil? || hooks.empty?

  prioritized_hooks(hooks).each do |hook|
    if ENV["BRIDGETOWN_LOG_LEVEL"] == "debug"
      hook_info = args[0].respond_to?(:relative_path) ? args[0].relative_path : hook.block
      Bridgetown.logger.debug("Triggering hook:", "#{owner}:#{event} for #{hook_info}")
    end
    hook.block.call(*args)
  end

  true
end