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):
There's a feature request on the Redcarpet GitHub page but unfortunately there's no conclusion that will help you.Markdown formatting syntax is not processed within block-level HTML tags. E.g., you can’t use Markdown-style
*emphasis*
inside an HTML block.
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.txtOf 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 blockdef 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
Ruby: Class C Includes Module M; Including Module N in M Does Not Affect C. What Gives
Truncate String When It Is Too Long
Ruby Interpreter (Cui) 1.9.2P180 [I386-Mingw32] Has Stopped Working (I Am Not Using MySQL )
Require Tree in Asset Pipeline
Sinatra Not Persisting Session with Redirect on Chrome
How to Handle Serialized Edit Fields in an Active Admin Resource
Convert Durations in Ruby - Hh:Mm:Ss.Sss to Milliseconds and Vice Versa
Rails Routes: Nested, Member, Collection, Namespace, Scope and Customizable
Inspect or Clean Up The Working Tree Error When Installing Ruby 2.1.3 on MAC Os X 10.9.5
Ruby/Rails Audio Conversion Plugins
Hw Impossibility: "Create a Rock Paper Scissors Program in Ruby Without Using Conditionals"
How to Scrape a Website with The Socksify Gem (Proxy)
How to Wait for System Command to End
Browsing Ruby Code a La Smalltalk
Rails Validating Search Params