Module: Lich::Util::TextStripper
- Defined in:
- documented/util/textstripper.rb
Overview
Utility module for stripping markup, HTML, and XML from text
This module provides methods to remove various types of formatting from text strings, including HTML tags, XML tags, and Markdown markup. It uses the Kramdown library for HTML and Markdown parsing, and Ox for proper XML parsing.
Defined Under Namespace
Modules: Mode
Constant Summary collapse
- MODE_TO_INPUT_FORMAT =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Note:XML mode does not use Kramdown; it uses Ox instead
Note:MARKDOWN is an alias for MARKUP and uses the same input format
Map of modes to their corresponding Kramdown input formats
{ Mode::HTML => 'html', Mode::MARKUP => 'GFM', Mode::MARKDOWN => 'GFM' }.freeze
Class Method Summary collapse
-
.entity_to_char(entity) ⇒ String
private
Convert HTML entity codes to characters.
-
.extract_text(element) ⇒ String
private
Extract plain text from a Kramdown element tree.
-
.extract_xml_text(element) ⇒ String
private
Extract plain text from an Ox element tree.
-
.log_error(message, exception) ⇒ void
private
Log an error message to both the response output and Lich log.
-
.requires_kramdown?(mode) ⇒ Boolean
private
Check if a mode requires kramdown.
-
.smart_quote_to_char(quote_type) ⇒ String
private
Convert smart quote symbols to regular characters.
-
.strip(text, mode) ⇒ String
Strip markup/code from text based on the specified mode.
-
.strip_html(text) ⇒ String
private
Strip HTML tags and return plain text.
-
.strip_markdown(text) ⇒ String
private
Strip Markdown formatting and return plain text (alias for strip_markup).
-
.strip_markup(text) ⇒ String
private
Strip Markdown formatting and return plain text.
-
.strip_with_kramdown(text, mode) ⇒ String
private
Strip tags using Kramdown based on the input format.
-
.strip_xml(text) ⇒ String
private
Strip XML tags and return plain text.
-
.strip_xml_with_ox(text) ⇒ String
private
Strip XML tags using Ox and return plain text.
-
.validate_mode(mode) ⇒ Symbol
private
Validate and normalize a mode value.
Class Method Details
.entity_to_char(entity) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Convert HTML entity codes to characters
435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 |
# File 'documented/util/textstripper.rb', line 435 def self.entity_to_char(entity) if entity.respond_to?(:char) entity.char else # Fallback for symbol entities case entity when :nbsp then ' ' when :lt then '<' when :gt then '>' when :amp then '&' when :quot then '"' else entity.to_s end end end |
.extract_text(element) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method handles different element types:
:text- Returns the text value directly:entity- Converts HTML entities to characters:smart_quote- Converts smart quotes to regular quotes:codeblock,:codespan- Returns code content as plain text:br- Converts line breaks to newlines:blank- Converts blank lines to newlines- All other elements - Recursively processes children
Extract plain text from a Kramdown element tree
Recursively traverses the Kramdown element tree and extracts all text content, ignoring markup and formatting.
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 |
# File 'documented/util/textstripper.rb', line 398 def self.extract_text(element) return '' if element.nil? case element.type when :text element.value when :entity # Convert HTML entities (e.g., -> space) entity_to_char(element.value) when :smart_quote # Convert smart quotes to regular quotes smart_quote_to_char(element.value) when :codeblock, :codespan # Return code content as plain text element.value when :br # Convert line breaks to newlines "\n" when :blank # Blank lines become newlines "\n" else # For all other elements (p, div, span, etc.), recursively process children if element.children element.children.map { |child| extract_text(child) }.join else '' end end end |
.extract_xml_text(element) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method processes all child nodes including:
- Text nodes (plain Strings in Ox's generic model)
- CDATA sections (Ox::CData)
- Nested elements (recursively)
Extract plain text from an Ox element tree
Recursively traverses the Ox element tree and extracts all text content, including CDATA sections.
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 |
# File 'documented/util/textstripper.rb', line 360 def self.extract_xml_text(element) return '' if element.nil? # In Ox's generic model text nodes are plain Strings and CDATA sections # are Ox::CData; comments/PIs are other node types and are ignored. element.nodes.map do |node| case node when Ox::CData node.value when Ox::Element extract_xml_text(node) when String node else '' end end.join end |
.log_error(message, exception) ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Log an error message to both the response output and Lich log
261 262 263 264 265 |
# File 'documented/util/textstripper.rb', line 261 def self.log_error(, exception) = "TextStripper: #{} (#{exception.class}: #{exception.}). Returning original." respond() Lich.log() end |
.requires_kramdown?(mode) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Check if a mode requires kramdown
134 135 136 |
# File 'documented/util/textstripper.rb', line 134 def self.requires_kramdown?(mode) MODE_TO_INPUT_FORMAT.key?(mode) end |
.smart_quote_to_char(quote_type) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Convert smart quote symbols to regular characters
457 458 459 460 461 462 463 |
# File 'documented/util/textstripper.rb', line 457 def self.smart_quote_to_char(quote_type) case quote_type when :lsquo, :rsquo then "'" when :ldquo, :rdquo then '"' else quote_type.to_s end end |
.strip(text, mode) ⇒ String
If Kramdown or Ox parsing fails, a warning is issued and the original text is returned unchanged
Strip markup/code from text based on the specified mode
This method provides a unified interface for removing different types of markup from text. It handles HTML tags, XML tags, and Markdown formatting based on the mode parameter.
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
# File 'documented/util/textstripper.rb', line 191 def self.strip(text, mode) return "" if text.nil? || text.empty? # Validate mode BEFORE entering the rescue block # This allows ArgumentError to propagate to the caller as documented validated_mode = validate_mode(mode) # Check if kramdown is required and available if requires_kramdown?(validated_mode) && !KRAMDOWN_LOADED respond("Need to restart Lich5 in order to use this method.") return text end # Route to appropriate parsing method based on mode case validated_mode when Mode::XML strip_xml_with_ox(text) else strip_with_kramdown(text, validated_mode) end rescue Kramdown::Error => e # Handle Kramdown parsing errors (HTML/MARKUP/MARKDOWN modes) log_error("Failed to parse #{validated_mode}", e) text rescue Ox::ParseError => e # Handle Ox parsing errors (XML mode) log_error("Failed to parse #{validated_mode}", e) text rescue StandardError => e # Catch any other unexpected errors during parsing log_error("Unexpected error during #{validated_mode} parsing", e) text end |
.strip_html(text) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method is called internally by #strip when mode is Mode::HTML
Uses Kramdown for HTML parsing
Strip HTML tags and return plain text
Parses the input as HTML and removes all HTML tags, returning only the text content. This is a convenience wrapper around #strip_with_kramdown.
487 488 489 490 491 492 493 494 |
# File 'documented/util/textstripper.rb', line 487 def self.strip_html(text) unless KRAMDOWN_LOADED respond("Need to restart Lich5 in order to use this method.") return text end strip_with_kramdown(text, Mode::HTML) end |
.strip_markdown(text) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This is functionally identical to strip_markup
Uses GitHub Flavored Markdown (GFM) as the input format
Strip Markdown formatting and return plain text (alias for strip_markup)
This is an alias for #strip_markup that provides a more explicit method name for working with Markdown content. Both :markup and :markdown modes are functionally identical.
591 592 593 594 595 596 597 598 |
# File 'documented/util/textstripper.rb', line 591 def self.strip_markdown(text) unless KRAMDOWN_LOADED respond("Need to restart Lich5 in order to use this method.") return text end strip_with_kramdown(text, Mode::MARKDOWN) end |
.strip_markup(text) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Uses GitHub Flavored Markdown (GFM) as the input format
Uses Kramdown for Markdown parsing
This method is called internally by #strip when mode is Mode::MARKUP
Strip Markdown formatting and return plain text
Parses Markdown (GitHub Flavored Markdown) and removes all formatting, returning only the plain text content. This is a convenience wrapper around #strip_with_kramdown.
560 561 562 563 564 565 566 567 |
# File 'documented/util/textstripper.rb', line 560 def self.strip_markup(text) unless KRAMDOWN_LOADED respond("Need to restart Lich5 in order to use this method.") return text end strip_with_kramdown(text, Mode::MARKUP) end |
.strip_with_kramdown(text, mode) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method uses Kramdown's conversion chain to ensure proper text extraction. The process is:
- Parse input according to format (HTML/GFM)
- Convert internal representation to plain text
- Strip leading/trailing whitespace
For HTML mode, Kramdown's HTML parser extracts text content while preserving text nodes and ignoring markup. For markup/markdown modes, the GFM parser processes Markdown syntax and then extracts plain text.
Strip tags using Kramdown based on the input format
This is a shared helper method that handles the actual parsing and tag removal for HTML, MARKUP, and MARKDOWN modes. It converts the parsed document to plain text using Kramdown's standard conversion methods.
289 290 291 292 293 294 295 296 297 298 299 300 |
# File 'documented/util/textstripper.rb', line 289 def self.strip_with_kramdown(text, mode) unless KRAMDOWN_LOADED respond("Need to restart Lich5 in order to use this method.") return text end input_format = MODE_TO_INPUT_FORMAT[mode] doc = Kramdown::Document.new(text, input: input_format) # Extract plain text from the parsed document by traversing the element tree extract_text(doc.root).strip end |
.strip_xml(text) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method uses Ox for proper XML parsing, which correctly handles XML-specific features (CDATA, namespaces, etc.)
This method is called internally by #strip when mode is Mode::XML
Strip XML tags and return plain text
Removes XML tags from the input text using Ox for proper XML parsing. This method correctly handles XML-specific features like namespaces, CDATA sections, and processing instructions. This is a convenience wrapper around #strip_xml_with_ox.
528 529 530 |
# File 'documented/util/textstripper.rb', line 528 def self.strip_xml(text) strip_xml_with_ox(text) end |
.strip_xml_with_ox(text) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
skip: :skip_off keeps whitespace verbatim, including whitespace-only text nodes between sibling elements. (:skip_none still drops those inter-element nodes, so "x y" would strip to "xy" not "x y".)
This method handles:
- XML namespaces
- CDATA sections (content is preserved as text)
- Nested elements
- Mixed content (text and elements)
- HTML named entities (e.g.
) and numeric character references - Unescaped special characters in plain text (wraps in CDATA if needed)
Strip XML tags using Ox and return plain text
This method uses Ox (generic mode) to properly parse XML content and
extract all text nodes. Unlike the HTML parser, Ox correctly handles
XML-specific features like namespaces, CDATA sections, and processing
instructions, and it decodes HTML named entities such as that
are not part of XML's predefined set.
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 |
# File 'documented/util/textstripper.rb', line 328 def self.strip_xml_with_ox(text) # Try to parse as-is first (in case it's already well-formed XML) begin parsed = Ox.load("<root>#{text}</root>", mode: :generic, skip: :skip_off) rescue Ox::ParseError # If parsing fails due to unescaped characters, wrap in CDATA parsed = Ox.load("<root><![CDATA[#{text}]]></root>", mode: :generic, skip: :skip_off) end # Ox.load returns an Ox::Document when the input has an XML prolog and # the bare root Ox::Element otherwise; the root is <root> either way. root = parsed.is_a?(Ox::Document) ? parsed.root : parsed # Extract all text content from the document extract_xml_text(root).strip end |
.validate_mode(mode) ⇒ Symbol
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Validate and normalize a mode value
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 |
# File 'documented/util/textstripper.rb', line 234 def self.validate_mode(mode) # Ensure mode is a Symbol or String unless mode.is_a?(Symbol) || mode.is_a?(String) raise ArgumentError, "Mode must be a Symbol or String, got #{mode.class}" end # Normalize to symbol normalized_mode = mode.to_sym # Validate against allowed modes unless Mode.valid?(normalized_mode) raise ArgumentError, "Invalid mode: #{mode}. Use one of: #{Mode.list}" end normalized_mode end |