Friday, October 2, 2009

First Steps With Chicago Boss

All right. Well, hopefully you found a delightful Chicago Boss graphic greeting you as you completed the Getting Started article. But that wasn't particularly satisfying. So let's build a simple "todo" application and examine the steps (and pitfalls and caveats) as we go.

1. The Models

Our simple applicaiton will have two model definitions, one for "categories" of todo items (e.g. "personal", "work") and one for the todo items themselves.

Model/todo_category.erl:
-module(todo_category, [Id, Name, Description]).
-compile(export_all).
-has_many(todo_items).

Model/todo_item.erl:
-module(todo_item, [Id, TodoCategoryId, Name, Description]).
-compile(export_all).
-belongs_to(todo_category).

OK. A word about "belongs_to" -- you must have a CamelCaseId in the main module definition which corresponds exactly to the corresponding model referenced by "belongs_to". It could have been placed at the end of the list, e.g. "-module(todo_item, [Id, Name, Description, TodoCategoryId])." but I tend to put these "foreign key" bits at the beginning. YMMV.

2. The Controller

There's a lot going on in this controller, I'll explain it later. First, the code:

Controller/todo_controller.erl:
-module(todo_controller).
-compile(export_all).

item_list(Req) ->
    Items = boss_db:find(todo_item, [], 100),
    {ok, [{item_list, Items}]}.

items_by_category(Req) ->
    CategoryId = Req:get_qs_value("category_id"),
    Category = boss_db:find(CategoryId),
    Items = boss_db:find(todo_item, [{todo_category_id, CategoryId}], 100),
    {ok, [{item_list, Items}, {category, Category}]}.

new_item_form(Req) ->
    Categories = boss_db:find(todo_category, [], 100),
    {ok, [{category_list,Categories}]}.

new_item_submit(Req) ->
    CategoryId = Req:get_post_value("item_category_id"),
    Name = Req:get_post_value("item_name"),
    Description = Req:get_post_value("item_description"),
    Item = todo_item:new(id, CategoryId, Name, Description),
    SavedItem = Item:save(),
    {redirect, lists:concat(["item?id=", [SavedItem:id()]])}.

item(Req) ->
    ItemId = Req:get_qs_value("id"),
    Item = boss_db:find(ItemId),
    {ok, [{item, Item}]}.

category_list(Req) ->
    Categories = boss_db:find(todo_category, [], 100),
    {ok, [{category_list,Categories}]}.

new_category_submit(Req) ->
    Name = Req:get_post_value("category_name"),
    Description = Req:get_post_value("category_description"),
    Category = todo_category:new(id, Name, Description),
    SavedCategory = Category:save(),
    {redirect, "category_list"}.

category(Req) ->
    CategoryId = Req:get_qs_value("id"),
    Category = boss_db:find(CategoryId),
    {ok, [{category, Category}]}.

All right. First a word about controllers in general. Chicago Boss automatically (convention, not configuration) routes requests to /some/word to Controller/some_controller.erl:word(Req) if that controller and method exist. For a simple html file, these don't have to exist. We'll see an example of that in a moment.

What I've done here is define a few web entry points to the application: "/todo/item_list", "/todo/items_by_category", "/todo/new_category_submit", etc. Most of these methods return a simple "ok" tuple along with some data. Some of them, the callbacks for create form submission, use "redirect" to send the user along to an appropriate page instead of simply presenting a "OK, thanks for your submission" page.

You also see a few of the methods available: Req:get_qs_value to get a value from a query string, and Req:get_post_value to get a value from a form submit. Of particular interest might be the "boss_db:find" examples. We could add these as ease-of-use functions in our models themselves, but for now, let's go with what we have. (Noting that I'm not showing update or delete paths yet in this snippet: so far just create and read.)

3. The Views

All right. We have defined a model and some controller routes for our web application, but to present data back to the user, we'll need some views. I'm not going to present all the views necessary to implement this application, or present them in full xhtml-strict compliance glory (what would be the fun in that?) but I will give a few of the nicer bits which show off some of the templating goodness available.

View/todo/item_list.html:
<table>
  <tr>
    <th>category</th>
    <th>name</th>
    <th>description</th>
  </tr>

{% for item in item_list %}
  <tr>
    <td><a href="category?id={{ item.todo_category.id }}">{{ item.todo_category.name }}</a></td>
    <td><a href="item?id={{ item.id }}">{{ item.name }}</a></td>
    <td>{{ item.description }}</td>
  </tr>
{% endfor %}
</table>

<a href="new_item_form">create new</a>

All right. A for loop and some inline string data. Whee. Well, actually, that's pretty much all you need to do 90% of what a view should be doing. There's more under the covers, but that will have to wait until a more in-depth article on the view template features.

Getting Started with Chicago Boss

So, you heard about Chicago Boss, the new web application framework for Erlang, and tried to get started, and ran into the brick wall of undocumentation.


No worries, mate.


First, obviously, you'll need Erlang itself, specifically version 13 and up:


wget http://erlang.org/download/otp_src_R13B02-1.tar.gz
tar xzvf otp_src...
cd otp_src...
./configure
make
sudo make install

And for Chicago Boss you'll need Tokyo Cabinet, a new-ish file-based database:


wget http://1978th.net/tokyocabinet/tokyocabinet-1.4.33.tar.gz
tar xzvf tokyoca...
cd tokyoca...
./configure
make
sudo make install

And you'll need Tokyo Tyrant, which acts as a network server for Tokyo Cabinet:


wget http://1978th.net/tokyotyrant/tokyotyrant-1.1.34.tar.gz
tar xzvf tokyoty...
cd tokyoty...
./configure
make
sudo make install

Now, Chicago Boss says you need a "table" database up and running. All this means is, in one terminal window (or screen session), run:


ttserver my.tct

Now, "my.tct" doesn't have to exist, you didn't have to learn how to use Tokyo Cabinet's commands to create it (though there are worse uses of your time), and Tokyo Tyrant will create it. The ".tct" extension means "Tokyo Cabinet Table" database, and it knows now to treat it like a table database instead of one of its other supported formats (hash, btree, etc.).


OK. Now suck down the Chicago Boss git and build it:


git clone git://evanmiller.org/git/ChicagoBoss.git
cd ChicagoBoss
make

Finally, start-dev.sh inside the ChicagoBoss git repository you've just downloaded, and visit http://localhost:8001/hello/world to ensure you've got things runnings.


Now, and here's the fun part, in another screen start adding models, views, and controllers. They are included and reloaded automatically. More on how to actually do this (another undocumentation wall) in the next post.


Update: If you found this article useful, there's a followup 'first steps' article entitled First Steps With Chicago Boss.

Wednesday, April 4, 2007

The unofficial and official reddit stance on copyright

The official reddit stance on copyright is fairly easy to see. It's the footer text of every page: (c) 2007 CondeNet, Inc. All rights reserved. It makes sense for reddit to have this official stance; after all, the entire chain of software, services, and tooling upon which it is built are also built upon the foundations of copyright:

Python, the programming language in which reddit is written, is Copyright © 1990-2006, Python Software Foundation. The components of reddit's python code, such as the CherryPy WSGI components, are Copyright (c) 2004-2007, CherryPy Team and others.

Lighttpd, the web server used by reddit's servers, is Copyright (c) 2004, Jan Kneschke.

The project management and bug tracking software for Lighttpd (and CherryPy) is Trac, Copyright © 2003-2006 Edgewall Software.

Much of the more popular content (xkcd, newspapers, other sites) are also under various copyrights and accompanying licences.

So much for the official stance.

Now, unofficially and despite the widespread preference for copyrighted material (see the "more popular content" statement above) there seems to be broad support among the reddit user base to actually abolish copyright, as exemplified in a recent top-rated link Why you SHOULD be a pirate. The discussion even invaded the apolitical sanctity of my beloved programming subreddit in the form of the link Copyright infringement is not theft. In both discussions, there seems to be quite widespread support for getting rid of copyright.

I find this quite ironic given the nature of reddit as a copyrighted product, its base of copyrighted software, and particularly the interest in the form of upvotes of all sorts of copyrighted material. Perhaps the same anti-copyright discussion could be had on a completely public domain message board somewhere, but I am not aware of any internet-capable public domain operating systems. I encourage those among the redditor crowd who believe strongly in their anti-copyright stance to produce a public domain software stack upon which to discuss this topic and with which to distribute their public domain art, music, and film.

I would join them in contributing software and photography, the latter of mine of which primarily ends up in the Wikimedia Commons under a ShareAlike license, but I am certainly willing to put my code and photographs where my mouth is. I wonder if any of the redditors who so strongly support the anti-copyright movement would really do the same?

Further irony: the majority of Gnutella and BitTorrent clients are copyrighted software (several even completely proprietary). The famous Pirate Party of Sweden goes the step of clearly marking their internet content No copyright, Piratpartiet, 2006–2007, but something interesting happens when you connect to their web server:
sam@sol:~/projects/erlang/sway$ telnet www2.piratpartiet.se 80
Trying 217.198.145.137...
Connected to kaukbacken.homelinux.net.
Escape character is '^]'.
GET / HTTP/1.1
Host: www2.piratpartiet.se

HTTP/1.1 200 OK
Date: Wed, 04 Apr 2007 20:06:13 GMT
Server: Apache
X-Powered-By: PHP/5.2.1-pl3-gentoo


You guessed it. Apache, PHP, and Gentoo (a Linux distribution)? All copyrighted software.

I welcome our new public domain overlords. Copyright is dead. Long live the public domain. It would be nice to see proponents of the anti-copyright movement eat their own cooking, though, and to take at least a few moments to notice the hypocrisy and irony of the situation when they do not.

Draconian DRM and the seemingly limitless extensions on the duration of copyright are an issue. Copyright itself is a good. To verify this, simply check the "Help -> About" menu of your browser for its copyright information.