Wednesday, February 27, 2008

'ey! Markio!

Mark-ee-oh. Whenever I say that out loud, I think of some generic movie from the early 90s in which Markio and his “crew” “hang out” and shoot “ball”. It goes something like this…

Friend: “Ey Markio! Lets go shoot some ball!”
Markio: “Alright…”

...Others disagree.

Anyway. _why wrote a couple times about a language called Io. Those posts turned me on to a great language. In his second post he wrote an incredibly small DSL for generating basic HTML. It did that pretty well. Not long after that I started working on a little web framework in Io, deemed “Iota”. Am I not clever? Because, really, what does the world need more than another web framework?

I wrote the first version of the framework. And it works. It has a tiny little ORM and a tiny little session manager and a tiny little html generator, not much different from _why’s. However, the whole thing was rather fragile, and written is a very Ruby-esque style. Ruby-style is just not a very good fit for Io.

So, I took it all apart, am rewriting parts of it, and have decided to release it bit by bit. The first bit is Markio. If you can’t tell, I blatantly poached the name from Markaby (Markup as Ruby). I prefer to think of Markio as… Markaby in Io. Markio.

It comes in at well under 100 lines of code, but handles most of the basic things that a markup tool should handle. Lets look at how to use it…

builder := Markio Env clone
builder build(
  html(
    head( title( >"My Spiffy Web Page" ) )
    body(
      div_header( >"Some header crap" )
      div_content(
        span.spiffy( >"Spiffy span" )
        span.spiffy( >"Another spiffy span" )
        a({"href":"/there"}, >"Link to there" )
      )
    )
  )
)

Its pretty easy to see the similarity to Markaby. There are a few significant differences to the syntax though.

First of all, in Markaby if you want a div with the class “foo” and the id “bar”, you’d type something: div.foo.bar!. The equivalent in Markio is div.foo_bar. Why the divergence? Honestly, I can’t stand the exclamation point thing. Thats really it. I originally intended to use a hash instead of an underscore, however it appears that Io isn’t a fan of that. CamelCase is the way things are done in the Io world, so the use of an underscore shouldn’t be too confusing.

Markio was designed to be easily dropped into a framework or some other such thing. Which means that there needs to be an easy way to drop paramaters into it. (The code is evaluated in the context of the Markio Env. I suppose that could change…) If we were going to do some such, it might look like this…

params := {"id":1234, "flash":"Victory is mine!"}
builder := Markio makeEnv(params)
builder build(
  div.flash( >flash )
  span.your-id( >("Your id is: " .. id) )
)

In short, Markio makeEnv takes a Map and clones Env. It then sets new members on it using the keys and values of the Map passed to it.

The last major difference is that you cannot simply output strings and expect them to be appended to the output. There is an internal string which is built up. So, all literal output needs to be added to it. That is why the “>” operator is used. It simply appends the argument to the stream.

You can grab Markio right here!

A few notes: First, you may have noticed the strange Map literal syntax I was using. This isn’t built into Io. But its dead easy to add it. I love Io. Grab the code for that here. Secondly, there are a couple known bugs with Markio. First of all, it does not make self-closing tags at the moment. There is a TODO in the code to make that work. Secondly, setting attributes is a bit odd. If you make the first argument to the tag a Map, it will work… as long as there is another argument. If you pass just a Map (a({"href":"blah"})) it will fail. The simple workaround at the moment is just to pass a nil as a second argument.

Have fun. Let me know if you love it… or hate it… or hate me.

Tuesday, February 05, 2008

Io App Server

Recently, _why wrote about a fairly unknown language called Io. He talked about some of the amazing inference features in Io. (Well… Really just the Call object. But that single object puts Io well beyond most languages with regards to reflecting on itself.) Io’s website has a brief list of where its main features came from. However, I’ve been telling people that it works like a combination of Javascript (protoype-based object system) and Lisp (macros). In fact, however, Lisp and Javascript already have a lot in common, so it really just reminds me of Lisp with syntax.

Getting to the point, however. I like Io. Also, it has become my tradition lately to write a little web server in languages that I’m learning as a sort of first project. (Theres a few reasons for this. Namely, it gets into text processing, using external libraries, i/o, system calls, etc… Practical things.) So, I started doing this as normal with Io… however I ended up going a bit further.

So… Introducing the first alpha release of Iota, my tiny Io application framework. Along with Brio, an application server written in Io that plays nicely with Iota.

A few notes. First, I’m a complete newb to Io. So, if anyone out there who is more familiar with Io would like to tear it apart and stomp on the coding style, I’d appreciate it. Secondly, I tried to write Iota in a pragmatic fashion, with a small blog application as my model. So, the features it has may be tied a bit too closely to that model. This will change in time. Lastly, there are currently no tests. There is one simple reason for this: I did it for fun, and I don’t find tests to be fun. This should, and probably will, be rectified before I convert this blog over to Iota.

Sunday, January 13, 2008

Beginning Io

I’m pretty excited about this programming language “Io”. _why the lucky stiff has been writing about it a bit lately over on Hackety. He’s been writing about the insane inflection the language allows. Its pretty much directly on par with Lisp… and in fact, I wonder if it couldn’t be classified as a dialect of Lisp… with syntax.

Anyway… The inflection is great, and I’m sure I’ll use it more as I progress further with the language. However, I like to start small… and one of the first things I try to do when I pick up a new language is write a little web server with it.

In this case, I’ve decided to go a bit further and write a little blog application with it.

The easy route would be to just use the CGI capabilities that Io comes with. But thats not what we’re going to do… because why do easy when you can do fun? So, we’re going to throw together a little, buggy application server. Then we’ll build the blog on top of it.

First things first, we’re going to need to setup a basic web server.

AppServe := Server clone 

AppServe handleSocket := method(socket,               
                socket streamWrite( "Foobar" )
                socket close) 

AppServe start

Kick off a new browser tab and head to localhost:8000. You should see truth written all over your monitor. I mean… It works! Great, so now we have a place to start.

Lets consider for a moment exactly what our application server needs to do. In this case, we’re not interested in serving static files like a real web server. We just need it to give an application, which we’ve not yet defined, an easy way to get requests… and send responses.

For this exercise then, we’re just going to make a simple event-based system. The application server is initialized by the application. The application provides a callback to the server. Whenever a request comes in, the callback is called, and the application gets the data it needs. What it sends back is a response, and we’ll deal with that in a little while.

AppServe run := method(port, handler,
                  self setPort(port)
                  self handler := handler
                  self start)

AppServer run simply takes a port and a callback… and starts the server. Easy enough. Moving along…

Request := Object clone do( raw := nil resource := nil httpVersion := nil httpMethod := nil headers := nil body := nil )

Request parse := method(data, self raw = data

requestLines := data split("\n")
statusParts := requestLines at(0) split
self httpMethod = statusParts at(0)
self resource = statusParts at(1)
self httpVersion = statusParts at(2)
headerLines := requestLines slice(1, requestLines indexOf("") - 1)
self headers = headerLines map(v, v split(": "))
self body = requestLines slice( headerLines size + 2 ) join("\n") )

Response := Object clone do( status := 200 reason := “OK” headers := nil body := nil

init := method(
          headers = Map clone atPut("Content-Type", "text/html") ) )

Response assemble := method( lines := List clone

lines append("HTTP/1.1 #{status} #{reason}" interpolate)
headers foreach(k, v, lines append("#{k}: #{v}" interpolate))
lines append("")
lines append(body)
lines join("\n") )

AppServe := Server clone do( setPort(8000) handleSocket := method(socket, socket streamReadNextChunk data := socket readBuffer

response := Response clone
request := Request clone
request parse(data)
response = handler call(request, response)
socket streamWrite( response assemble )
socket close) )

AppServe run := method(handler, self handler := handler self start)