Class: Markbridge::Parsers::BBCode::ClosingStrategies::TagReconciler

Inherits:
Object
  • Object
show all
Defined in:
lib/markbridge/parsers/bbcode/closing_strategies/tag_reconciler.rb

Overview

Encapsulates logic for reconciling mismatched closing tags

Constant Summary collapse

MAX_AUTO_CLOSE_DEPTH =
5

Instance Method Summary collapse

Constructor Details

#initialize(registry:) ⇒ TagReconciler

Returns a new instance of TagReconciler.



11
12
13
# File 'lib/markbridge/parsers/bbcode/closing_strategies/tag_reconciler.rb', line 11

def initialize(registry:)
  @registry = registry
end

Instance Method Details

#try_auto_close(handler:, context:) ⇒ Boolean

Attempt to auto-close tags to match a closing tag

Parameters:

  • handler (BaseHandler)

    the handler for the closing tag

  • context (ParserState)

Returns:

  • (Boolean)

    true if successful, false if auto-close not possible



20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/markbridge/parsers/bbcode/closing_strategies/tag_reconciler.rb', line 20

def try_auto_close(handler:, context:)
  match_depth = find_matching_handler_depth(handler, context)

  return false if match_depth.nil? || match_depth >= MAX_AUTO_CLOSE_DEPTH
  return false unless all_auto_closeable?(context, match_depth)

  count = match_depth + 1
  count.times { context.pop }
  context.auto_close!(count)

  true
end

#try_reorder(handler:, tokens:, context:) ⇒ Boolean

Attempt to reorder closing tags

Parameters:

  • handler (BaseHandler)

    the handler for the closing tag

  • tokens (Object)

    the token stream

  • context (ParserState)

Returns:

  • (Boolean)

    true if successful, false otherwise



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/markbridge/parsers/bbcode/closing_strategies/tag_reconciler.rb', line 39

def try_reorder(handler:, tokens:, context:)
  match_depth = find_matching_handler_depth(handler, context)
  return false if match_depth.nil? || match_depth >= MAX_AUTO_CLOSE_DEPTH

  opening_handlers = collect_auto_closeable_handlers(context, match_depth)
  return false if opening_handlers.empty?

  closing_handlers = [handler]
  closing_handlers.concat(peek_closing_handlers(tokens, opening_handlers.size - 1))
  return false if closing_handlers.size != opening_handlers.size
  unless opening_handlers.sort_by(&:object_id) == closing_handlers.sort_by(&:object_id)
    return false
  end

  # Consume the extra closing tags
  (opening_handlers.size - 1).times do
    peeked = tokens.peek
    break unless peeked.is_a?(TagEndToken)
    tokens.next
  end

  opening_handlers.each { context.pop }
  context.auto_close!(opening_handlers.size)

  true
end