How To Use Actuarius

chenkelmann edited this page Feb 7, 2012 · 4 revisions

#How To Use Actuarius#

These are the recipes you need to use Actuarius in your own apps. First I will cover the basic instructions, then I will describe ways to modify Actuarius’ behavior. For more details I recommend the Actuarius ScalaDoc.

##Maven / sbt / Download## You can get Actuarius binaries from the henkelmann.eu Maven Repo. For artifact id's, repo URL, version etc. please consult the project README.

You can also manually download binary jars, sources and javadoc from http://maven.henkelmann.eu/eu/henkelmann/

##Basic Usage## Once you have Actuarius on your classpath, you can easily process Markdown input. The simplest way to do that is like this:

import eu.henkelmann.actuarius.ActuariusTransformer

val transformer = new ActuariusTransformer()

def markdownToHtmlSnippet(input:String):String = transformer(input)

Note that you need a separate instance for each thread you run transformations in. Actuarius is based on Scala’s Parser Combinators which are (regrettably) not thread-safe (see http://scala-programming-language.1934581.n4.nabble.com/Scala-Parsers-are-not-thread-safe-td2243477.html). However, the overhead for creating ActuariusTransformer instances is very small, so this should not be a performance problem.

If you want to give a class the ability to parse Markdown, you can also mixin the eu.henkelmann.actuarius.Transformer trait. This will add the same apply method that the Standalone ActuariusTransformer offers. In fact, ActuariusTransformer is a simple class that only mixes in Transformer:

class ActuariusTransformer extends Transformer

##Converting output to XML/XHTML##

Actuarius only outputs Strings. The reason for this is that Markdown allows you to use verbatim HTML in your text. Actuarius cannot guarantee that this is well formed, so it cannot create scala.xml.NodeSeq instances. (An alternative to Actuarius, the Knockoff project outputs NodeSeqs that contain scala.xml.Unparsed nodes for not well formed blocks. This might however mean that you think you have well-formed XML when in fact you haven’t, as the Unparsed nodes may contain anything.)

So if you want the output of Actuarius as XML NodeSeq instances you have two choices:

  1. Wrap the output in Strings representing the enclosing tags you want for your output, then parse it manually.
  2. Just wrap the output in an Unparsed node.

The first method would look something like this:

def markdownToNodeSeq(input:String):NodeSeq =
    scala.xml.XML.loadString("<div>" + transformer(input) + "</div>")

If you allow verbatim XML/HTML in your input, this may fail, as the input might already be not well formed. So if you convert to NodeSeqs this way, you should either disable verbatim XML (see below) so Actuarius can guarantee only to output well formed XML or add proper error handling for input that cannot be turned into well-formed XML.

You have to take care when mixing inline html with inline Markdown, as you can accidently cause the output to be not well-formed anymore, even if your tags themselves are in fact well-formed. The following Markdown will cause Actuarius to emit not well-formed HTML:

This <span>*is not</span>* well formed!

The output will be:

<p>This <span><em>is not</span></em> well formed!</p>

This is the same behavior as the original Markdown.

Wrapping the output in Unparsed nodes works something like this:

def markdownToUnparsedNodeSeq(input:String):NodeSeq =
    new scala.xml.Unparsed(transformer(input))

Note that this is actually cheating, as the output looks like a proper NodeSeq when in fact it isn’t. It is up to you which of the three methods (plain String output, parsed NodeSeq, fake Unparsed) you use. I use Actuarius for the content of my Blog. As I want the pages and Atom feed to be well-formed, I use the “proper” parsing method, as I immediately notice errors in my page when I write an article. (I prefer a 500 error that I notice immediately over broken XHTML)

##Customizing the Output of Actuarius## You can modify the output of Actuarius. A typical use-case would be if you want to add attributes to some of the emitted tags. The eu.henkelmann.actuarius.Transformer trait has a method def deco():Decorator that returns a eu.henkelmann.actuarius.Decorator instance. That trait defines a number of methods that influence the output of the Transformer that returns it. In order to customize that behavior, create your own Transformer class by mixing in the Transformer trait and override the deco() method to return your own Decorator. The most comfortable way is probably to make your own Transformer its own Decorator by mixing in both traits and have deco() return this:

import eu.henkelmann.actuarius.{Decorator, Transformer}

class MyDecoratingTransformer extends Transformer with Decorator {
    override def deco() = this
}

Now you can overwrite any of the methods in Decorator to influence the output of your Transformer. There are three types of methods that influence the output:

  1. Decorator methods for block elements like paragraphs and code blocks. These exist for the opening and closing tags and have to return a String with the opening/closing tag respectively. They are named decorateFooOpen and decorateFooClose. Note that if you return broken tags or not matching tags from these methods, your Transformer’s output will not be proper XML anymore, so be warned!

  2. Decorator methods for inline elements like emphasis or links. These get passed the content(s) of the inline elements and have to return the content wrapped the way you want it.

  3. Other methods. Currently there is a method to control the usage of verbatim XML and the way nested blocks are indented.

So as an example assume we want to wrap our paragraphs into <div>s instead of <p>s and give those <div>s a class="myParagraph" attribute. Also we want to disable verbatim XML to make sure nobody sneaks any nasty stuff into the output (this is useful if you process user content with Actuarius) and that the output is always well-formed XML snippets. Also we want to use the <blink> element for emphasis instead of <em>, as it is a sign for aesthetic and professional web pages. So we extend our custom Transformer/Decorator like this:

import eu.henkelmann.actuarius.{Decorator, Transformer}

class MyDecoratingTransformer extends Transformer with Decorator {
    override def deco() = this
    override def allowVerbatimXml():Boolean = false
    override def decorateParagraphOpen():String = "<div class=\"myParagraph\">"
    override def decorateParagraphClose():String = "</div>\n"
    override def decorateEmphasis(text:String):String = "<blink>" + text + "</blink>"
}

This should be enough to get you started with Actuarius, for more details I recommend having a look at the Javadoc
and at the sources. I did my best to make them clean, well-readable and well-documented. As the project is still brand new there is no user group or anything yet. But feel free to mail me with any questions, comments, (constructive) criticism at christoph-actuarius_at_henkelmann.eu (just replace _at_ with @). If you find Actuarius useful, I would like to hear from you!