The best kittens, technology, and video games blog in the world.

Monday, July 24, 2006

RLisp gets HTTP support

This isn't quite a hello-world, because I want to show how to use macros for building HTTP services. First, we need to tell Ruby to load webrick module and bind class name into RLisp namespace (there is no automatic importing of constants, maybe there should me):

(ruby-eval "require 'webrick'") ; import module
(let HTTPServer (ruby-eval "WEBrick::HTTPServer")) 
Now let's create the server object and tell it to bind to port 1337 instead of default port 80. Configuration is simply a hash table:
; Configure the server
(let config [Hash new])
[config set 'Port 1337]
; Tell the class to make us a server object
(let server (send HTTPServer 'new config))
Now we could basically send mount_proc message to server object to bind a lambda to URL.
; Tell server to call our Hello World handler
(send server 'mount_proc "/hello"
   (lambda (req res)
       [res body= "<html><body><h3>Hello, world!</h3></body></html>"]
       [res field_set "Content-Type" "text/html"]
   )
)
But this is not very nice. Let's macro around this definition. First let's make a macro that lets us bind more easily:
; Define a macro for HTML mounts
(defsyntax def-server-html-mount args
   `(send ,[args get 0] 'mount_proc ,[args get 1]
       (lambda (req res)
           (send res 'field_set "Content-Type" "text/html")
           (send res 'body= (do ,@(tl (tl args))))
           (print res)
       )
   )
)
Now we can rewrite the original handler to:
; Tell server to call our Hello World handler
(def-server-html-mount server "/hello"
   "<html><body><h3>Hello, world!</h3></body></html>"
)
The mount is as good as it gets, but we'd still rather have nice syntax for HTML. So let's define a macro that creates html-generating functions:
; Define a macro for HTML tag function
(defsyntax def-html-tag (tagname)
   `(defun ,tagname args
       (+
       "<"  (send ',tagname to_s) ">"
       [args join]
       "</" (send ',tagname to_s) ">"
       )
   )
)
And define a few such functions:
(def-html-tag html)
(def-html-tag body)
(def-html-tag h3)
Could it be any more cute than that ?
(def-server-html-mount server "/hello2"
   (html (body (h3 "Macros Greet you")))
)
Happy about the results, we start the server:
; Tell the server to go !
(send server 'start)
RLisp is available for download from http://taw.github.io/rlisp/. Previous posts about RLisp are here [1] and here [2].

2 comments:

Łukasz Biegaj said...

Can you post here how does look http_server_hello.rl implemented in plain Ruby?

taw said...

It looks remarkably similar:

require 'webrick'

# Configure the server
config = {:Port => 1337}

# Tell the class to make us a server object
server = WEBrick::HTTPServer.new(config)

# Tell server to call our Hello World handler
server.mount_proc("/hello") {|req,res|
res.body = "<html><body><h3>Hello, world!</h3></body></html>"
res["Content-Type"] = "text/html"
}

# Tell the server to go !
server.start