From 054d6cb994c7619ad6333abb5cc0ccd0e736bc41 Mon Sep 17 00:00:00 2001 From: Mighty Byte Date: Sun, 18 Mar 2012 11:33:34 -0400 Subject: [PATCH 1/5] Add warning to 0.8 release notes. --- blogdata/content/2012/03/16/snap-0.8-released.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/blogdata/content/2012/03/16/snap-0.8-released.md b/blogdata/content/2012/03/16/snap-0.8-released.md index d2fe71a..19f43d4 100644 --- a/blogdata/content/2012/03/16/snap-0.8-released.md +++ b/blogdata/content/2012/03/16/snap-0.8-released.md @@ -7,6 +7,9 @@ The Snap team would like to announce the release of version 0.8 of the Snap Framework. +NOTE: If you use the heist snaplet, then 0.8 will break your application. It +will still compile, but it won't work. See below for details. + ## New features / improvements From f19603a1648460d7147cd3b596536d1f9ee84dc0 Mon Sep 17 00:00:00 2001 From: Mighty Byte Date: Sun, 18 Mar 2012 14:08:15 -0400 Subject: [PATCH 2/5] Update the basic API tutorial (more of an overhaul), quickstart, and snaplets tutorial. --- snaplets/heist/templates/docs/quickstart.md | 12 +- .../templates/docs/tutorials/snap-api-new.md | 286 ------------------ .../templates/docs/tutorials/snap-api.md | 235 ++++++-------- .../docs/tutorials/snaplets-tutorial.lhs | 14 +- 4 files changed, 109 insertions(+), 438 deletions(-) delete mode 100644 snaplets/heist/templates/docs/tutorials/snap-api-new.md diff --git a/snaplets/heist/templates/docs/quickstart.md b/snaplets/heist/templates/docs/quickstart.md index f34327e..0cf1e33 100644 --- a/snaplets/heist/templates/docs/quickstart.md +++ b/snaplets/heist/templates/docs/quickstart.md @@ -17,12 +17,15 @@ To set up a new Snap project, run the following commands: ~~~~~~ {.shell} $ mkdir myproject $ cd myproject -$ snap init +$ snap init barebones ~~~~~~ The `snap init` command creates a template Snap project in the current -directory. The `Main` module for this project will be created in `src/Main.hs`. -When you build this project with `cabal install`, an executable is created in +directory. You can also do `snap init -h` to see help about other project +templates that are available. For now we'll focus on the barebones project. + +The `Main` module for this project will be created in `src/Main.hs`. When you +build this project with `cabal install`, an executable is created in `$HOME/.cabal/bin` called `myproject`. To build and run the example application, run the following commands: @@ -33,7 +36,8 @@ $ myproject -p 8000 Now point your web browser to [http://localhost:8000/](http://localhost:8000/); you should see a simple response string. To activate dynamic recompilation in -your project, build with "cabal install -fdevelopment". +your project, first build snap with "cabal install snap -fhint" and then +rebuild your application with "cabal clean; cabal install -fdevelopment". For more information, continue on to the [Snap API tutorial](tutorials/snap-api) or take a look at the [Snap diff --git a/snaplets/heist/templates/docs/tutorials/snap-api-new.md b/snaplets/heist/templates/docs/tutorials/snap-api-new.md deleted file mode 100644 index 726c030..0000000 --- a/snaplets/heist/templates/docs/tutorials/snap-api-new.md +++ /dev/null @@ -1,286 +0,0 @@ -## Examining Hello World - -In the [Quick Start Guide](/docs/quickstart), we installed Snap and created a -template "hello world" application. Here we'll look at what's inside the -application and describe basic use of Snap's web server API. - -`snap init` creates two files in the `src` directory, Common.hs and Main.hs. -Common.hs contains general-purpose code that will eventually be integrated -into the Snap framework so you won't have to carry this code with your -application. For now, we've left it out to avoid unnecessary project -dependencies. You don't need to worry about Common.hs unless you want an -in-depth understanding of the infrastructure. Here's the important code in -Main.hs: - -~~~~~~ {.haskell} -site :: Snap () -site = - ifTop (writeBS "hello world") <|> - dir "seeform" (method POST showParams) <|> - route [ ("foo", writeBS "bar") - , ("echo/:echoparam", echoHandler) - ] <|> - dir "static" (fileServe ".") - -echoHandler :: Snap () -echoHandler = do - param <- getParam "echoparam" - maybe (writeBS "must specify echo/param in URL") - writeBS param -~~~~~~ - -The behavior of this code can be summarized with the following rules: - -1. If the user requested the site's root page (http://mysite.com/), then -return a page containing the string "hello world". -2. If the user requested /foo, then return "bar". -3. If the user requested /echo/xyz, then return "xyz". -4. If the request URL begins with /static/, then look for files on disk -matching the rest of the path and serve them. -5. If none of these match, then Snap returns a 404 page. - -Let's go over each of the Snap API functions used here. - -##### [`ifTop`](/docs/latest/snap-core/Snap-Types.html#v%3AifTop) - -`ifTop` only executes its argument if the client requested the root URL. Use -this for your home page. It can also be combined with the `dir` function to -define your index handler for a certain URL directory. - -##### [`writeBS`](/docs/latest/snap-core/Snap-Types.html#v%3AwriteBS) - -`writeBS` appends a strict ByteString to the response being constructed. Snap -also provides an analogous function `writeLBS` for lazy ByteStrings. You can -also use the functions `writeText` and `writeLazyText` if you use Data.Text -instead of ByteString. - -##### [`dir`](/docs/latest/snap-core/Snap-Types.html#v%3Adir) - -`dir` runs its action only if the request path starts with the specified -directory. You can combine successive dir calls to match more than one -subdirectory into the path. - - - - - - - - - - -If you're not familiar with Haskell, you may be wondering about the `<|>`. It -is simply a binary operator that evaluates its first argument, and if it -failed, evaluates the second. If the first argument succeeded, then it stops -without evaluating the second argument. - -The `site` function uses `<|>` to connect three different functions that guard -what page gets rendered. First, the `ifTop` function runs. This function -succeeds if the requested URL is `http://site.com/`. If that happens, then -Snap sends a response of "hello world". Otherwise the `route` function is -executed. - -`route` takes a list of (route, handler) tuples and succeeds returning the -result of the associated handler of the route that matches. If no route -matches, then execution is passed on to `fileServe`. - - - -~~~~~~ {.haskell} -foo :: Snap () -foo = modifyResponse $ setResponseBody $ - (enumBS "foo" >. enumBS "bar" >. enumBS "baz") -~~~~~~ - -This is kind of weird for people who are not used to it because it's an -inversion of control. You as the programmer are not actually sending anything -out to a socket; you're actually assembling a "program", that when given an -iteratee, feeds that data to the iteratee. What actually happens is that we -give the response body enumerator an iteratee that sends data out over the -socket, potentially with a `transfer-encoding` applied. - -For other convenience functions that manipulate the response body enumerator, -consult the [API -documentation](/docs/latest/snap-core/Snap-Types.html#10). - -We hope this quick and dirty introduction to iteratee I/O has shed some light -on using Snap. Some further discussion, the original talk and other iteratee -resources may be found on [Oleg's site](http://okmij.org/ftp/Streams.html). You -can also consult the [iteratee package API -docs](http://hackage.haskell.org/package/iteratee), and the [Haskell -Wiki page on iteratees](http://www.haskell.org/haskellwiki/Iteratee). - -### Routing - -Our goal is to get our toy application to spit back a portion of the request -URL. That is, I want the following behavior: - -~~~~~~ {.shell} -$ curl localhost:8000/echo/ohsnap; echo -ohsnap -~~~~~~ - -So first, we need to tackle how to route URLs. Snap provides two types of -routing functions: combinators and -[`route`](/docs/latest/snap-core/Snap-Types.html#v%3Aroute). Some combinators -are as follows: - -- [`<|>`](http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Applicative.html#v%3A%3C%7C%3E) `:: Snap a -> Snap a -> Snap a` -- [`ifTop`](/docs/latest/snap-core/Snap-Types.html#v%3AifTop) `:: Snap a -> Snap a` -- [`dir`](/docs/latest/snap-core/Snap-Types.html#v%3Adir) `:: ByteString -> Snap a -> Snap a` -- [`method`](/docs/latest/snap-core/Snap-Types.html#v%3Amethod) `:: Method -> Snap a -> Snap a` - -These do exactly what you might think they do. Calling `ifTop`: - -~~~~~~ {.haskell} -foo :: Snap () -foo = ifTop $ do ... -~~~~~~ - -takes an action in the Snap monad and transforms it to only run if the request -path is at the "top level" (specifically, when -[`rqPathInfo`](/docs/latest/snap-core/Snap-Types.html#v%3ArqPathInfo) is -empty). The `dir` combinator transforms the action to run if the request path -starts with the specified directory. The `method` combinator matches on -specific HTTP methods. - -The astute reader will no doubt now see that these functions can be used in -conjunction with `Alternative` semantics of the `Snap` monad to do routing. -However, this kind of routing is expensive in that it can be O(n) in the number -of handlers. To remedy this, Snap also provides you with a function that routes -requests based on the request path in `O(log n)` time: - -- `route :: [(ByteString, Snap a)] -> Snap a` - -This function takes an associative list of paths and actions and combines it -all together into one action that does the routing. It also supports capturing -parts of the path into parameters. - -Let's see this in action to route the path `echo/` to some echo action. Open -up `Main.hs` in your favorite editor and edit `site` to look like the -following. - -~~~~~~~~~~~~~~~ {.haskell} -site :: Snap () -site = route [ ("" , ifTop (writeBS "hello world")) - , ("echo/:s" , echoHandler) ] - <|> fileServe "." -~~~~~~~~~~~~~~~ - -The above code routes the top level empty path to the original "hello world" -action, and the path `echo/` to `echoHandler` (which we haven't written yet). -More importantly, when it routes `echo/`, it captures the next immediate path -component (not the rest of the path) into a parameter named `s`. We can access -`s`, or any other request parameter, with the function -[`getParam`](/docs/latest/snap-core/Snap-Types.html#v%3AgetParam). If the -request was neither to the top level nor to `echo/`, we try to find a file in -the current directory with the same name as the request path and serve that. - -Moving on, let's write `echoHandler`, which should just spit back `s`. - -~~~~~~~~~~~~~~~ {.haskell} -echoHandler :: Snap () -echoHandler = do - s <- getParam "s" - writeBS $ maybe "" id s -~~~~~~~~~~~~~~~ - -Let's build our toy application and run it again. Now we have a perfectly -useless server that echos paths that start with `echo/`. - -~~~~~~ {.shell} -$ curl localhost:8000/echo/foo; echo -foo -~~~~~~ - - -### Error Handling - -Pretend that we wrote this echo server for an elementary school, and the PTA -has requested that profanities be censored and unechoable. The parents of PTA -also happen to be not very bright and have taken the euphemism "4-letter word" -too literally. They have requested that we block all 4-letter words. For -arbitrary reasons, we've decided to respond to echo requests of 4-letter words -by sending a `403 Forbidden` error. - -We'll need `ByteString` utility functions for this, so be sure to add the -following line somewhere in your list of `import`s. - -~~~~~~~~~~~~~~~ {.haskell} -import qualified Data.ByteString as B -~~~~~~~~~~~~~~~ - -Let's rewrite our `echoHandler` as follows. - -~~~~~~~~~~~~~~~ {.haskell} -echoHandler :: Snap () -echoHandler = do - s <- getParam "s" - case s of - Just s' -> if (B.length s' == 4) then badWord else (writeBS s') - _ -> writeBS "" - where - badWord = do - putResponse $ - setResponseStatus 403 "Forbidden" emptyResponse - writeBS "Forbidden: four-letter word" - r <- getResponse - finishWith r -~~~~~~~~~~~~~~~ - -The `badWord` action sets the response status code to be 403 using a -combination of the -[`putResponse`](/docs/latest/snap-core/Snap-Types.html#v%3AputResponse) and -[`setResponseStatus`](/docs/latest/snap-core/Snap-Types.html#v%3AsetResponseStatus) -functions, writes out the body of the response, and calls the function -[`finishWith`](/docs/latest/snap-core/Snap-Types.html#v%3AfinishWith) on that -response. - -The `finishWith` combinator is a function you can call to short-circuit the -monad processing so that no further `Snap` actions will be run; use it when -you're really, really sure about what you want to return and you don't want -your response to be mucked with. - -Let's test this with some childish language to see that it works. - -~~~~~~ {.shell} -$ curl -i localhost:8000/echo/poop -HTTP/1.1 403 Forbidden -Date: Mon, 10 May 2010 07:08:32 GMT -Server: Snap/0.pre-1 -Transfer-Encoding: chunked - -Forbidden: four-letter word -~~~~~~ - - -### Serving It Up - -So we've written our handler, how do we actually serve it and run the server? -Luckily you don't need to write any code as the generated `Main.hs` has the -glue code already. The relevant portion is reproduced below. - -~~~~~~~~~~~~~~~ {.haskell} - httpServe "*" port "myserver" - (Just "access.log") - (Just "error.log") - site -~~~~~~~~~~~~~~~ - -There is no external server to plug into and no complicated directory -structure to manage. Everything is done programmatically. To embed the Snap -server inside your program, all you need to do is to pass -[`httpServe`](/docs/latest/snap-server/Snap-Http-Server.html#v%3AhttpServe) -some configuration parameters and your handler. Note that access and error -logging are optional, should you wish to forego them for performance reasons. - - -## What Now? - -We hope we've whetted your appetite for using Snap. From here on out you should -take a look at the [API documentation](/docs/latest/snap-core/index.html), -which explains many of the concepts and functions here in further detail. - -You can also come hang out in -[`#snapframework`](http://webchat.freenode.net/?channels=snapframework&uio=d4) -on [`freenode`](http://freenode.net/). diff --git a/snaplets/heist/templates/docs/tutorials/snap-api.md b/snaplets/heist/templates/docs/tutorials/snap-api.md index 312a490..c57de3a 100644 --- a/snaplets/heist/templates/docs/tutorials/snap-api.md +++ b/snaplets/heist/templates/docs/tutorials/snap-api.md @@ -1,180 +1,135 @@ -## Installation - -The exposed Snap API is on the same level of abstraction as Java Servlets. If -you understand servlets, most of the rest of the tutorial should be very -self-explanatory. Even if you don't, have no fear! The following tutorial only -expects that you know a little bit of Haskell. +## Examining Hello World Before we dive into writing our first Snap web application, let's do a quick overview of the parts of the Snap framework. Currently Snap is divided into four components: + - `snap-core` is the core of Snap. It defines an API for interfacing with + web servers and includes type definitions and all code that is + server-agnostic. This API is on the same level of abstraction as Java + Servlets and is the focus of this tutorial. - - `snap-core` is the core of Snap. It includes type definitions and all code - that is server-agnostic. - - - `snap-server` is an HTTP server library built on top of `snap-core`. It - currently includes a backend using stock Haskell socket I/O and a backend - which uses the [libev](http://software.schmorp.de/pkg/libev.html) O(1) event - loop library. + - `snap-server` is an HTTP server library that supports the interface + defined in `snap-core`. It currently includes a backend using stock + Haskell socket I/O and a backend which uses the + [libev](http://software.schmorp.de/pkg/libev.html) O(1) event loop + library. - - `heist` is the HTML templating library. You do not need it to use Snap, - but you are certainly welcome to. + - `heist` is the HTML templating library. You do not need it to use the + above two libraries but you are certainly welcome to. - - `snap` is a library which contains the extension framework for organizing - pieces of Snap sites. It also contains a `snap` executable which generates - a skeleton project to get you started. + - `snap` is a library that builds on the above three prackages and provides + higher-level abstractions for building complex websites. It also contains + a `snap` executable which can generate several different skeleton projects + to get you started. -To install Snap, simply use `cabal`. - -~~~~~~ {.shell} -$ cabal install snap -~~~~~~ +In the [Quick Start Guide](/docs/quickstart), we installed Snap and created a +template "hello world" application. Here we'll look at what's inside the +application and describe basic use of Snap's web server API. -It's up to you whether or not you want to use the Heist templating library. -However, heist is a dependency for the snap project starter, and our example -below does use it. +If you understand servlets and Haskell, most of the rest of the tutorial +should be very self-explanatory. Even if you don't, have no fear! The +following tutorial only expects that you know a little bit of Haskell. ## Hello, Snap! -To generate a skeleton Snap web application, the `snap` package installs an -executable `snap` into `$HOME/.cabal/bin`. We can use that to create our "Hello -Snap" application. +`snap init barebones` creates a single file in the `src` directory, Main.hs. +Here's the important code in Main.hs: -(Normally, snap builds an example using Heist and a custom extension to get -your project started. Use `snap init barebones` instead of `snap init` for a -bare-bones skeleton.) - -~~~~~~ {.shell} -$ mkdir hello-snap -$ cd hello-snap -$ snap init +~~~~~~ {.haskell} +main :: IO () +main = quickHttpServe site + +site :: Snap () +site = + ifTop (writeBS "hello world") <|> + route [ ("foo", writeBS "bar") + , ("echo/:echoparam", echoHandler) + ] <|> + dir "static" (serveDirectory ".") + +echoHandler :: Snap () +echoHandler = do + param <- getParam "echoparam" + maybe (writeBS "must specify echo/param in URL") + writeBS param ~~~~~~ -We now have a skeleton Snap project with a `.cabal` file and a source -directory. Install and run it: +The behavior of this code can be summarized with the following rules: -~~~~~~ {.shell} -$ cabal install -$ hello-snap -p 8000 -Initializing Heist/Impl... done. -Initializing Timer/Timer... done. -Listening on http://0.0.0.0:8000/ -~~~~~~ +1. If the user requested the site's root page (http://mysite.com/), then +return a page containing the string "hello world". +2. If the user requested /foo, then return "bar". +3. If the user requested /echo/xyz, then return "xyz". +4. If the request URL begins with /static/, then look for files on disk +matching the rest of the path and serve them. +5. If none of these match, then Snap returns a 404 page. -Then see what your browser thinks of it. +Let's go over each of the Snap API functions used here. -~~~~~~ {.shell} -$ curl 'http://localhost:8000/'; echo - - - Snap web server -... -~~~~~~ +##### [`dir`](http://hackage.haskell.org/packages/archive/snap-core/0.8.0/doc/html/Snap-Core.html#v:dir) -Make sure to try some of the echo examples. When you are satisfied, we can kill -the server by hitting `CTRL-C`. +`dir` runs its action only if the request path starts with the specified +directory. You can combine successive dir calls to match more than one +subdirectory into the path. +##### [`ifTop`](http://hackage.haskell.org/packages/archive/snap-core/0.8.0/doc/html/Snap-Core.html#v:ifTop) -### Under the Hood +`ifTop` only executes its argument if the client requested the root URL. Use +this for your home page. It can also be combined with the `dir` function to +define your index handler for a certain URL directory. -Peeking in the `src` directory, we find the haskell files responsible for the -simple demo page we start with. +##### [`writeBS`](http://hackage.haskell.org/packages/archive/snap-core/0.8.0/doc/html/Snap-Core.html#v:writeBS) -~~~~~ {.shell} -$ cd src -$ ls -Site.hs Main.hs Application.hs -~~~~~ +`writeBS` appends a strict ByteString to the response being constructed. Snap +also provides an analogous function `writeLBS` for lazy ByteStrings. You can +also use the functions `writeText` and `writeLazyText` if you use Data.Text +instead of ByteString. -`Main.hs` contains the `main` entry point to the application. The default -skeleton project contains some C preprocessor statements for optionally -configuring the server to use [hint](http://hackage.haskell.org/package/hint) -to dynamically load the site in "development" mode. If we ignore this for now, -we see that `main` just starts up `snap-server` using our site's initialization -and web handling routines: +If you're not familiar with Haskell, you may be wondering about the `<|>`. It +is simply a binary operator that evaluates its first argument, and if it +failed, evaluates the second. If the first argument succeeded, then it stops +without evaluating the second argument. -~~~~~~ {.haskell} -main :: IO () -main = quickHttpServe applicationInitializer site -~~~~~~ +The `site` function uses `<|>` to connect three different functions that guard +what page gets rendered. First, the `ifTop` function runs. This function +succeeds if the requested URL is `http://site.com/`. If that happens, then +Snap sends a response of "hello world". Otherwise the `route` function is +executed. -The `Application.hs` file defines the `Application` type, which is the type of -our site's web handlers. `Application` extends the default `Snap` handler type -with some application-specific state, also defined in `Application.hs`. +You could build your whole site using `<|>` to connect different handlers +together, but this kind of routing is expensive because the amount of time it +takes to construct a request scales linearly with the number of handlers in +your site. For large sites, this could be quite noticeable. To remedy this, +Snap also provides you with the `route` function that routes requests based on the +request path in `O(log n)` time: -A handler (informally, for now) is a function, run by the Snap server, which -takes an HTTP request and generates the server's Response, with a lot of the -complexity sort of nudged away under the rug. The handlers currently being used -by your sample app are defined in `Site.hs`. +##### [`route`](http://hackage.haskell.org/packages/archive/snap-core/0.8.0/doc/html/Snap-Core.html#v:route) -For example, here's the top-level Handler used by your sample app: +`route` takes a list of (route, handler) tuples and succeeds returning the +result of the associated handler of the route that matches. If no route +matches, then `route` fails and execution is passed on to `serveDirectory`. -~~~~~~ {.haskell} -site :: Application () -site = route [ ("/", index) - , ("/echo/:stuff", echo) - ] - <|> serveDirectory "resources/static" -~~~~~~ +In a real application, you will want to use `route` for almost everything. +We didn't do it that way in this example because we wanted to demonstrate +more of the API. + +##### [`getParam`](http://hackage.haskell.org/packages/archive/snap-core/0.8.0/doc/html/Snap-Core.html#v:getParam) -This sets up a routing table for the site's URLs: requests for the "`/`" URL -get routed to the "`index`" handler, and requests for "`/echo/foo`" get routed -to the "`echo`" handler after we set "`stuff=foo`" in the request's parameter -mapping. - -The second half of the site handler, after the main routing table, handles -serving any files from the disk. The `a <|> b` syntax means: "try `a`, and if -it fails, try `b`". In this case, if the user requests an URL that doesn't -match any of the entries in the routing table --- like "`/screen.css`", for -example --- the `fileServe` function will attempt to find the file under the -"`resources/static`" directory, and will serve it back to the user if it is -found. If the file is *not* found, the "serveDirectory" handler will fail, -causing the `site` handler to fail, which will cause Snap to produce a -"404 Not Found" response. - - -Next, let's take a look at the `echo` handler: - -~~~~~ {.haskell} -echo :: Application () -echo = do - message <- decodedParam "stuff" - heistLocal (bindString "message" message) $ render "echo" - where - decodedParam p = fromMaybe "" <$> getParam p -~~~~~ - -The `echo` handler takes the `stuff` parameter out of the parameters mapping -(remember, "`stuff`" was bound using `route` above), binds its value to a -`heist` tag, and then renders the "echo" template. - -A [lengthier Heist tutorial](/docs/tutorials/heist/) is available, but here's -what you need to know for now: `heist` serves HTML templates, but with a -twist: a tag element can be rebound to a Haskell function which replaces it -with some programmatically-generated markup. In our case, the `echo` template -lives in `resources/templates/echo.tpl`, and the "``" tag has been -redefined to be substituted for the text that was entered by the user. The -template looks like this: - -~~~~~ {.html} - -
-

Is there an echo in here?

-
-

You wanted me to say this?

-

""

-

Return

- -~~~~~ +`getParam` retrieves a GET or POST parameter from the request. In this +example, the `route` function binds a captured portion of the URL to the +parameter `echoParam` so the associated handler can make easy use of it. +`echoHandler` checks to see whether a parameter was passed and returns the +value or an error message if it didn't exist. ## What Now? We hope we've whetted your appetite for using Snap. From here on out you should -take a look at the [API documentation](http://hackage.haskell.org/package/snap-core), +take a look at the [API +documentation](http://hackage.haskell.org/package/snap-core), which explains many of the concepts and functions here in further detail. You can also come hang out in [`#snapframework`](http://webchat.freenode.net/?channels=snapframework&uio=d4) -on [`freenode`](http://freenode.net/). +on [`freenode`](http://freenode.net/) IRC. diff --git a/snaplets/heist/templates/docs/tutorials/snaplets-tutorial.lhs b/snaplets/heist/templates/docs/tutorials/snaplets-tutorial.lhs index 5a45b97..3babcf1 100644 --- a/snaplets/heist/templates/docs/tutorials/snaplets-tutorial.lhs +++ b/snaplets/heist/templates/docs/tutorials/snaplets-tutorial.lhs @@ -287,9 +287,10 @@ snaplet filesystem layout might look like: |-- images/ |-- js/ |-- *snaplets/* + |-- *heist/* + |-- templates/ |-- subsnaplet1/ |-- subsnaplet2/ - |-- templates/ Only the starred items are actually enforced by current code, but we want to establish the others as a convention. The file snaplet.cfg is automatically @@ -310,7 +311,7 @@ directory that should be installed. That argument has the type `Maybe (IO FilePath)`. In this case we used `Nothing` because our simple example doesn't have any filesystem data. As an example, let's say you are creating a snaplet called killerapp that will be distributed as a hackage project called -snaplet-killerapp. Your project directory structure might look something like +snaplet-killerapp. Your project directory structure will look something like this: snaplet-killerapp/ @@ -318,10 +319,8 @@ this: |-- snaplet-killerapp.cabal |-- src/ -In this example, all of the files and directories listed above under -foosnaplet/ are in resources/. This is not required. It just makes it easier -to see all the files that need to be included in the data-files cabal section -described below. Somewhere in the code you will define an initializer for the +All of the files and directories listed above under foosnaplet/ will be in +resources/. Somewhere in the code you will define an initializer for the snaplet that will look like this: killerInit = makeSnaplet "killerapp" "42" (Just dataDir) $ do @@ -333,8 +332,7 @@ what machine you're using, the third argument to `makeSnaplet` has to be `Maybe (IO FilePath)` instead of the more natural pure version. To make things more organized, we use the convention of putting all your snaplet's data files in a subdirectory called resources. So we need to create a small function that -appends `/resources` to the result of `getDataDir`. (This also means that to -test this snaplet, you'll need to run it from the resources directory.) +appends `/resources` to the result of `getDataDir`. import Paths_snaplet_killerapp dataDir = liftM (++"/resources") getDataDir From 3807bd077c4312db362d9b36370eb3ea4a1acccb Mon Sep 17 00:00:00 2001 From: Mighty Byte Date: Sun, 18 Mar 2012 14:27:06 -0400 Subject: [PATCH 3/5] Fix templates directory in snaplets tutorial. --- snaplets/heist/templates/docs/tutorials/snaplets-tutorial.lhs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snaplets/heist/templates/docs/tutorials/snaplets-tutorial.lhs b/snaplets/heist/templates/docs/tutorials/snaplets-tutorial.lhs index 3babcf1..98a86e3 100644 --- a/snaplets/heist/templates/docs/tutorials/snaplets-tutorial.lhs +++ b/snaplets/heist/templates/docs/tutorials/snaplets-tutorial.lhs @@ -345,7 +345,7 @@ including a section like the following in snaplet-killerapp.cabal: data-files: resources/snaplet.cfg, resources/public/stylesheets/style.css, - resources/templates/page.tpl + resources/snaplets/heist/templates/page.tpl Now whenever your snaplet is used, its filesystem data will be automagically copied into the local project that is using it, whenever the application is From 9cb1f082e5561bfe27c3e0052e9b030febcec701 Mon Sep 17 00:00:00 2001 From: Mighty Byte Date: Thu, 5 Apr 2012 11:11:06 -0400 Subject: [PATCH 4/5] Added snaplet-redson to directory. --- snaplets/heist/templates/snaplets.tpl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/snaplets/heist/templates/snaplets.tpl b/snaplets/heist/templates/snaplets.tpl index 770ae49..56077d1 100644 --- a/snaplets/heist/templates/snaplets.tpl +++ b/snaplets/heist/templates/snaplets.tpl @@ -111,6 +111,16 @@
Support for the redis in-memory key-value store.
+
snaplet-redson + + [ hackage + | github ] + +
+
CRUD for JSON data with Redis storage.
+
snaplet-sedna [ Date: Mon, 9 Apr 2012 13:40:34 -0400 Subject: [PATCH 5/5] Added snaplet-recaptcha to the directory. --- snaplets/heist/templates/snaplets.tpl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/snaplets/heist/templates/snaplets.tpl b/snaplets/heist/templates/snaplets.tpl index 56077d1..037cd16 100644 --- a/snaplets/heist/templates/snaplets.tpl +++ b/snaplets/heist/templates/snaplets.tpl @@ -101,6 +101,16 @@
MongoDB support
+
snaplet-recaptcha + + [ hackage + | github ] + +
+
A ReCAPTCHA verification snaplet with connection sharing.
+
snaplet-redis [