The random rantings of a concerned programmer.

(Untitled)

March 30th, 2009 | Category: Random

So, I’ve been working on my Haskell Web Framework shit (oh god). My current project is rewriting the abortion of a codebase, LulzBB, in Haskell. LulzBB is a PhpBB clone written in PHP. It was born after I got so sick and tired of maintaining shittons of modifications to the PhpBB codebase (which is an even bigger failed abortion, if that’s possible).

One of the “FUCK THAT WAS A TERRIBLE IDEA”s in the original version of LulzBB was keeping the same ill-conceived database schema as PhpBB. Instead, I’m going to use one that isn’t absolute shit (and going to use PostGRES instead of MySQL, though that’s more of a deployment difference since HDBC is awesome).

Anyway it’s still a shitty web forum and it’s gonna have the same shitty features as every other fucking forum software except it’ll be in Haskell and isn’t that great. Also I’m toying around with git, so if you want to see how shitty my code actually is (spoiler: it’s really shitty) you can visually molest your eyes at github.

7 comments

(Untitled)

January 25th, 2009 | Category: Random

I ended up just using Text.Regex to parse the Symfony routing.yml bullshit. Basically, I’ve got a bit of code which reads in some routing Yaml like

index:
  url: /index
  param: { module: index }

tag_list:
  url: /tag
  param: { module: tag, action: list }

tag_view:
  url: /tag/:id
  param: { module: tag, action: view }

Then as a build step parse and transform it into a couple tables which get statically linked into the application –

module Site.RoutingTable where
import qualified Site.Index
import qualified Site.Tag
import Data.Map (fromAsc)
import Routing (Route (..))

actionTable = fromAscList [
        (("Index", "index", Site.Index.index),
        (("Tag", "list"), Site.Tag.list),
        (("Tag", "view"), Site.Tag.view)]

urlTree = Branch ([Branch ([Literal ("tag",RouteEnd (Just [("module","tag"),
("action","list")]))],Just (Parameter ("id",RouteEnd (Just [("module","tag"),
("action","view")])))),Literal ("index",RouteEnd (Just [("module","index")]))],Nothing)

Basically, the urlTree is a decision tree which contains all the possible paths through the tree –

- index - end
| tag   - end
        | :id - end

When a request needs to be routed, the URL is split with the '/' delimiter into a list of strings. The pop is popped off the front of that list at each level of the tree until it hits an RouteEnd element or a Branch element with no corresponding Literal and no Parameter or Wildcard part (in the later case, the route fails and a HTTP 404 response should be returned).

Parameter and Wildcard nodes are only taken when there isn’t a competing Literal node. When a Parameter node gets taken, the value it corresponds to gets pushed onto an associative list for processing later on.

When the routing process hits the end, the RouteEnd node contains the parameters specified in the Yaml. Those parameters are merged with the parameters generated by the Parameter nodes in the tree traversal (but will not overwrite — the parameters in the Yaml simply serve as defaults).

Thus we can route a Url -> Parameters where Url :: String and Parameters :: [(String, String)].

Next, we need to resolve what code to execute. Contained within the parameters be a "module" and a "action" parameter — these are resolved in the table to a function pointer within the application’s namespace. The application functions are all existentially quantified as

data Action = forall a. IConnection a => MkAction (RouteParameters -> a -> String)

– they get passed both a HDBC database reference and the URL parameters and return a string which gets output to the browser.

A good use of a weekend, I guess. [source]

1 comment