scotty-hastache (empty) → 0.1.0
raw patch · 6 files changed
+279/−0 lines, 6 filesdep +basedep +blaze-htmldep +blaze-markupsetup-changed
Dependencies added: base, blaze-html, blaze-markup, containers, filepath, hastache, http-types, mtl, scotty, wai, warp
Files
- LICENSE +30/−0
- Setup.hs +2/−0
- examples/hastachetest.hs +16/−0
- examples/templates/greet.html +14/−0
- scotty-hastache.cabal +49/−0
- src/Web/Scotty/Hastache.hs +168/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2013, Daniil Frumin++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Daniil Frumin nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ examples/hastachetest.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE OverloadedStrings #-}+-- http://orbt.io/QHBm.png+module Main where++import Text.Hastache+import Web.Scotty.Trans as S+import Web.Scotty.Hastache++main :: IO ()+main = scottyH 3000 $ do+ setTemplatesDir "templates"++ get "/:word" $ do+ beam <- param "word"+ setH "action" $ MuVariable (beam :: String)+ hastache "greet.html"
+ examples/templates/greet.html view
@@ -0,0 +1,14 @@+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">+<html> <head>+<title></title>+</head>++<body>+<h1>Scotty, {{action}} me up!</h1>++++<hr>+<address></address>+<!-- hhmts start --><!-- hhmts end -->+</body> </html>
+ scotty-hastache.cabal view
@@ -0,0 +1,49 @@+name: scotty-hastache+version: 0.1.0+homepage: https://github.com/co-dan/scotty-hastache+bug-reports: https://github.com/co-dan/scotty-hastache/issues+synopsis: Easy Mustache templating support for Scotty++description: This library provides a small templating DSL extension+ for Scotty via the `hastache` library. + .+ [Scotty] is a light-weighted Web framework\/router <http://hackage.haskell.org/package/scotty>+ .+ [Hashache] is a Haskell implementation of the Mustache templates: <http://mustache.github.io/>, <http://hackage.haskell.org/package/hastache>+ ++license: BSD3+license-file: LICENSE+author: Dan Frumin+maintainer: difrumin@gmail.com+copyright: (c) 2013 Dan Frumin <difrumin@gmail.com>+category: Web+stability: experimental+build-type: Simple+cabal-version: >=1.10++extra-source-files: examples/hastachetest.hs+ examples/templates/greet.html++library+ exposed-modules: Web.Scotty.Hastache+ build-depends: base >= 4.4 && < 5,+ blaze-html >= 0.6.0.0,+ blaze-markup >= 0.5.1.0,+ containers >= 0.5.0.0,+ filepath >= 1.3.0.0,+ hastache >= 0.5.0,+ http-types >= 0.7.3.0.1,+ mtl >= 2.1.2,+ scotty >= 0.5.0,+ wai >= 1.3.0.1,+ warp >= 1.3.4.1+++ hs-source-dirs: src+ GHC-options: -Wall -fno-warn-orphans+ default-language: Haskell2010++source-repository head+ type: git+ location: git://github.com/co-dan/scotty-hastache.git
+ src/Web/Scotty/Hastache.hs view
@@ -0,0 +1,168 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE ImpredicativeTypes #-}+{-# LANGUAGE InstanceSigs #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeSynonymInstances #-}++{- | Hastache templating for Scotty++@+\{\-\# LANGUAGE OverloadedStrings \#\-\}+module Main where++import Text.Hastache+import Web.Scotty.Trans as S+import Web.Scotty.Hastache++main :: IO ()+main = scottyH 3000 $ do+ setTemplatesDir \"templates\"+ -- ^ Setting up the director with templates+ get \"/:word\" $ do+ beam <- param \"word\"+ setH \"action\" $ MuVariable (beam :: String)+ -- ^ \"action\" will be binded to the contents of \'beam\'+ hastache \"greet.html\"+@++Given the following template:++@+\<h1\>Scotty, {{action}} me up!\<\/h1\>+@++Upon the @GET \/beam@ the result will be:++@+\<h1\>Scotty, beam me up!\<\/h1\>+@++-}+module Web.Scotty.Hastache where++import Control.Arrow ((***))+import Control.Monad.State as State+import Data.IORef (newIORef, readIORef,+ writeIORef)+import qualified Data.Map as M+import Data.Maybe (fromMaybe)+import Data.Monoid (mempty)+import Network.Wai (Application, Response)+import Network.Wai.Handler.Warp (Port)+import System.FilePath.Posix ((</>))+import Text.Blaze.Html.Renderer.String as BRS+import Text.Blaze.Html.Renderer.Utf8 as BRU+import Text.Blaze.Internal (Markup)+import Text.Hastache+import Text.Hastache.Context+import Web.Scotty.Trans as S++-- * Runners and types++-- | The runner to use instead of 'scotty'+scottyH :: Port -> ScottyH () -> IO ()+scottyH p s = do+ (runH, runActionToIO) <- mkHStateRunners defaultConfig+ scottyT p runH runActionToIO s++-- | The runner to use instead of 'scottyOpts'+scottyHOpts :: Options -> ScottyH () -> IO ()+scottyHOpts opts s = do+ (runH, runActionToIO) <- mkHStateRunners defaultConfig+ scottyOptsT opts runH runActionToIO s++-- | A type synonym for @ScottyT HState@+type ScottyH = ScottyT HState++-- | A type synonym for @ScottyT HState@+type ActionH = ActionT HState++-- * The DSL itself++-- ** Configuration++-- | Update the Hastache configuration as whole+setHastacheConfig :: MuConfig IO -> ScottyH ()+setHastacheConfig conf = do+ (_, tmap) <- lift State.get+ lift . State.put $ (conf, tmap)++-- | Modify the Hastache configuration as whole+modifyHastacheConfig :: (MuConfig IO -> MuConfig IO) -> ScottyH ()+modifyHastacheConfig f = lift $ State.modify (f *** id)++-- | Set the path to the directory with templates. This affects+-- how /both/ 'hastache' and the @{{> template}}@ bit searches for the+-- template files.+setTemplatesDir :: FilePath -> ScottyH ()+setTemplatesDir dir = do+ lift $ State.modify $ \(conf :: MuConfig IO, tmap) ->+ (conf { muTemplateFileDir = Just dir }, tmap)++-- | Set the default extension for template files. This affects+-- how /both/ 'hastache' and the @{{> template}}@ bit searches for the+-- template files.+setTemplateFileExt :: String -> ScottyH ()+setTemplateFileExt ext = do+ lift $ State.modify $ \(conf :: MuConfig IO, tmap) ->+ (conf { muTemplateFileExt = Just ext }, tmap)++-- ** Actions++-- | This is a function, just like 'S.html' or 'S.text'.+-- It takes a name of the template (the path is computed using the +-- information about the templates dir and template files extension) +-- and renders it using Hastache.+--+-- The variables that have been initialized using 'setH' are +-- substituted for their values, uninitialized variables are +-- considered to be empty/null.+hastache :: FilePath -> ActionT HState ()+hastache tpl = do+ ((conf :: MuConfig IO), tmap) <- lift State.get+ setHeader "Content-Type" "text/html"+ let cntx a = fromMaybe MuNothing (M.lookup a tmap)+ let tplFile = fromMaybe "." (muTemplateFileDir conf)+ </> tpl+ ++ fromMaybe "" (muTemplateFileExt conf)+ res <- liftIO $ hastacheFile conf tplFile (mkStrContext cntx)+ raw res++-- | Set the value of a mustache variable.+setH :: String -> MuType IO -> ActionT HState ()+setH x y = do+ (conf, tmap) <- lift State.get+ lift . State.put $ (conf, M.insert x y tmap)++-- * Internals++-- | State with the Hastache config+type HState = StateT (MuConfig IO, M.Map String (MuType IO)) IO++mkHStateRunners :: MuConfig IO -> IO (forall a. HState a -> IO a, HState Response -> IO Response)+mkHStateRunners conf = do+ gstate <- newIORef undefined+ let runH m = do+ (r,(muconf,_)) <- runStateT m (conf, mempty)+ writeIORef gstate muconf+ return r+ runActionToIO m = do+ muconf <- readIORef gstate+ evalStateT m (muconf, mempty)+ return (runH, runActionToIO)++scottyHApp :: MuConfig IO -> ScottyH () -> IO Application+scottyHApp conf defs = do+ (runH, runActionToIO) <- mkHStateRunners conf+ scottyAppT runH runActionToIO defs++instance Show Markup where+ show = BRS.renderHtml++instance MuVar Markup where+ isEmpty = isEmpty . BRU.renderHtml+ toLByteString = BRU.renderHtml++