Skip to content

Instantly share code, notes, and snippets.

@yogthos
Created July 29, 2012 19:42
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yogthos/3201386 to your computer and use it in GitHub Desktop.
Save yogthos/3201386 to your computer and use it in GitHub Desktop.
Guestbook in Clojure

Install Leiningen and create a project

wget https://raw.github.com/technomancy/leiningen/preview/bin/lein
lein self-install
lein plugin install lein-noir 1.2.1
lein noir new guestbook
cd guestbook

#Add dependencies

edit project.clj and add jdbc dependencies

(defproject guestbook "0.1.0-SNAPSHOT"
            :description "FIXME: write this!"
            :dependencies [[org.clojure/clojure "1.3.0"]
                           [org.clojure/java.jdbc "0.2.3"]
                           [org.xerial/sqlite-jdbc "3.7.2"]
                           [noir "1.2.1"]]
            :main guestbook.server)

run the project

lein run

update common namespace with our layout

(ns guestbook.views.common
  (:use [noir.core :only [defpartial]]
        [hiccup.page-helpers :only [include-css html5]]))

(defpartial layout [& content]
  (html5
    [:head
     [:title "guestbook"]
     (include-css "/css/reset.css")]
    [:body               
     [:section#wrapper content]
     [:footer#footer "My awesome guestbook"]]))

add the main page to welcome namespace

(ns guestbook.views.welcome
  (:require [guestbook.views.common :as common]
            [noir.content.getting-started]
            [guestbook.models.db :as db])
  (:use noir.core hiccup.core hiccup.form-helpers))

(defn show-guests []
  (into [:ul.guests]
        (for [{:keys [message name timestamp]} (db/read-guests)]
          [:li
           [:blockquote message]
           [:p "-" [:cite name]]
           [:time timestamp]])))

(defpage "/" {:keys [name message error]}
  (common/layout
    [:h1 "Guestbook"]
    [:p "Welcome to my guestbook!"]
    [:p error]
    (show-guests)
    [:hr]
    (form-to [:post "/"]
             [:p "Name:" (text-field "name" name)]
             [:p "Message:" (text-area {:rows 10 :cols 40} "message" message)]
             (submit-button "comment"))))

(defn error [params error]
  (assoc params :error error))

(defpage [:post "/"] params
  (cond 
    (empty? (:name params )) (render "/" (error params "Some dummy who forgot to leave a name"))
    (empty? (:message params )) (render "/" (error params "WOW THIS IS THE BEST WEBSITE EVER"))
    :else 
    (do 
      (db/save-message params)
      (render "/"))))

create the database handler

(ns guestbook.models.db
  (:require [clojure.java.jdbc :as sql])
  (:import java.sql.DriverManager))

(def db {:classname  "org.sqlite.JDBC",
         :subprotocol   "sqlite",
         :subname       "db.sq3"})

(defn create-table []
  (sql/with-connection
    db
    (sql/create-table
      :guestbook
      [:id "INTEGER PRIMARY KEY AUTOINCREMENT"]
      [:timestamp "TIMESTAMP DEFAULT CURRENT_TIMESTAMP"]
      [:name "TEXT"]
      [:message "TEXT"])
    (sql/do-commands "CREATE INDEX timestamp_index ON guestbook (timestamp)")))

(defn db-read [query & args]
  (sql/with-connection 
    db
    (sql/with-query-results res (vec (cons query args)) (doall res))))

(defn read-guests []
  (db-read "SELECT * FROM guestbook ORDER BY timestamp DESC"))

(defn save-message [{:keys [name message]}]
  (sql/with-connection 
    db
    (sql/insert-values
      :guestbook
      [:name :message :timestamp]
      [name message (new java.util.Date)])))

and we're done.

@noonien
Copy link

noonien commented Jul 30, 2012

You do realize the main argument was that Python code was clearer than PHP's, right? This code is hardly readable, IMHO. However it might be because I have no experience whatsoever with Clojure, nor do I want to.

@yogthos
Copy link
Author

yogthos commented Jul 30, 2012

Just because you happen to be unfamiliar with the syntax doesn't mean the code is not clean or hard to read for somebody who actually works with the language. I certainly find it a hell of a lot more readable than PHP myself. Also, can you point out what specifically is hard to read or understand in there?

@noonien
Copy link

noonien commented Jul 30, 2012

I agree, my opinion about the syntax doesn't really matter because I have no familiarity with the language, however, someone coming from PHP will probably have no problem understanding Python, whereas Clojure might appear really confusing. Also, in the main article, the author has also shown a method of deployment.

The templating syntax would be pretty hard to explain to designers (IMHO). And the usage of SQL might, to some, make the code harder to read(mixing languages), but you could probably get rid of those queries quite easilt.

@yogthos
Copy link
Author

yogthos commented Jul 30, 2012

The deployment for the Clojure version is simply doing lein uberjar which will produce a runnable jar, then you can run it with java -jar guestbook.jar, if you wanted to run it on an app server it's not any harder, you just run lein ring uberwar and it makes a deployable package that runs on any java appserver.

whereas Clojure might appear really confusing

While it's different syntax, I would say Clojure is a lot less quirky than PHP or Python, in fact here's a perspective somebody coming from Ruby http://briancarper.net/blog/536/clojure-from-a-ruby-perspective it's just not that different.

The templating syntax would be pretty hard to explain to designers (IMHO)

The templating syntax translates to HTML one to one, but you can always use a different templating library that actually uses xml, like enlive, I have yet to see that being an issue though.

And the usage of SQL might, to some, make the code harder to read(mixing languages), but you could probably get rid of those queries quite easilt.

They're the same queries you have in PHP and Python, so I'm not sure how that's an argument. But yes you can use a Clojure library like korma to avoid writing SQL completely.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment