image image


Worknote: RubyFrontier und kramdown

Auch wenn ich dieses Notizheft scherzhaft meine World Markdown nenne (in Anlehnung an Winers World Outline), so ist es doch eigentlich das Markdown-Superset kramdown, das hinter den Kulissen werkelt. Ich nutze es aus zwei Gründen:

  • (John Grubers Original-) Markdown hat zwei kleinere Bugs: So kann die Software nicht vernünftig mit Links umgehen, die Klammern enthalten, wie sie zum Beispiel in der Wikipedia häufiger vorkommen (http://de.wikipedia.org/wiki/Java_(Programmiersprache)). Hier glaubt Markdown einfach, die Klammer hinter Programmiersprache wäre das Ende der Linkauszeichnung und liefert daher den Link in der Form http://de.wikipedia.org/wiki/Java_(Programmiersprache, also ohne die letzte Klammer. Außeredem kann man in Markdown ja kursiven Text auch darstellen, indem man nicht nur Sternchen, sondern auch je einen Unterstrich vor und nach dem Text setzt, also _dieser Test ist kursiv_ wird zu »dieser Text ist kursiv«. Markdown interpretiert aber auch Unterstriche in Links, wenn sie mindestens zwei mal vorkommen, als Anweisung, dieses als kursiven Text zu behandeln und verhaut so die Links: Aus www.meine_tolle_webseite wird www.meine<em>tolle</em>webseite. Für beides gibt es Workarounds, aber schön ist es nicht.
  • Markdown hat keine Befehle für Fußnoten, kramdown schon. Und auch wenn ich Fußnoten als etwas betrachte, das dem Web ferne steht1, im wissenschaftlichen Bereich kommt man bis heute einfach nicht darum herum.

Daher hatte ich mich entschieden, kramdown zu nutzen, das von Matt Neuburg ja auch wärmstens empfohlen wird2.

Doch zuerst rannte ich dabei nur in Probleme. Das kleinste dabei war, daß kramdown weder zur Standard-Ruby-Installation auf dem Mac gehört, noch daß es mit RubyFrontier mitgeliefert wird.

image

Doch

sudo gem install kramdown

erledigt dies zuverlässig auf jedem Mac.

Schwieriger war das nächste Problem. Da kramdown Seltsames mit den Makro-Aufrufen anstellt, hatte sich Matt entschieden, im Gegensatz zu Markdown, das im pageFilter aufgerufen wird, kramdown erst im postMacroFilter aufzurufen. Das führte bei mir jedoch zu zwei ärgerlichen Nebeneffekten:

[1]: Der postMacroFilter arbeitet auf der gesamten Webseite, also auf dem bodytext wie auf dem umgebenden Template. Das ist natürlich logisch, da ja auch das Template Makros enthalten kann. Nun erkennt aber dummerweise kramdown (wie auch Markdown) eingerückten Text als Quelltext und behandelt ihn auch als solchen, das heißt also, statt den Footer dieser Seite als HTML zu behandeln, schrieb kramdown

<br />
<div class="footer">
<p>(<a href="http://creativecommons.org/licenses/by-nc-sa/3.0/de/">cc</a>) 2012-<%= yearnow() %> -- Some Rights Reserverd -- Letze Änderung: 10.10.2012, 17:15 Uhr -- <a href="Impressum">Impressum</a> -- <a href="RSS-Feed">RSS-Feed</a></p>
<p> …

heraus. Die Alternative wäre natürlich, im Template auf Einrückungen zu verzichten, aber ich liebe nun einmal sauber eingerückten Quellcode, daher war diese Alternative für mich keine.

[2]: kramdown schreibt die Fußnoten an das Ende des Textes, den der Interpreter abarbeitet. Das heißt also, wenn man dann auf Einrückungen verzichtet, erschienen die Fußnoten nach dem Footer, also im Falle dieses Notizheftes unterhalb des Flattr-Buttons. Das ist natürlich ebenfalls hoch unerwünscht, Fußnoten sollten da erscheinen, wo Ihr sie in dieser Worknote unten auch seht.

Daher erschien mir die einzig vernünftige Alternative, kramdown ebenfalls im pageFilter aufzurufen3. Dann funktionierten aber die Makros nicht mehr, da kramdown einige Substitionen vornimmt. Nun kann man kramdown aber auch von der Kommandozeile aus aufrufen, und daher habe ich mir dort angeschaut, was die Software eigentlich mit den Makro-Aufrufen anstellt. Und das war eigentlich ziemlich eindeutig, aus

<%= imageref("pussyland", {:width => "560", :height => "560") %>

wurde

&lt;%= imageref(&ldquo;pussyland&rdquo;, {:width =&gt; &ldquo;560&rdquo;, :height =&gt; &ldquo;560&rdquo;) %&gt;

Wie man leicht sieht, werden alle < in &lt;, alle > in &gt; und alle Anführungszeichen in &ldquo; resp. &rdquo; umgewandelt. Das ließ sich mit ein paar einfachen Textersetzungen in RubyFrontier einfach wieder rückgängig machen. Also habe ich dem pageFilter noch folgende Zeilen spendiert (direkt nach der Markdown-Substitution – die erste Kommentarzeile ist noch Originaltext von Matt Neuburg, damit Ihr wißt, wo Ihr den Code einfügen könnt):

# however, I now advise using kramdown instead of Markdown
if adrPageTable[:kramdown]
  adrPageTable[:bodytext] = Kramdown::Document.new(adrPageTable[:bodytext],
  :auto_ids => false, :entity_output => :numeric).to_html.gsub("&quot;", '"')
# but kramdown also substitutes &lt;% for <% and %&gt; for %>, so if we have macros they've just been stripped
  adrPageTable[:bodytext] = adrPageTable[:bodytext].gsub("&lt;%", "<%")
  adrPageTable[:bodytext] = adrPageTable[:bodytext].gsub("%&gt;", "%>")
# and kramdown substitutes =&gt; for => so we have to substitute that back
  adrPageTable[:bodytext] = adrPageTable[:bodytext].gsub("=&gt;", "=>")
# we also need macros for removing the "smart quotes"
  adrPageTable[:bodytext] = adrPageTable[:bodytext].gsub("&#8220;", "\"")
  adrPageTable[:bodytext] = adrPageTable[:bodytext].gsub("&#8221;", "\"")
end

Natürlich darf man nicht vergessen, im postMacroFilter den kramdown-Aufruf zu entfernen (bei mir ist dieser Filter nun leer), dann aber – wenn man in der #prefs.yaml die Anweisung

:markdown: true

durch die Anweisung

kramdown: true

ersetzt – läuft alles wie geschmiert.

Die Geschichte mit den smart quotes (oder fancy quotes) finde ich übrigens ärgerlich. Fast jede Sprache der Welt hat ihre eigenen Regeln für An- und Abführungszeichen, so z.B. “Großbritannien und die USA”, „Deutschland“, die »Schweiz« oder «Frankreich», wobei die beiden letzgenannten auch bei deutschen Verlagen (und auch auf diesen Seiten) häufig eingesetzt werden. In Zeiten von UTF-8 resp. UTF-16 sollte man es jedem selber überlassen, welche An- und Abführungszeichen er verwenden will und nicht eine Software basteln, die glaubt, schlauer sein zu müssen, als der Autor der Texte.

Jetzt bleibt eigentlich nur noch eine Kleinigkeit zu tun: kramdown schreibt die Fußnoten einfach als ordered list heraus und das sieht in der Default-Version nicht besonders schön aus. Da aber diese Liste mit class=footnote identifizierbar ist, reicht es, ein wenig CSS-Zauberei an den Tag zu legen und schon ist alles wieder gut:

.footnotes {
  font-size: 90%;
  border-top: 1px solid;
  margin-top: 20px;
}

Wie ich schon häufiger anmerkte, bin ich nicht wirklich der CSS-Guru. Es bleibt also Euch überlassen, die Fußnoten noch schöner zu gestalten.

Caveat

Zum Schluß aber noch etwas Grundsätzliches: Die Zahl der Supersets zu Markdown ist Legion und fast jede hat eine leicht abweichende Syntax bei den eigenen Erweiterungen. Setzt daher diese Erweiterungen sparsam ein, damit Ihr möglichst kompatibel zu Markdown und anderen Supersets wie Multimarkdown, PHP-Markdown Extra, Maruku, Pandoc und anderen seid. Ihr verschenkt sonst die Möglichkeit, unter Umständen einfach eine andere Software, die auf Markdown oder einem der Supersets aufsetzt, zu benutzen.

Ich selber nutze konsequent (fast) nur die Syntax von Markdown und keine der kramdown-Erweiterungen. Lediglich wenn ich tatsächlich Fußnoten benötige, mache ich eine Ausnahme. Und natürlich werde ich bei mathematischen Formeln schwach, die in kramdown in der LaTeX-Notation niedergeschrieben werden können. Und Tabellen sind in kramdwon auch ganz, ganz einfach zu erstellen. Soviel zur Konsequenz …

image

  1. Fuß- und Endnoten sind typische Ausdrucksformen der Print-Ära. Auf das Ende einer (Buch-) Seite zu schauen, geht schnell, selbst an das Ende eines Buches zu blättern (bei Endnoten) ist noch eine hinnehmbare Zumutung für den Leser. Aber bei einer langen Webseite nach unten zu scrollen und dann wieder nach oben, um mühselig die Stelle wiederzufinden, die man gelesen hatte …?

  2. […] however, I now advise using kramdown instead of Markdown

  3. Das scheint mir auch der »natürlich« Ort, an dem kramdown aufgerufen werden sollte. Denn logischerweise soll die Software nur auf dem bodytext, also dem eigentlichen Inhalt der Seite arbeiten und nicht auch noch auf dem Template.


RubyFrontier und kramdown bitte flattrn

comments powered by Disqus