Ruby wrapper for libcmark (CommonMark parser)
Ruby C Shell
Latest commit 8dd8c8b Dec 13, 2016 @kivikakk kivikakk 💎 bump to 0.14.0
Permalink
Failed to load latest commit information.
.bundle
bin
ext/commonmarker
lib
script
test
vendor/cache
.gitignore
.gitmodules
.ruby-version
.travis.yml Revert "Test on Ruby 2.3, too" Jan 5, 2016
Gemfile
LICENSE.txt
README.md
Rakefile
appveyor.yml
commonmarker.gemspec

README.md

CommonMarker

Build Status Gem Version

Ruby wrapper for libcmark, the reference parser for CommonMark. It passes all of the C tests, and is therefore spec-complete.

Installation

Add this line to your application's Gemfile:

gem 'commonmarker'

And then execute:

$ bundle

Or install it yourself as:

$ gem install commonmarker

Usage

Converting to HTML

Call render_html on a string to convert it to HTML:

require 'commonmarker'
CommonMarker.render_html('Hi *there*', :default)
# <p>Hi <em>there</em></p>\n

The second argument is optional--see below for more information.

Generating a document

You can also parse a string to receive a Document node. You can than print that node to HTML, iterate over the children, and other fun node stuff. For example:

require 'commonmarker'

doc = CommonMarker.render_doc('*Hello* world', :default)
puts(doc.to_html) # <p>Hi <em>there</em></p>\n

doc.walk do |node|
  puts node.type # [:document, :paragraph, :text, :emph, :text]
end

The second argument is optional--see below for more information.

Example: walking the AST

You can use walk or each to iterate over nodes:

  • walk will iterate on a node and recursively iterate on a node's children.
  • each will iterate on a node and its children, but no further.
require 'commonmarker'

# parse the files specified on the command line
doc = CommonMarker.render_doc("# The site\n\n [GitHub](https://www.github.com)")

# Walk tree and print out URLs for links
doc.walk do |node|
  if node.type == :link
    printf("URL = %s\n", node.url)
  end
end

# Capitalize all regular text in headers
doc.walk do |node|
  if node.type == :header
    node.each do |subnode|
      if subnode.type == :text
        subnode.string_content = subnode.string_content.upcase
      end
    end
  end
end

# Transform links to regular text
doc.walk do |node|
  if node.type == :link
    node.insert_before(node.first_child)
    node.delete
  end
end

Creating a custom renderer

You can also derive a class from CommonMarker's HtmlRenderer class. This produces slower output, but is far more customizable. For example:

class MyHtmlRenderer < CommonMarker::HtmlRenderer
  def initialize
    super
    @headerid = 1
  end

  def header(node)
    block do
      out("<h", node.header_level, " id=\"", @headerid, "\">",
               :children, "</h", node.header_level, ">")
      @headerid += 1
    end
  end
end

# this renderer prints directly to STDOUT, instead
# of returning a string
myrenderer = MyHtmlRenderer.new
print(myrenderer.render(doc))

# Print any warnings to STDERR
renderer.warnings.each do |w|
  STDERR.write("#{w}\n")
end

Options

CommonMarker accepts the same options that CMark does, as symbols. Note that there is a distinction in CMark for "parse" options and "render" options, which are represented in the tables below.

Parse options

Name Description
:default The default parsing system.
:normalize Attempt to normalize the HTML.
:smart Use smart punctuation (curly quotes, etc.).
:validate_utf8 Replace illegal sequences with the replacement character U+FFFD.

Render options

Name Description
:default The default rendering system.
:sourcepos Include source position in rendered HTML.
:hardbreaks Treat \n as hardbreaks (by adding <br/>).
:safe Suppress raw HTML and unsafe links.

Passing options

To apply a single option, pass it in as a symbol argument:

CommonMarker.render_doc("\"Hello,\" said the spider.", :smart)
# <p>“Hello,” said the spider.</p>\n

To have multiple options applied, pass in an array of symbols:

CommonMarker.render_html("\"'Shelob' is my name.\"", [:hardbreaks, :sourcepos])

For more information on these options, see the CMark documentation.

Hacking

After cloning the repo:

script/bootstrap
bundle exec rake compile

If there were no errors, you're done! Otherwise, make sure to follow the CMark dependency instructions.

Benchmarks

Some rough benchmarks:

$ bundle exec rake benchmark

input size = 11063727 bytes

redcarpet
  0.070000   0.020000   0.090000 (  0.079641)
github-markdown
  0.070000   0.010000   0.080000 (  0.083535)
commonmarker with to_html
  0.100000   0.010000   0.110000 (  0.111947)
commonmarker with ruby HtmlRenderer
  1.830000   0.030000   1.860000 (  1.866203)
kramdown
  4.610000   0.070000   4.680000 (  4.678398)