Class: Markbridge::Processors::DiscourseMarkdown::Scanner

Inherits:
Object
  • Object
show all
Defined in:
lib/markbridge/processors/discourse_markdown/scanner.rb

Overview

Single-pass scanner for Discourse Markdown that extracts specific constructs (mentions, polls, events, uploads) while preserving all other content unchanged.

The scanner respects code blocks (fenced, indented, and inline) and will not extract constructs that appear within code.

Examples:

Basic usage

scanner = Scanner.new
result = scanner.scan("Hello @gerhard!")
result.nodes.first # => AST::Mention

With custom tag library for rendering

scanner = Scanner.new(tag_library: my_library)
result = scanner.scan(input)
result.markdown # => "Hello <<MENTION:1>>!"

With mention type resolver

scanner = Scanner.new(mention_resolver: ->(name) {
  groups.include?(name) ? :group : :user
})
result = scanner.scan("@Testers and @gerhard")
result.nodes[0].type # => :group
result.nodes[1].type # => :user

Constant Summary collapse

DEFAULT_DETECTORS =

Default detectors in priority order

[
  Detectors::Poll,
  Detectors::Event,
  Detectors::Upload,
  Detectors::Mention,
].freeze
TRIGGER_CHARS =

Characters that can start a construct (for fast bailout)

Set.new(["@", "[", "!"]).freeze

Instance Method Summary collapse

Constructor Details

#initialize(detectors: DEFAULT_DETECTORS, tag_library: nil, mention_resolver: nil) ⇒ Scanner

Returns a new instance of Scanner.

Parameters:

  • detectors (Array<Class>) (defaults to: DEFAULT_DETECTORS)

    detector classes to use (instantiated automatically)

  • tag_library (Renderers::Discourse::TagLibrary, nil) (defaults to: nil)

    tag library for rendering placeholders

  • mention_resolver (#call, nil) (defaults to: nil)

    callable that takes a name and returns :user or :group



49
50
51
52
53
54
# File 'lib/markbridge/processors/discourse_markdown/scanner.rb', line 49

def initialize(detectors: DEFAULT_DETECTORS, tag_library: nil, mention_resolver: nil)
  @detector_instances = build_detectors(detectors, mention_resolver)
  @tag_library = tag_library
  # @code_tracker / @result / @nodes / @node_index / @pos / @input /
  # @line_start are set by #scan before use; no defensive init needed.
end

Instance Method Details

#scan(input) ⇒ ScanResult

Scan input and extract constructs.

Parameters:

  • input (String)

    Discourse Markdown input

Returns:

  • (ScanResult)

    result containing processed markdown and extracted nodes



60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/markbridge/processors/discourse_markdown/scanner.rb', line 60

def scan(input)
  @code_tracker = CodeBlockTracker.new
  @result = +""
  @nodes = []
  @node_index = 0
  @pos = 0
  @input = input.to_s
  @line_start = true

  scan_input

  ScanResult.new(markdown: @result, nodes: @nodes)
end