Class: Clickwrap::DocumentRenderers::MarkdownRails

Inherits:
Object
  • Object
show all
Defined in:
lib/clickwrap/document_renderers/markdown_rails.rb

Overview

Byte parity with the application's own pages, by construction.

Content-file Rails apps (Sitepress and friends) render their public legal pages through the markdown-rails gem, whose initializer registers a renderer for .md templates:

MarkdownRails.handle :md do
ApplicationMarkdown.new
end

When the same files are also Clickwrap documents, what people accept and what the public page serves must be the SAME BYTES — same renderer, same options, no re-sanitization pass changing entities behind the digest. Wiring that by hand means a lambda, an engine name, gem versions, and a parity test, all copied between applications. This renderer says it once:

Clickwrap.configure do |config|
config.document_renderer = :markdown_rails
end

At render time it asks markdown-rails for the exact renderer object the application's own .md pages go through, renders through it, stores the output verbatim (sanitizer_name: "none" in the provenance — safety stays where it already lives, in the pipeline every public page trusts), and records honest provenance: the renderer class the application registered, plus the markdown-rails and Markdown-engine gem versions.

The handler is resolved LAZILY, at first render, never at configuration time: Rails initializers run alphabetically, so clickwrap.rb usually runs before markdown.rb, and an eager lookup would capture the stock default renderer instead of the application's own.

Honest bound: the renderer is called directly, without a view context — exactly how a frozen document must render, because a snapshot cannot depend on the request it happened to be published during. Markdown that calls Rails view helpers (image_tag and friends) fails loudly at publish; documents like that need the explicit lambda form of Clickwrap::DocumentRenderers::Markdown instead.

Constant Summary collapse

HANDLER_EXTENSION =
:md

Instance Method Summary collapse

Constructor Details

#initializeMarkdownRails

Returns a new instance of MarkdownRails.



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/clickwrap/document_renderers/markdown_rails.rb', line 46

def initialize
  # The gem must be bundled for this choice to ever work, and a missing
  # bundle is a configuration mistake worth failing the boot for. The
  # HANDLER may legitimately not be registered yet — see the class
  # comment — so that half of the check waits until render time.
  #
  # The handler file loads first on purpose: markdown-rails' engine runs
  # an on_load(:action_view) hook that references its own Handler
  # constant, and when Action View is already loaded (it is, here) that
  # hook fires mid-require, before the entry file has declared the
  # autoload the hook depends on.
  begin
    require "markdown-rails/handler"
    require "markdown-rails"
  rescue LoadError
    raise ConfigurationError,
          "config.document_renderer = :markdown_rails needs the markdown-rails gem, and " \
          "it is not in this application's bundle. Add `gem \"markdown-rails\"` (the " \
          "Sitepress content stack), or render through your own pipeline with " \
          "Clickwrap::DocumentRenderers::Markdown.new(render_markdown_with:, engine_name:)."
  end

  @fallback = DocumentRenderer.new
end

Instance Method Details

#call(bytes, definition) ⇒ Object



71
72
73
74
75
# File 'lib/clickwrap/document_renderers/markdown_rails.rb', line 71

def call(bytes, definition)
  return @fallback.call(bytes, definition) unless definition.media_type == "text/markdown"

  application_markdown_renderer_for(definition).call(bytes, definition)
end

#engine_nameObject

The provenance the application's registered renderer would produce right now — exposed so hosts and tests can ask "which renderer will my documents publish through?" in one call.



80
81
82
# File 'lib/clickwrap/document_renderers/markdown_rails.rb', line 80

def engine_name
  "markdown_rails/#{registered_renderer_class_name}"
end

#engine_versionObject



84
85
86
87
88
89
# File 'lib/clickwrap/document_renderers/markdown_rails.rb', line 84

def engine_version
  %w[markdown-rails redcarpet commonmarker kramdown].filter_map do |gem_name|
    spec = Gem.loaded_specs[gem_name]
    "#{gem_name} #{spec.version}" if spec
  end.join(" / ").presence || "unstated"
end