HN user

svetlyak40wt

75 karma

I'm a lead software developer at Yandex. I'm specializing in web development, python and c++. My opensource projects are at the GitHub: http://github.com/svetlyak40wt/

Posts11
Comments45
View on HN
[dead] 3 years ago

Turn on english subtitles if you don't speak Russian.

In this video, I tell you how to make a complex web application in Common Lisp and Clack.

You will see how you can add different middleware to your application, for example, logging all HTTP requests.

I will also show you how to distribute static files from the CL web server and how to combine several Clack applications in one server so that each application responds in its own route.

Also, I will explain the difference between Clack and Hunchentoot. If you want to learn about it, watch the video to the end!

Spinneret is better than CL-WHO at least in it's string escaping policy. All values are escaped by default whereas with CL-WHO you need to wrap with CL-WHO:ESC all string values.

Thus CL-WHO is vulnerable to XSS attack by default.

You can define your own syntax in CL:

    CL-USER> (set-macro-character #\{
           (lambda (str char)
             (declare (ignore char))
             (let ((*readtable* (copy-readtable *readtable* nil))
            (keep-going t))
        (set-macro-character #\} (lambda (stream char)
              (declare (ignore char) (ignore stream))
              (setf keep-going nil)))
        (let ((pairs (loop for key = (read str nil nil t)
            while keep-going
            for value = (read str nil nil t)
            collect (list key value)))
              (retn (gensym)))
          `(let ((,retn (make-hash-table :test #'equal)))
             ,@(mapcar
         (lambda (pair)
           `(setf (gethash ,(car pair) ,retn) ,(cadr pair)))
         pairs)
             ,retn)))))
    T
    
    CL-USER> {:foo 100500 :bar 42}
    #<HASH-TABLE :TEST EQUAL :COUNT 2 {1005879463}>
    
    CL-USER> (alexandria:hash-table-alist #v1)
    ((:BAR . 42) (:FOO . 100500))
    CL-USER> 

And define a printer for the hash to output it as desired:
    CL-USER> (defmethod print-object ((obj hash-table) stream)
               (princ "{" stream)
               (loop with indent = nil
                     for key being the hash-keys in obj using (hash-value value)
                     when indent
                       do (format stream "~% ")
                     unless indent
                       do (setf indent t)
                     do (format stream "~S ~S" key value))
               (princ "}" stream))
    #<STANDARD-METHOD COMMON-LISP:PRINT-OBJECT (HASH-TABLE T) {10040C9F83}>
    
    CL-USER> {:foo 100500 :bar 42}
    {:FOO 100500
     :BAR 42}

I'd recomment a ClozureCL instead of SBCL for a newcomer, because CCL does not do some optimizations and it is easier to debug. For example, it will show you local variables created by `let`, but SBCL – does not.