Zoetrope

a blog about web apps, Lisp, Rails and all the REST ...

Lisp bundle for Textmate

There's a nice Lisp bundle for Textmate available, it ads syntax highlighting and snippets for defun, defmacro, setf etc. Just check it out with subversion:

>$ cd Library/Application\ Support/Textmate/Bundles/
svn co http://macromates.com/svn/Bundles/trunk/Bundles/Lisp.tmbundle/

Textmate Lisp Bundle

tags: ,

Common Lisp First Contact: an easygoing introduction to Lisp

Sven Van Caekenberghe, author of the KPAX web-application framework has published a nice and easy-to-read introduction to Common Lisp a called Common Lisp: First Contact. If you're not familiar with the Common Lisp programming languange and its syntax and have 10 minutes to spare it makes one hell of an introduction and the PDF is beautifully tuned for reading it on your widescreen monitor.

tags: ,

Make mistakes fast, fix them even faster

A great blog-post about Lisp and some of principles of Agile Development. Having a very short edit-compile-run cycle (put on your "I HEART REPL" badge) spoils you to no end. Also see this InfoQ article about the same topic.

I consider it one of the biggest advantages of a Lisp development environment, and am glad the same warm and fuzzy feeling is around when coding Ruby. Smalltalk programmers would agree also.

It's even more important when you're developing web applications I think, where things like XHTML, CSS and Javascript come into play. I've got bad habits on that end, my cycle can often be too short: code 3 lines, ALT-TAB Firefox and hit CMD-R; rinse and repeat. I would tear out my hairs if I had a long compile cycle or had to restart web-servers...

tags:

using Lisp to store your data on Amazon S3

If you want to access your Amazon S3 account, take a look at CL-S3 from Sven Van Caekenberghe. It's simpler than wrestling with curl and the Amazon webservices authentication ;-)

What you need

CL-S3 has the following dependencies, most of which are other packages from Sven, and most are installable using ASDF-INSTALL

  • s-http-client, to speak the HTTP lingo
  • s-xml, no webservices without XML right?
  • s-utils, some utility code that CL-S3 uses
  • s-base64, al your base are belong to us!
  • KPAX, Sven's web framework (for URI-encoding functions) the latest version does not need KPAX
  • ironclad, Nathan Froyds nice cryptography package, providing MD5 functionality

Download CL-S3 from Amazon S3 itself and symlink its cl-s3.asd in your ASDF systems directory.

So fire up your favourite REPL (I'm using Lispworks Personal Edition for this example) and load it al up using ASDF:


CL-USER 3 > (setf (logical-pathname-translations "home")
              `(("**;*.*.*" ,(concatenate 'string (namestring (user-homedir-pathname)) "**/*.*"))))
               (("**;*.*.*" "/Users/tarkin/**/*.*"))

CL-USER 4 > (unless (member :asdf *features*)
              (load #p"home:Lisp;asdf;init-asdf"))
; Loading text file /Users/tarkin/lisp/asdf/init-asdf.lisp
;  Loading text file /Users/tarkin/lisp/asdf/asdf.lisp
;Pushed #P"/Users/tarkin/lisp/asdf/systems/" onto ASDF central registry
#P"/Users/tarkin/lisp/asdf/init-asdf.lisp"

CL-USER 5 > (asdf:operate 'asdf:load-op :cl-s3)
; loading system definition from /Users/tarkin/lisp/asdf/systems/cl-s3.asd into
...
; Loading fasl file /Users/tarkin/Lisp/cl-s3/cl-s3-package.nfasl
; Loading fasl file /Users/tarkin/Lisp/cl-s3/cl-s3.nfasl
NIL

Giving CL-S3 the lowdown on your account

Set up your Amazon webservices access identifiers (access key id and secret access key id)


CL-S3 7 > (setf *access-key-id* "AAAAYKR2D401BBB09CCC")
"AAAAYKR2D401BBB09CCC"

CL-S3 4 > (setf *secret-access-key* "ooh_my_secret_is_very_secret")
"ooh_my_secret_is_very_secret"

Doing the deed

So now we should be able to query the service using CL-S3.


CL-S3 11 > (get-service)
;; CL-S3 GET http://s3.amazonaws.com/
((|ListAllMyBucketsResult| :|xmlns| "http://s3.amazonaws.com/doc/2006-03-01/") 
 (|Owner| (ID "beeec79bbda42e62b7ac74273effdabef1ddadf1b22b4c683cc91bf64d62f033") 
          (|DisplayName| "nickypeeters")) 
 (|Buckets| 
  (|Bucket| 
   (|Name| "lisp") 
   (|CreationDate| "2007-05-29T13:46:12.000Z"))))
200
((:X-AMZ-ID-2 . "wb2EU2Etuv8Mw6+Y9jonKPm6lf0uGMxfcspgwnKK0YRCYorteJ08FH1cmD5ZhtpU") 
 (:X-AMZ-REQUEST-ID . "07C15D88FD3EB8CD") (:DATE . "Tue, 29 May 2007 17:51:23 GMT") 
 (:CONTENT-TYPE . "application/xml") 
 (:TRANSFER-ENCODING . "chunked") 
 (:SERVER . "AmazonS3"))
#<URI http://s3.amazonaws.com:80>
:KEEP-ALIVE

Let's make a bucket to hold our objects in using put-bucket


CL-S3 15 > (put-bucket "zoetrope")
;; CL-S3 PUT http://s3.amazonaws.com/zoetrope
""
200
((:X-AMZ-ID-2 . "Dxl2qxeYXo6VvuOBscjnWEQaPZjaQlk97E+XLsL+DVRVmQMafEaRrpEnFrWyf5k9") 
 (:X-AMZ-REQUEST-ID . "BE93305AD58B1777") 
 (:DATE . "Tue, 29 May 2007 18:01:36 GMT") 
 (:LOCATION . "/zoetrope") 
 (:CONTENT-LENGTH . "0") 
 (:SERVER . "AmazonS3"))
#<URI http://s3.amazonaws.com:80/zoetrope>
:NEW

Put a little text under the new bucket using put-object. You need to provide a key (e.g. filename) and the content-type of the object (e.g. text/plain). S3 returns also returns the uri of the new object.


CL-S3 16 > (put-object "zoetrope" 
            "practical-common-lisp" 
            "Practical Common Lisp is a nice book on Common Lisp" 
            "text/plain")
;; CL-S3 PUT http://s3.amazonaws.com/zoetrope/practical-common-lisp
""
200
...
#<URI http://s3.amazonaws.com:80/zoetrope/practical-common-lisp>
:NEW

So lets see if Amazon S3 really has our little text at http://s3.amazonaws.com:80/zoetrope/practical-common-lisp using an s-http-client request


CL-S3 17 > (s-http-client:do-http-request "http://s3.amazonaws.com:80/zoetrope/practical-common-lisp")
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<Error>
  <Code>AccessDenied</Code>
  <Message>Access Denied</Message><RequestId>4BA0925CDE61CC24</RequestId>
  <HostId>T2NKSHtx1nOaLcbcllgy62wPlDP/GPp//MecPlcORke/gFSE7M2zpVEevGtlmIGq</HostId>
</Error>"
403
...

Oops ! S3 returns an AccessDenied error in XML. By default any object you put is for-your-eyes-only. So let's make an authenticated request using get-object


CL-S3 20 > (get-object "zoetrope" "practical-common-lisp")
;; CL-S3 GET http://s3.amazonaws.com/zoetrope/practical-common-lisp
"Practical Common Lisp is a nice book on Common Lisp"
200
...

Uploading a file and making it public

CL-S3 doesn't have a file-upload utility method, so let's use a quick slurp-file function. We set the object to public and read-only by using the canned access-policy with the x-amz-acl header of public-read


CL-S3 21 > (defun contents-of-file (pathname)
  (with-output-to-string (contents)
    (with-open-file (in pathname :direction :input)
      (s-utils:copy-stream in contents))))

CL-S3 22 > (put-object "zoetrope" "lispification.pdf" 
             (contents-of-file "/Users/tarkin/lispification.pdf") 
             "application/pdf" 
             :amz-headers '(("x-amz-acl" . "public-read")))
;; CL-S3 PUT http://s3.amazonaws.com/zoetrope/lispification.pdf
""
200
...
#<URI http://s3.amazonaws.com:80/zoetrope/lispification.pdf>
:KEEP-ALIVE

CL-S3 has 2 utility functions for downloading and uploading files


CL-S3 39 > (download-file "lisp" "lispification.pdf")
;; CL-S3 GET http://s3.amazonaws.com/lisp/lispification.pdf
#<STREAM::LATIN-1-FILE-STREAM /Users/tarkin/lispification.pdf>
200
...
#<URI http://s3.amazonaws.com:80/lisp/lispification.pdf>
:KEEP-ALIVE

You can see the function returns the file-stream where the file was written. You can optionally give a directory to save the file in. Uploading a file works in the same way.


CL-S3 40 > (upload-file "/Users/tarkin/Lisp/init_lispworks.lisp" "lisp" 
         :mime-type "text/plain" :acl "public-read")
;; CL-S3 PUT http://s3.amazonaws.com/lisp/init_lispworks.lisp
""
200
...
#<URI http://s3.amazonaws.com:80/lisp/init_lispworks.lisp>
:KEEP-ALIVE

Check out the CL-S3 API docs for more info.

Flex your XML muscles into a '( )

For some reason it seems today is all about XML. A nice post over on defmacro.org introduces non-Lispers to the infamous parenthesis by ways of comparing XML to Lisp code. So if you already expose yourself to the wonders of XML as a developer, you should be able to gradually come to love the parenthesis.

And then I come across a screencast about Adobe Flex development which strikes me as a another example for the article above. Flex is a combination of lots of XML, intermingled with ActionScript. It even has special binding expressions that refer to data/code. A real pity that halfway through the screencast they have to resort to a CDATA statement to mix-in some actual code (an event handler in the example). No wonder we don't find XML magic [anymore] after learning Lisp.

Flex looks great though. I can see it getting some traction soon, especially if you take technologies like Apollo in account.

But wouldn't it be bliss if we could Flex our muscles in Lisp instead ?

tags: