68 lines
2.4 KiB
Ruby
68 lines
2.4 KiB
Ruby
# renders markdown for Articles, DisplayAds, Comments
|
|
class ContentRenderer
|
|
Result = Struct.new(:front_matter, :reading_time, :processed_html, keyword_init: true)
|
|
|
|
class_attribute :processor, default: MarkdownProcessor::Parser
|
|
class_attribute :front_matter_parser, default: FrontMatterParser::Parser.new(:md)
|
|
|
|
class ContentParsingError < StandardError
|
|
end
|
|
|
|
# @param input [String] body_markdown to process
|
|
# @param source [Article, Comment, DisplayAd]
|
|
# @param user [User, NilClass] article's or comment's user, nil for DisplayAd
|
|
# @param fixer [Object] fixes the input markdown
|
|
def initialize(input, source:, user: nil, fixer: MarkdownProcessor::Fixer::FixAll)
|
|
@input = input || ""
|
|
@source = source
|
|
@user = user
|
|
@fixer = fixer
|
|
end
|
|
|
|
# @param link_attributes [Hash] options passed further to RedCarpet::Render::HTMLRouge, example: { rel: "nofollow"}
|
|
# @param prefix_images_options [Hash] options for Html::Parser#prefix_all_images
|
|
# @return [ContentRenderer::Result]
|
|
def process(link_attributes: {},
|
|
prefix_images_options: { width: 800, synchronous_detail_detection: false })
|
|
fixed = fixer.call(input)
|
|
processed = processor.new(fixed, source: source, user: user)
|
|
|
|
processed_html = processed.finalize(link_attributes: link_attributes,
|
|
prefix_images_options: prefix_images_options)
|
|
|
|
Result.new(front_matter: nil, processed_html: processed_html, reading_time: 0)
|
|
rescue StandardError => e
|
|
raise ContentParsingError, e.message
|
|
end
|
|
|
|
# processes Article markdown, calculates reading time and finds frontmatter (if it exists)
|
|
#
|
|
# @return [ContentRenderer::Result]
|
|
def process_article
|
|
fixed = fixer.call(input)
|
|
parsed = front_matter_parser.call(fixed)
|
|
front_matter = parsed.front_matter
|
|
processed = processor.new(parsed.content, source: source, user: user)
|
|
|
|
reading_time = processed.calculate_reading_time
|
|
|
|
processed_html = processed.finalize
|
|
|
|
Result.new(front_matter: front_matter, processed_html: processed_html, reading_time: reading_time)
|
|
rescue StandardError => e
|
|
raise ContentParsingError, e.message
|
|
end
|
|
|
|
def has_front_matter?
|
|
fixed = fixer.call(input)
|
|
parsed = front_matter_parser.call(fixed)
|
|
front_matter = parsed.front_matter
|
|
front_matter.any? && front_matter["title"].present?
|
|
rescue ContentRenderer::ContentParsingError
|
|
true
|
|
end
|
|
|
|
private
|
|
|
|
attr_reader :fixer, :input, :user, :source
|
|
end
|