I wrote a simple script to translate (a subset of) StackExchange markdown to HTML. I used Regex
for this task, but luckily I only had to use simple patterns.
Modularization
I also wrote a Regexp-generating function as I noticed that in Markdown you are always looking for things inside such and such symbols, I feel like it simplified the code.
What I do not like
The massive and mindless use of .tr
to remove surrounding mark-up before applying HTML tags.
Tests
The code has 9 testcases, one for each feature.
Code / Tests ratio.
The code is pretty compact, totalling 16 lines of logic supported by 50 blank/end-only/comments/tests lines.
Testing bug
I used my own testing framework, but sadly it has a bug that does not allow to use #
inside tests, so I replaced it with 35.chr
Links trickiness
The code is a bit longer when handling HTML links as they are a bit more complex than tags like bold
or italics
Limitations
The code does not escape tags contained in:
``
It also has no support for lists of any kind and gives results visually more ugly (still correct) than the markdown implemented on this site.
It works on my basic example.
(On-topic, as I acknowledge that this code is not perfect but I do not ask you to fix it.)
The code
require "arrow_test"
# Returns a Regex that matches anything inside the delimiter.
# The given delimiter is escaped to allow the use of special characters.
#
# anything_inside("**") #=> /\*\*.*\*\*/
def anything_inside(start, ending=nil)
start = "\\" + start.chars.join("\\")
ending = start if ending == nil
Regexp.new(start + ".*" + ending)
end
# This function translates MarkDown to HTML.
#
# markdown_to_html("plaintext") #=> "plaintext"
# markdown_to_html("**bold only**") #=> "<b>bold only</b>"
# markdown_to_html("_italics only_") #=> "<i>italics only</i>"
# markdown_to_html("`code only`") #=> "<code>code only</code>"
# markdown_to_html(" code by indentation") #=> "<code>code by indentation</code>"
# markdown_to_html("> To be or not to be\n\n") #=> "<q> To be or not to be</q>"
# markdown_to_html(35.chr + "Title\n") #=> "<h1>Title</h1>"
# markdown_to_html("\npara\n") #=> "\n<p>para</p>\n"
# markdown_to_html("[foo](http://foo.com)") #=> "<a href=\"http://foo.com\">foo</a>"
def markdown_to_html(text)
text
.gsub(anything_inside(">", "\n\n")) {|txt| "<q>#{txt.sub(/^>*/,"").tr("\n\n", "")}</q>" }
.gsub(anything_inside("**")) {|txt| "<b>#{txt.tr("**","")}</b>"}
.gsub(anything_inside("_")) {|txt| "<i>#{txt.tr("_","")}</i>"}
.gsub(anything_inside("`")) {|txt| "<code>#{txt.tr("`","")}</code>"}
.gsub(anything_inside("#", "\n")) {|txt| "<h1>#{txt.tr("\n","").sub(/^\#*/,"")}</h1>"}
.gsub(anything_inside("\n")) {|txt| "\n<p>#{txt.tr("\n","")}</p>\n"}
.gsub(/\ \ \ \ .*/) {|txt| "<code>#{txt.strip}</code>"}
.gsub(/\[.*\]\(.*\)/) do |txt|
to_show = txt.match(/(\[.*\])/)[1].tr("[","").tr("]","")
url = txt.match(/(\(.*\))/)[1].tr("(","").tr(")","")
"<a href=\"#{url}\">#{to_show}</a>"
end
end
if __FILE__ == $0
arrow_test($0, true)
File.write("example.html", markdown_to_html("""
# A nice example.
All the time, the site [example](www.example.com) amuses me with its beauty.
I felt a **strong attachment** to it, regardless of its simplicity.
The site is an _example_ as few things can be, as Lapalisse said:
> What is an example, is an example.
Such beatiful a site may be used in examples such as:
**Python**
import webbrowser
webbrowser.open(\"www.example.com\")
And now, for something completely different, `inline code`.
> The great man may not have ideas, but will always write examples.
_And that is all,_ I hope you enjoyed reading this example, good day.
"""))
end
ending = start if ending == nil
can be rewrittenending ||= start
. \$\endgroup\$