Skip to content

Instantly share code, notes, and snippets.

@chaslemley
Created October 24, 2010 16:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chaslemley/2964d548027eb63c19d7 to your computer and use it in GitHub Desktop.
Save chaslemley/2964d548027eb63c19d7 to your computer and use it in GitHub Desktop.
Slim style HTML Parser
(ns slim.core)
(use '[clojure.contrib.duck-streams :only (read-lines spit)])
(defstruct html-node :depth :leading_whitespace :interpreted :selector :attributes :content)
(defn process-line [acc line]
(let [[full-text
leading_whitespace
interpreted
selector
full_attributes
attributes
content] (re-find #"^([\s]*)([-=;|]?)([\w]*)([(](.*?)[)])?(.*)$" line)]
(if (or (= (.trim full-text) "") ; empty line
(= interpreted ";")) ; comment
acc
(conj acc (struct-map html-node :depth (count leading_whitespace),
:leading_whitespace leading_whitespace,
:interpreted_type interpreted,
:interpreted (or (= interpreted "=") (= interpreted "-")),
:selector selector,
:attributes attributes,
:content (.trim content))))))
(defn process-file [file-name line-accum]
(reduce process-line line-accum (read-lines file-name)))
(def self-closing-tags
#{"meta" "br" "link"})
(defn attributes [attr]
(if (nil? attr) "" (str " " attr)))
(defn opening-tag [node]
(if (contains? self-closing-tags (node :selector))
(str "\n" (node :leading_whitespace) "<" (node :selector) (attributes (node :attributes)) " />")
(str "\n" (node :leading_whitespace) "<" (node :selector) (attributes (node :attributes)) ">")))
(defn closing-tag [node]
(if (contains? self-closing-tags (node :selector)) "" (str "\n" (node :leading_whitespace) "</" (node :selector) ">")))
(defn interpreted-clojure [node]
(load-string (node :content)))
(defn content [node]
(if (= "" (node :content)) "" (str "\n" (node :leading_whitespace) " " (node :content))))
(defn write-html [data stack]
(if (empty? data)
(reduce #(str %1 (closing-tag %2)) "" stack)
(let [current (first data)]
(if (<= (get current :depth -1) (get (first stack) :depth -2))
(str (closing-tag (first stack)) (write-html data (rest stack)))
(if (current :interpreted)
(if (= "=" (current :interpreted_type))
(str "\n" (current :leading_whitespace) (interpreted-clojure current) (write-html (rest data) stack))
(do (interpreted-clojure current) (str (write-html (rest data) stack))))
(if (= (current :interpreted_type) "|")
(str (content current) (write-html (rest data) stack))
(str (opening-tag current) (content current) (write-html (rest data) (conj stack current)))))))))
(time (write-html (process-file (str "test.slim.html") []) '()))
(spit "test.html" (write-html (process-file (str "test.slim.html") []) '()))
;; TODO
;; Add Doctype Directive
- (def things ["cars" "trucks" "automobiles" "kittens" "clothes"])
- (def other_things ["losers" "winners" "fighters"])
- (def and_more_things ["coders" "kangaroos" "guns"])
- (defn greeting [name] (str "Hello, " name))
- (defn fib-step [ab] [(last ab) (+ (first ab) (last ab))])
- (defn fib-seq [] (map first (iterate fib-step [0 1])))
; This is a comment
html(xmlns="http://www.w3.org/1999/xhtml")
head
title Page Title
meta(name='keywords' content="template language")
link(rel="alternate" href="/styles.css")
body
h1 Hello World
div
p(class='my classes' id='my_id') This is a paragraph. Lorem ipsum dolor ( ) sit amet,
| consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et
| dolore magna aliqua. &amp; Ut enim ad minim veniam, quis nostrud exercitation
| ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
| in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
| Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt
| mollit anim id est laborum.
ul
= (reduce #(str %1 "<li>" %2 "</li>") "" things)
= (reduce #(str %1 "<li>" %2 "</li>") "" other_things)
= (reduce #(str %1 "<li>" %2 "</li>") "" and_more_things)
li
a(class="hello" href='http://google.com') Go To Google
p
= (greeting "Kathleen")
| You are awesome
| and fun
= (str "test")
h3(style="color:green") Fibonacci Numbers
ul
= (reduce #(str %1 "<li>" %2 "</li>") "" (take 10 (fib-seq)))
div(id="footer") Copyright &copy; 2010 Chas Lemley
script(type="text/javascript")
| $(content).do_something();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment