Asciidoctor logo

:page-liquid: :icons: font :experimental:

I’ve been asked to design new courses for the next semester at my local university. Historically, I create course slides with Power Point and lab instructions with Word. There are other possible alternatives, for slides and documents:

  • https://www.google.com/slides/about/[Google Slides^]
  • A bunch of JavaScript frameworks (http://lab.hakim.se/reveal-js/[Reveal.js^], https://github.com/impress/impress.js/[Impress.js^], etc.)
  • Dedicated e-learning platforms (https://moodle.org/[Moodle^], etc.)
  • etc.

I also recently wrote some lab documents with Asciidoctor, versioned with Git. The build process generates HTML pages and those are hosted on GitHub pages. The build is triggered at every push.

This solution has several advantages for me:

  • I’m in full control of the media. Asciidoctor files are kept on my hard drive, and any other Git repository I want, public or private, in the cloud or self-hosted.
  • The Asciidoctor format is really great for writing documentation.
  • With one source document, there can be multiple output formats (.e.g. HTML, PDF, etc.).
  • Hosted on Github/GitLab Pages, HTML generation can be automated for every push on the remote.

== Starting point

Content should be released under the https://creativecommons.org/licenses/by-nc-sa/4.0/[Creative Commons license^]. That means there’s no requirement for a private repository. In addition, a public repository will allows students to make Pull Requests. Both https://pages.github.com/[Github^] and https://about.gitlab.com/features/pages/[GitLab^] provide free page hosting. Since developers are in general more familiar with Github than with GitLab, the former will be the platform of choice.

Content is made from courses and labs:

  • Courses should be displayed as slides
  • Labs as standard HTML documents

== Setup

Setup differs slightly for courses and labs.

=== Courses

To display slides, let’s use Reveal.js. Fortunately, http://asciidoctor.org/docs/asciidoctor-revealjs/[Asciidoctor Reveal.js^] allows to generate slides from Asciidoctor sources. With Ruby, the setup is pretty straightforward, thanks to the documentation:

. Install bundler: + [source, bash] —- gem install bundler —- + . Create a Gemfile with the following content: + [source] —- source ‘https://rubygems.org’

gem ‘asciidoctor-revealjs’

+ . Configure bundler: + [source, bash] —- bundle config –local github.https true bundle –path=.bundle/gems –binstubs=.bundle/.bin —- . Finally, generate HTML: + [source, bash] —- bundle exec asciidoctor-revealjs source.adoc —-

Actually, the generation command is slightly different in my case:

[source, bash]

bundle exec asciidoctor-revealjs -D output/cours\ <1> -a revealjs_history=true\ <2> -a revealjs_theme=white <3> -a revealjs_slideNumber=true\ <4> -a linkcss\ <5> -a customcss=../style.css\ <6> -a revealjsdir=https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.5.0 <7> cours/*.adoc <8> —-

<1> Set the HTML output directory <2> Explicitly push the URL into the browser history at each navigation step <3> Use the white them (by default, it’s black) <4> Display the slide number - it’s just mandatory for reference purpose <5> Create an external CSS file instead of embedding the styles into each document - makes sense if there are more than one document <6> Override some styles <7> Reference the JavaScript framework to use - could be a local location <8> Generate all documents belonging to a folder - instead of just one specific document

=== Labs

To generate standard HTML documents from Asciidoctor is even easier:

[source, bash]

bundle exec asciidoctor -D output/tp tp/*.adoc —-

== Automated remote generation

As a software developer, it’s our sacred duty to automate as much as possible. In this context, it means generating HTML pages from Asciidoctor sources on each push to the remote repository.

While Github doesn’t provide any build tool, it integrates greatly with https://travis-ci.org/[Travis CI^]. I’ve already written about the link:{% post_url 2016-04-25-gitlab-the-overlooked-git-solution-in-the-cloud %}[process^] to publish HTML on Github Pages. The only differences in the https://github.com/formations/javaee/blob/master/.travis.yml[build file^] come from:

. The project structure . The above setup

== Automated local generation

So far, so good. Everything works fine, every push to the remote generates the site. The only thing drawback, is that in order to preview the site, one has either to push… or to type the whole command-line every time. The bash history helps somewhat, until some other command is required.

[quote, Me] __ As a user, I want to preview the HTML automatically in order to keep me from writing the same command-line over and over. __

This one a bit is harder, because it’s not related to Asciidoctor. A full-blown solution with LiveReload and everything would be probably be overkill (read that I’m too lazy). But I’ll be happy enough with a watch over the local file system, and the trigger of a command when changes are detected. As my laptop runs on OSX, here’s a solution that “works on my machine”. This is based on the https://en.wikipedia.org/wiki/Launchd[launchd^] process and the https://en.wikipedia.org/wiki/Property_list[plist^] format.

This format is XML-based, but “weakly-typed” and based on the order of elements. For example, key value pairs are defined as such:

[source,xml]

<!DOCTYPE plist PUBLIC “-//Apple Computer//DTD PLIST 1.0//EN” “http://www.apple.com/DTDs/PropertyList-1.0.dtd”>

key1 value1 key2 value2 ---- A couple of things I had to find out on my own - I had no prior experience with _launchd_: . A `.plist` file should be named as per the key named `Label`. . It should be located in the `~/Library/LaunchAgents/` folder. . In this specific case, the most important part is to understand https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html#//apple_ref/doc/uid/10000172i-SW7-SW8[how to watch the filesystem^]. It's achieved with the `WatchPaths` key associated with the array of paths to watch. . The second most important part is the command to execute, `ProgramArguments`. The syntax is quite convoluted: every argument on the command line (as separated by spaces) should be an element in an array. + NOTE: It seems the `$PATH` is not initialized with environment variables of my own user, so the full path to the executable should be used. + . As debugging is mandatory - at least with the first few runs, feel free to use `StandardErrorPath` and `StandardOutPath` to respectively write standard err and out in files. The final `.plist` looks something like that: [source] ---- <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> Label ch.frankel.generatejaveecours.plist WorkingDirectory /Users/frankel/projects/course/javaee Program /usr/local/bin/bundle ProgramArguments /usr/local/bin/bundle exec asciidoctor-revealjs -a revealjs_history=true -a revealjs_theme=white -a revealjs_slideNumber=true -a linkcss -a customcss=../style.css -a revealjsdir=https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.5.0 cours/*.adoc WatchPaths /Users/frankel/projects/course/javaee/cours StandardErrorPath /tmp/asciidocgenerate.err StandardOutPath /tmp/asciidocgenerate.out ---- To finally launch the _daemon_, use the `launchctl` command: [source, bash] ---- launchctl load ~/Library/LaunchAgents/ch.frankel.generatejaveecours.plist ---- == Conclusion While automating HTML page generation on every push is quite straightforward, previewing HTML before the push requires manual action. However, with a bit of research, it's possible to scan for changes on the file system and automate generation on the laptop as well. Be proud to be lazy!