How to Restrict Markdown Syntax in Ruby

How can I restrict Markdown syntax in Ruby?

I have been using a second step after the markdown trasformation to sanitize the data using the sanitize gem. Its white-list based and very configurable, you could easily achieve what you are after with it.

To save you some time, here is my text formatter module, hope it helps you out. The built-in relaxed rule was a bit too strict for me.

module TextFormatter
require 'sanitize'

module Formatters
MARKDOWN = 1
TEXTILE = 2
end

RELAXED = {
:elements => [
'a', 'b', 'blockquote', 'br', 'caption', 'cite', 'code', 'col',
'colgroup', 'dd', 'dl', 'dt', 'em', 'i', 'img', 'li', 'ol', 'p', 'pre',
'q', 'small', 'strike', 'strong', 'sub', 'sup', 'table', 'tbody', 'td',
'tfoot', 'th', 'thead', 'tr', 'u', 'ul', 'del', 'ins', 'h1', 'h2', 'h3', 'h4', 'h5', 'h5', 'hr', 'kbd'],

:attributes => {
'a' => ['href', 'title'],
'blockquote' => ['cite'],
'col' => ['span', 'width'],
'colgroup' => ['span', 'width'],
'img' => ['align', 'alt', 'height', 'src', 'title', 'width'],
'ol' => ['start', 'type'],
'q' => ['cite'],
'table' => ['summary', 'width'],
'td' => ['abbr', 'axis', 'colspan', 'rowspan', 'width'],
'th' => ['abbr', 'axis', 'colspan', 'rowspan', 'scope',
'width'],
'ul' => ['type']
},

:protocols => {
'a' => {'href' => ['ftp', 'http', 'https', 'mailto',
:relative]},
'blockquote' => {'cite' => ['http', 'https', :relative]},
'img' => {'src' => ['http', 'https', :relative]},
'q' => {'cite' => ['http', 'https', :relative]}
}
}

def self.to_html(text, formatter = Formatters::MARKDOWN)
return "" unless text

html = case formatter
when Formatters::MARKDOWN then
RDiscount.new(text, :smart).to_html
when Formatters::TEXTILE then
RedCloth.new(text).to_html
end

Sanitize.clean(html, RELAXED)
end
end

RDiscount: Allow only certain tags

Since it seems that there's no “baked–in” solution for this, so here's my work–around using Redcarpet and Sanitize:

markdown = Redcarpet.new(:smart, :filter_html, :hard_wrap)
sanitize_options = {
:elements => %w(a strong em code pre br sub sup strike small)
}
html = Sanitize.clean(markdown.to_html, sanitize_options).html_safe

Markdown, enable processing of markdown within block level html

Maruku supports Markdown inside HTML blocks.

How do I render ``` code blocks in markdown with Redcarpet that are wrapped in divs?

Per the Markdown spec (such as it is):

Markdown formatting syntax is not processed within block-level HTML tags. E.g., you can’t use Markdown-style *emphasis* inside an HTML block.

There's a feature request on the Redcarpet GitHub page but unfortunately there's no conclusion that will help you.

Probably the path of least resistance here would be to run it through Redcarpet, then run the resulting HTML through Nokogiri, running the contents of each of its block-level nodes through Redcarpet again. E.g.:

require 'redcarpet'
require 'nokogiri'

block_nodes = %w(p div blockquote ...) #¹

markdown = Redcarpet::Markdown.new Redcarpet::Render::HTML,
:fenced_code_blocks => true

html = markdown.render text

noko_doc = Nokogiri::HTML::DocumentFragment.parse html

noko_doc.css( *block_nodes ).each do |node|
node.content = markdown.render node.content if node.text?
end

html = noko_doc.to_html

¹ https://github.com/tanoku/sundown/blob/master/html_block_names.txt

Of course if, if you have more than one level of nesting (an HTML block containing a Markdown block containing an HTML block and so on) you'll have to do this recursively on any new HTML nodes you generate. This would be easy but obviously has performance implications, which is why I said "path of least resistance" and not "best solution in all cases."

Rendering sections of ERb templates in Markdown with Middleman

You defined your markdown method to receive one parameter called text. But what you provide in your views is a block.

To make things work, you either change the way you call the markdown helper method in the view

<%= markdown 'this is some markdown text in here' %>

or you change the markdown helper to accept a block

def markdown
Redcarpet.new(yield).to_html
end

P.S.: The Redcarpet syntax has changed a bit since the Railscast, so if you are using a more recent gem version, implementing it this way won't work.

Starting at least from 3.3.4, perhaps earlier, you have to create a specific renderer and then call render on it with the markdown as an argument, i.e.

def markdown
Redcarpet::Render::XHTML.new.render(yield)
end

Up to date documentation can be found here: https://github.com/vmg/redcarpet



Related Topics



Leave a reply



Submit