Class: Markbridge::Parsers::BBCode::HandlerRegistry
- Inherits:
-
Object
- Object
- Markbridge::Parsers::BBCode::HandlerRegistry
- Includes:
- Enumerable
- Defined in:
- lib/markbridge/parsers/bbcode/handler_registry.rb
Overview
Registry of BBCode tag handlers
Instance Attribute Summary collapse
-
#closing_strategy ⇒ Object
writeonly
Sets the attribute closing_strategy.
Class Method Summary collapse
-
.build_from_default {|HandlerRegistry| ... } ⇒ HandlerRegistry
Build a registry from the default configuration with optional customization.
-
.default(closing_strategy: nil) ⇒ HandlerRegistry
Create the default handler registry with common BBCode tags.
-
.default_closing_strategy(registry) ⇒ ClosingStrategies::Reordering
Create the default closing strategy for a registry.
-
.shared_default ⇒ HandlerRegistry
Shared, deep-frozen default registry for the no-customization fast path.
Instance Method Summary collapse
-
#[](tag_name) ⇒ BaseHandler?
Get handler for a tag name.
-
#auto_closeable?(element_class) ⇒ Boolean
Check if an element class is auto-closeable.
-
#close_element(token:, context:, tokens: nil) ⇒ Object
Close an element using the closing strategy.
-
#each {|tag_name, handler| ... } ⇒ Enumerator
Iterate over registered (tag_name, handler) pairs.
-
#freeze ⇒ Object
Freeze the registry together with its internal collections so that registration on a shared instance fails loudly instead of silently mutating state visible to every parser.
-
#handler_for_element(element) ⇒ BaseHandler?
Get handler for an element instance.
-
#initialize(closing_strategy: nil) ⇒ HandlerRegistry
constructor
A new instance of HandlerRegistry.
-
#overlay(tag_names) {|previous| ... } ⇒ self
Replace the handler bound to one or more tag names by yielding the previously-bound handler (which may be
nil) and registering whatever the block returns. -
#register(tag_names, handler) ⇒ Object
Register a handler for one or more tag names and associate it with an element class.
Constructor Details
#initialize(closing_strategy: nil) ⇒ HandlerRegistry
Returns a new instance of HandlerRegistry.
12 13 14 15 16 17 |
# File 'lib/markbridge/parsers/bbcode/handler_registry.rb', line 12 def initialize(closing_strategy: nil) @handlers = {} @element_handlers = {} @auto_closeable_elements = Set.new @closing_strategy = closing_strategy end |
Instance Attribute Details
#closing_strategy=(value) ⇒ Object (writeonly)
Sets the attribute closing_strategy
10 11 12 |
# File 'lib/markbridge/parsers/bbcode/handler_registry.rb', line 10 def closing_strategy=(value) @closing_strategy = value end |
Class Method Details
.build_from_default {|HandlerRegistry| ... } ⇒ HandlerRegistry
Build a registry from the default configuration with optional customization
208 209 210 211 212 |
# File 'lib/markbridge/parsers/bbcode/handler_registry.rb', line 208 def self.build_from_default registry = default yield(registry) if block_given? registry end |
.default(closing_strategy: nil) ⇒ HandlerRegistry
Create the default handler registry with common BBCode tags.
Each call returns a fresh instance — mutations made to one will
not be visible to another. Convenience methods on Markbridge
build a fresh default registry per call when none is supplied;
to share state across calls, build one once and pass it via
the handlers: kwarg.
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/markbridge/parsers/bbcode/handler_registry.rb', line 104 def self.default(closing_strategy: nil) # Create registry - we'll set closing strategy after registering handlers registry = new # Simple formatting handlers (auto-closeable) registry.register( %w[b bold strong], Handlers::SimpleHandler.new(AST::Bold, auto_closeable: true), ) registry.register( %w[i italic em], Handlers::SimpleHandler.new(AST::Italic, auto_closeable: true), ) registry.register( %w[s strike del], Handlers::SimpleHandler.new(AST::Strikethrough, auto_closeable: true), ) registry.register( %w[u underline], Handlers::SimpleHandler.new(AST::Underline, auto_closeable: true), ) registry.register( "sup", Handlers::SimpleHandler.new(AST::Superscript, auto_closeable: true), ) registry.register( "sub", Handlers::SimpleHandler.new(AST::Subscript, auto_closeable: true), ) # Code handlers (raw content) registry.register(%w[code pre tt], Handlers::CodeHandler.new) # Image handler registry.register("img", Handlers::ImageHandler.new) # Attachment handler registry.register(%w[attach attachment], Handlers::AttachmentHandler.new) # URL handler registry.register(%w[url link iurl], Handlers::UrlHandler.new) # Email handler registry.register("email", Handlers::EmailHandler.new) # Quote handler registry.register("quote", Handlers::QuoteHandler.new) # Spoiler handler registry.register(%w[spoiler hide], Handlers::SpoilerHandler.new) # Color handler registry.register("color", Handlers::ColorHandler.new) # Size handler registry.register("size", Handlers::SizeHandler.new) # Alignment handlers (single instance - reads alignment from tag name) registry.register(%w[center left right justify], Handlers::AlignHandler.new) # Self-closing handlers registry.register("br", Handlers::SelfClosingHandler.new(AST::LineBreak)) registry.register("hr", Handlers::SelfClosingHandler.new(AST::HorizontalRule)) # List handlers registry.register(%w[list ul ol ulist olist], Handlers::ListHandler.new) registry.register(%w[* li .], Handlers::ListItemHandler.new) # Table handlers registry.register("table", Handlers::TableHandler.new) registry.register("tr", Handlers::TableRowHandler.new) registry.register(%w[td th], Handlers::TableCellHandler.new) # Set the closing strategy registry.closing_strategy = closing_strategy || default_closing_strategy(registry) registry end |
.default_closing_strategy(registry) ⇒ ClosingStrategies::Reordering
Create the default closing strategy for a registry
217 218 219 220 |
# File 'lib/markbridge/parsers/bbcode/handler_registry.rb', line 217 def self.default_closing_strategy(registry) reconciler = ClosingStrategies::TagReconciler.new(registry:) ClosingStrategies::Reordering.new(reconciler) end |
.shared_default ⇒ HandlerRegistry
Shared, deep-frozen default registry for the no-customization
fast path. Built once per process; Parser falls back to it
when no handlers: are given, skipping the full registry
construction on every parse. Handlers and closing strategies
are stateless after construction, so sharing is safe across
parsers and threads.
191 192 193 |
# File 'lib/markbridge/parsers/bbcode/handler_registry.rb', line 191 def self.shared_default @shared_default ||= default.freeze end |
Instance Method Details
#[](tag_name) ⇒ BaseHandler?
Get handler for a tag name
64 65 66 67 68 69 70 |
# File 'lib/markbridge/parsers/bbcode/handler_registry.rb', line 64 def [](tag_name) # Keys are always downcased strings and the scanner emits # downcased tags, so the fetch hits directly on the hot path; # the block normalizes only unusual lookups (mixed case, # symbols) instead of allocating a downcased copy per token. @handlers.fetch(tag_name) { @handlers[tag_name.to_s.downcase] } end |
#auto_closeable?(element_class) ⇒ Boolean
Check if an element class is auto-closeable
82 83 84 |
# File 'lib/markbridge/parsers/bbcode/handler_registry.rb', line 82 def auto_closeable?(element_class) @auto_closeable_elements.include?(element_class) end |
#close_element(token:, context:, tokens: nil) ⇒ Object
Close an element using the closing strategy
90 91 92 |
# File 'lib/markbridge/parsers/bbcode/handler_registry.rb', line 90 def close_element(token:, context:, tokens: nil) @closing_strategy&.handle_close(token:, context:, registry: self, tokens:) end |
#each {|tag_name, handler| ... } ⇒ Enumerator
Iterate over registered (tag_name, handler) pairs. Useful for debugging custom registries — e.g. confirming an override has stuck. Iteration order matches registration order.
25 26 27 |
# File 'lib/markbridge/parsers/bbcode/handler_registry.rb', line 25 def each(&block) @handlers.each(&block) end |
#freeze ⇒ Object
Freeze the registry together with its internal collections so that registration on a shared instance fails loudly instead of silently mutating state visible to every parser.
198 199 200 201 202 203 |
# File 'lib/markbridge/parsers/bbcode/handler_registry.rb', line 198 def freeze @handlers.freeze @element_handlers.freeze @auto_closeable_elements.freeze super end |
#handler_for_element(element) ⇒ BaseHandler?
Get handler for an element instance
75 76 77 |
# File 'lib/markbridge/parsers/bbcode/handler_registry.rb', line 75 def handler_for_element(element) @element_handlers[element.class] end |
#overlay(tag_names) {|previous| ... } ⇒ self
Replace the handler bound to one or more tag names by yielding
the previously-bound handler (which may be nil) and
registering whatever the block returns. Used to install a
delegating handler that wraps the default.
53 54 55 56 57 58 59 |
# File 'lib/markbridge/parsers/bbcode/handler_registry.rb', line 53 def (tag_names) Array(tag_names).each do |name| previous = self[name] register(name, yield(previous)) end self end |
#register(tag_names, handler) ⇒ Object
Register a handler for one or more tag names and associate it with an element class
32 33 34 35 36 37 38 |
# File 'lib/markbridge/parsers/bbcode/handler_registry.rb', line 32 def register(tag_names, handler) element_class = handler.element_class Array(tag_names).each { |tag_name| @handlers[tag_name.to_s.downcase] = handler } @element_handlers[element_class] = handler @auto_closeable_elements << element_class if handler.auto_closeable? self end |