Class: RobotLab::Hook

Inherits:
Object
  • Object
show all
Defined in:
lib/robot_lab/hook.rb

Overview

Base class for hook handlers.

Subclasses implement class methods for each hook they handle. Unimplemented hooks are silently skipped; around hooks passthrough automatically so the chain never breaks.

The namespace defaults to the snake_case form of the last segment of the class name (e.g. TokenLogger -> :token_logger). Override with self.namespace = :custom when needed.

Examples:

class AuditHook < RobotLab::Hook
  def self.before_run(ctx)
    ctx.local.started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  end

  def self.after_run(ctx)
    elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - ctx.local.started_at
    puts "[#{ctx.robot.name}] #{(elapsed * 1000).round(1)}ms"
  end

  def self.on_error(ctx)
    puts "[#{ctx.robot.name}] ERROR: #{ctx.error.message}"
  end
end

RobotLab.on(AuditHook)
robot.on(AuditHook)
network.on(AuditHook)

Direct Known Subclasses

Narrator

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.namespaceSymbol?

Returns the hook's namespace symbol, derived from the class name by default. Returns nil for the base Hook class itself.

Returns:

  • (Symbol, nil)


44
45
46
47
48
49
50
51
52
53
# File 'lib/robot_lab/hook.rb', line 44

def namespace
  return @namespace if @namespace
  return nil if self == Hook

  name.split('::').last
      .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
      .gsub(/([a-z\d])([A-Z])/, '\1_\2')
      .downcase
      .to_sym
end

Class Method Details

.call(hook_name, context) { ... } ⇒ Object

Dispatch a single hook to this handler.

If the handler implements the method it is called. For around hooks that are not implemented the block is called directly (passthrough). Non-around hooks that are not implemented are silent no-ops.

Parameters:

  • hook_name (Symbol)

    e.g. :before_run, :around_tool_call

  • context (HookContext)

    the hook context object

Yields:

  • for around hooks — the next link in the chain



64
65
66
67
68
69
70
71
# File 'lib/robot_lab/hook.rb', line 64

def call(hook_name, context, &block)
  if singleton_class.public_method_defined?(hook_name)
    block ? public_send(hook_name, context, &block)
          : public_send(hook_name, context)
  elsif block
    block.call
  end
end

.inherited(subclass) ⇒ Object



73
74
75
76
# File 'lib/robot_lab/hook.rb', line 73

def inherited(subclass)
  super
  subclass.instance_variable_set(:@namespace, nil)
end