Class: Coradoc::Mirror::HandlerRegistry

Inherits:
Object
  • Object
show all
Defined in:
lib/coradoc/mirror/handler_registry.rb

Overview

Open registry mapping CoreModel classes to handler modules.

Replaces closed case/when dispatch with an extensible registry. Third-party gems can register additional handlers without modifying core classes (OCP).

Examples:

Registering a handler

registry = Coradoc::Mirror.default_registry
registry.register(MyCustomBlock, MyHandler)

Creating a custom registry

registry = Coradoc::Mirror::HandlerRegistry.new
registry.register(Coradoc::CoreModel::ParagraphBlock, MyParagraphHandler)

Defined Under Namespace

Classes: Entry

Constant Summary collapse

TERMINAL_ANCESTORS =

Find the handler entry for a given CoreModel element.

Walks the element’s class ancestors to find the most specific registered handler. This allows registering a handler for a base class (e.g., Block) that applies to all subclasses, while also registering specific handlers for subclasses.

Returns:

[Object, BasicObject].freeze

Instance Method Summary collapse

Constructor Details

#initializeHandlerRegistry

Returns a new instance of HandlerRegistry.



24
25
26
# File 'lib/coradoc/mirror/handler_registry.rb', line 24

def initialize
  @handlers = {}
end

Instance Method Details

#entry_for(element) ⇒ Object



60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/coradoc/mirror/handler_registry.rb', line 60

def entry_for(element)
  entry = @handlers[element.class]
  return entry if entry

  element.class.ancestors.each do |ancestor|
    next if ancestor == element.class
    break if TERMINAL_ANCESTORS.include?(ancestor)

    entry = @handlers[ancestor]
    return entry if entry
  end

  nil
end

#handle(element, context:) ⇒ Array(result, concat_flag)?

Invoke the handler for a given element.

Parameters:

  • element (CoreModel::Base)

    element to handle

  • context (CoreModelToMirror)

    transformer context

Returns:

  • (Array(result, concat_flag), nil)

    handler result or nil



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/coradoc/mirror/handler_registry.rb', line 88

def handle(element, context:)
  entry = entry_for(element)
  return nil unless entry

  kwargs = { context: context }.merge(entry.extra_kwargs || {})

  result = case entry.handler
           when Proc
             entry.handler.call(element, context)
           else
             entry.handler.public_send(entry.method_name, element, **kwargs)
           end

  [result, entry.concat]
end

#register(model_class, handler, method_name: :call, concat: false, extra_kwargs: {}) ⇒ Object

Register a handler for a CoreModel class.

Parameters:

  • model_class (Class)

    CoreModel class to handle

  • handler (Module, Class, Proc)

    handler implementation. If a Module/Class, method_name is called on it. If a Proc, called directly with (element, context:).

  • method_name (Symbol) (defaults to: :call)

    method to call on handler (default: :call)

  • concat (Boolean) (defaults to: false)

    if true, handler result is an array to concat into content rather than a single item to append

  • extra_kwargs (Hash) (defaults to: {})

    additional keyword arguments passed to the handler



39
40
41
42
43
44
45
46
47
# File 'lib/coradoc/mirror/handler_registry.rb', line 39

def register(model_class, handler, method_name: :call, concat: false,
             extra_kwargs: {})
  @handlers[model_class] = Entry.new(
    handler: handler,
    method_name: method_name,
    concat: concat,
    extra_kwargs: extra_kwargs
  )
end

#registered?(model_class) ⇒ Boolean

Check if a handler is registered for a CoreModel class.

Parameters:

  • model_class (Class)

Returns:

  • (Boolean)


79
80
81
# File 'lib/coradoc/mirror/handler_registry.rb', line 79

def registered?(model_class)
  @handlers.key?(model_class)
end