Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'master' of github.com:snapframework/snap-website

  • Loading branch information...
commit 53ce5080d2b2053aff854339a06c5c20ecbc9119 2 parents ba1a817 + e6f12b0
@gregorycollins gregorycollins authored
View
3  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
View
12 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
View
286 snaplets/heist/templates/docs/tutorials/snap-api-new.md
@@ -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/).
View
235 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
-<html>
- <head>
- <title>Snap web server</title>
-...
-~~~~~~
+##### [`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 "`<message>`" tag has been
-redefined to be substituted for the text that was entered by the user. The
-template looks like this:
-
-~~~~~ {.html}
-<body>
- <div id="content">
- <h1>Is there an echo in here?</h1>
- </div>
- <p>You wanted me to say this?</p>
- <p>"<message/>"</p>
- <p><a href="/">Return</a></p>
-</body>
-~~~~~
+`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.
View
16 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
@@ -347,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
View
20 snaplets/heist/templates/snaplets.tpl
@@ -101,6 +101,16 @@
</dt>
<dd>MongoDB support</dd>
+ <dt>snaplet-recaptcha
+ <span class="linklist">
+ [ <a href="http://hackage.haskell.org/package/snaplet-recaptcha"
+ > hackage </a>
+ | <a href="https://github.com/lpeterse/snaplet-recaptcha/"
+ >github</a> ]
+ </span>
+ </dt>
+ <dd>A ReCAPTCHA verification snaplet with connection sharing.</dd>
+
<dt>snaplet-redis
<span class="linklist">
[ <a href="http://hackage.haskell.org/package/snaplet-redis"
@@ -111,6 +121,16 @@
</dt>
<dd>Support for the redis in-memory key-value store.</dd>
+ <dt>snaplet-redson
+ <span class="linklist">
+ [ <a href="http://hackage.haskell.org/package/snaplet-redson"
+ > hackage </a>
+ | <a href="https://github.com/dzhus/snaplet-redson/"
+ >github</a> ]
+ </span>
+ </dt>
+ <dd>CRUD for JSON data with Redis storage.</dd>
+
<dt>snaplet-sedna
<span class="linklist">
[ <a href="http://hackage.haskell.org/package/snaplet-sedna"
Please sign in to comment.
Something went wrong with that request. Please try again.