Basic implementation of template groups

This commit is contained in:
Michael Snoyman 2009-12-29 23:07:38 +02:00
parent 3cbcac8c41
commit 911934bff0
12 changed files with 90 additions and 33 deletions

View File

@ -186,7 +186,7 @@ instance ToSElem HtmlObject where
#if TEST #if TEST
caseHtmlToText :: Assertion caseHtmlToText :: Assertion
caseHtmlToText = do caseHtmlToText = do
let actual = Tag "div" [("id", "foo"), ("class", "bar")] let actual = Tag "div" [("id", "foo"), ("class", "bar")] $ HtmlList
[ Html $ cs "<br>Some HTML<br>" [ Html $ cs "<br>Some HTML<br>"
, Text $ cs "<'this should be escaped'>" , Text $ cs "<'this should be escaped'>"
, EmptyTag "img" [("src", "baz&")] , EmptyTag "img" [("src", "baz&")]

4
TODO
View File

@ -1,6 +1,4 @@
Cleanup Data.Object.Translate Some form of i18n.
Cleanup Parameter stuff. Own module? Interface with formlets? Cleanup Parameter stuff. Own module? Interface with formlets?
Authentication via e-mail address built in. (eaut.org) Authentication via e-mail address built in. (eaut.org)
OpenID 2 stuff (for direct Google login). OpenID 2 stuff (for direct Google login).
Native support for HStringTemplate groups.
Use Text for HStringTemplate throughout

View File

@ -21,7 +21,7 @@ module Yesod
, module Yesod.Resource , module Yesod.Resource
, module Data.Object.Html , module Data.Object.Html
, module Yesod.Rep , module Yesod.Rep
, module Yesod.Templates , module Yesod.Template
, module Data.Convertible.Text , module Data.Convertible.Text
, Application , Application
) where ) where
@ -34,6 +34,6 @@ import Yesod.Handler
import Yesod.Resource import Yesod.Resource
import Hack (Application) import Hack (Application)
import Yesod.Rep import Yesod.Rep
import Yesod.Templates import Yesod.Template
import Data.Object.Html import Data.Object.Html
import Data.Convertible.Text import Data.Convertible.Text

View File

@ -38,6 +38,7 @@ module Yesod.Handler
import Yesod.Request import Yesod.Request
import Yesod.Response import Yesod.Response
import Yesod.Rep import Yesod.Rep
import Yesod.Template
import Control.Exception hiding (Handler) import Control.Exception hiding (Handler)
import Control.Applicative import Control.Applicative
@ -49,11 +50,10 @@ import Control.Monad (liftM, ap)
import System.IO import System.IO
import Data.Object.Html import Data.Object.Html
--import Data.Typeable
------ Handler monad ------ Handler monad
newtype Handler yesod a = Handler { newtype Handler yesod a = Handler {
unHandler :: (RawRequest, yesod) -> IO ([Header], HandlerContents a) unHandler :: (RawRequest, yesod, TemplateGroup)
-> IO ([Header], HandlerContents a)
} }
data HandlerContents a = data HandlerContents a =
forall e. Exception e => HCError e forall e. Exception e => HCError e
@ -81,22 +81,26 @@ instance MonadIO (Handler yesod) where
instance Exception e => Failure e (Handler yesod) where instance Exception e => Failure e (Handler yesod) where
failure e = Handler $ \_ -> return ([], HCError e) failure e = Handler $ \_ -> return ([], HCError e)
instance MonadRequestReader (Handler yesod) where instance MonadRequestReader (Handler yesod) where
askRawRequest = Handler $ \(rr, _) -> return ([], HCContent rr) askRawRequest = Handler $ \(rr, _, _) -> return ([], HCContent rr)
invalidParam _pt pn pe = invalidArgs [(pn, pe)] invalidParam _pt pn pe = invalidArgs [(pn, pe)]
authRequired = permissionDenied authRequired = permissionDenied
getYesod :: Handler yesod yesod getYesod :: Handler yesod yesod
getYesod = Handler $ \(_, yesod) -> return ([], HCContent yesod) getYesod = Handler $ \(_, yesod, _) -> return ([], HCContent yesod)
instance HasTemplateGroup (Handler yesod) where
getTemplateGroup = Handler $ \(_, _, tg) -> return ([], HCContent tg)
runHandler :: Handler yesod RepChooser runHandler :: Handler yesod RepChooser
-> (ErrorResult -> Handler yesod RepChooser) -> (ErrorResult -> Handler yesod RepChooser)
-> RawRequest -> RawRequest
-> yesod -> yesod
-> TemplateGroup
-> [ContentType] -> [ContentType]
-> IO Response -> IO Response
runHandler (Handler handler) eh rr y cts = do runHandler (Handler handler) eh rr y tg cts = do
(headers, contents) <- Control.Exception.catch (headers, contents) <- Control.Exception.catch
(handler (rr, y)) (handler (rr, y, tg))
(\e -> return ([], HCError (e :: Control.Exception.SomeException))) (\e -> return ([], HCError (e :: Control.Exception.SomeException)))
let contents' = let contents' =
case contents of case contents of
@ -105,7 +109,7 @@ runHandler (Handler handler) eh rr y cts = do
HCContent a -> Right a HCContent a -> Right a
case contents' of case contents' of
Left e -> do Left e -> do
Response _ hs ct c <- runHandler (eh e) specialEh rr y cts Response _ hs ct c <- runHandler (eh e) specialEh rr y tg cts
let hs' = headers ++ hs ++ getHeaders e let hs' = headers ++ hs ++ getHeaders e
return $ Response (getStatus e) hs' ct c return $ Response (getStatus e) hs' ct c
Right a -> do Right a -> do

View File

@ -47,7 +47,6 @@ module Yesod.Rep
import Data.ByteString.Lazy (ByteString) import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as BL import qualified Data.ByteString.Lazy as BL
import Data.Text.Lazy (Text) import Data.Text.Lazy (Text)
import qualified Data.Text.Lazy as TL
import Data.Maybe (mapMaybe) import Data.Maybe (mapMaybe)
import Data.Function (on) import Data.Function (on)
@ -162,15 +161,24 @@ instance HasReps Plain where
plain :: ConvertSuccess x Text => x -> Plain plain :: ConvertSuccess x Text => x -> Plain
plain = Plain . cs plain = Plain . cs
data Template = Template (StringTemplate Text) HtmlObject data Template = Template (StringTemplate Text)
String
HtmlObject
(IO [(String, HtmlObject)])
instance HasReps Template where instance HasReps Template where
reps = [ (TypeHtml, reps = [ (TypeHtml,
\(Template t h) -> \(Template t name ho attrsIO) -> do
return $ cs $ render $ setAttribute "o" h t) attrs <- attrsIO
, (TypeJson, \(Template _ ho) -> return
$ cs
$ render
$ setAttribute name ho
$ setManyAttrib attrs t)
, (TypeJson, \(Template _ _ ho _) ->
return $ cs $ unJsonDoc $ cs ho) return $ cs $ unJsonDoc $ cs ho)
] ]
-- FIXME
data TemplateFile = TemplateFile FilePath HtmlObject data TemplateFile = TemplateFile FilePath HtmlObject
instance HasReps TemplateFile where instance HasReps TemplateFile where
reps = [ (TypeHtml, reps = [ (TypeHtml,
@ -231,7 +239,7 @@ caseChooseRepTemplate = do
ho = toHtmlObject [ ("foo", toHtmlObject "<fooval>") ho = toHtmlObject [ ("foo", toHtmlObject "<fooval>")
, ("bar", toHtmlObject ["bar1", "bar2"]) , ("bar", toHtmlObject ["bar1", "bar2"])
] ]
hasreps = Template temp ho hasreps = Template temp "o" ho $ return []
res1 = cs "foo:&lt;fooval&gt;, bar:bar1bar2" res1 = cs "foo:&lt;fooval&gt;, bar:bar1bar2"
res2 = cs $ "{\"bar\":[\"bar1\",\"bar2\"]," ++ res2 = cs $ "{\"bar\":[\"bar1\",\"bar2\"]," ++
"\"foo\":\"&lt;fooval&gt;\"}" "\"foo\":\"&lt;fooval&gt;\"}"

View File

@ -43,7 +43,7 @@ import Language.Haskell.TH.Ppr
import System.IO import System.IO
-} -}
import Data.Typeable (Typeable) import Data.Typeable
import Control.Exception (Exception) import Control.Exception (Exception)
import Data.Attempt -- for failure stuff import Data.Attempt -- for failure stuff
import Data.Object.Text import Data.Object.Text
@ -62,7 +62,6 @@ import Test.Framework.Providers.QuickCheck (testProperty)
import Test.HUnit hiding (Test) import Test.HUnit hiding (Test)
import Test.QuickCheck import Test.QuickCheck
import Control.Monad (when) import Control.Monad (when)
import Data.Typeable
#endif #endif
resources :: QuasiQuoter resources :: QuasiQuoter

38
Yesod/Template.hs Normal file
View File

@ -0,0 +1,38 @@
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleContexts #-}
module Yesod.Template
( HasTemplateGroup (..)
, template
, NoSuchTemplate
, TemplateGroup
) where
import Data.Object.Html
import Data.Typeable (Typeable)
import Control.Exception (Exception)
import Control.Failure
import Yesod.Rep
import Data.Object.Text (Text)
import Text.StringTemplate
type TemplateGroup = STGroup Text
class HasTemplateGroup a where
getTemplateGroup :: a TemplateGroup
-- FIXME better home
template :: (MonadFailure NoSuchTemplate t, HasTemplateGroup t)
=> String -- ^ template name
-> String -- ^ object name
-> HtmlObject -- ^ object
-> IO [(String, HtmlObject)] -- ^ template attributes
-> t Template
template tn on o attrs = do
tg <- getTemplateGroup
t <- case getStringTemplate tn tg of
Nothing -> failure $ NoSuchTemplate tn
Just x -> return x
return $ Template t on o attrs
newtype NoSuchTemplate = NoSuchTemplate String
deriving (Show, Typeable)
instance Exception NoSuchTemplate

View File

@ -16,6 +16,7 @@ import Yesod.Utils
import Data.Maybe (fromMaybe) import Data.Maybe (fromMaybe)
import Data.Convertible.Text import Data.Convertible.Text
import Text.StringTemplate
import qualified Hack import qualified Hack
import Hack.Middleware.CleanPath import Hack.Middleware.CleanPath
@ -41,6 +42,10 @@ class Yesod a where
errorHandler :: ErrorResult -> Handler a RepChooser errorHandler :: ErrorResult -> Handler a RepChooser
errorHandler = defaultErrorHandler errorHandler = defaultErrorHandler
-- | The template directory. Blank means no templates.
templateDir :: a -> FilePath
templateDir _ = ""
class Yesod a => YesodApproot a where class Yesod a => YesodApproot a where
-- | An absolute URL to the root of the application. -- | An absolute URL to the root of the application.
approot :: a -> Approot approot :: a -> Approot
@ -80,7 +85,12 @@ toHackApp' y env = do
verb = cs $ Hack.requestMethod env verb = cs $ Hack.requestMethod env
handler = handlers resource verb handler = handlers resource verb
rr = cs env rr = cs env
res <- runHandler handler errorHandler rr y types -- FIXME don't do the templateDir thing for each request
let td = templateDir y
tg <- if null td
then return nullGroup
else directoryGroupRecursiveLazy td
res <- runHandler handler errorHandler rr y tg types
let langs = ["en"] -- FIXME let langs = ["en"] -- FIXME
responseToHackResponse langs res responseToHackResponse langs res

View File

@ -4,7 +4,7 @@
import Yesod import Yesod
import Hack.Handler.SimpleServer import Hack.Handler.SimpleServer
data HelloWorld = HelloWorld TemplateGroup data HelloWorld = HelloWorld
instance Yesod HelloWorld where instance Yesod HelloWorld where
handlers = [$resources| handlers = [$resources|
/: /:
@ -12,9 +12,7 @@ instance Yesod HelloWorld where
/groups: /groups:
Get: helloGroup Get: helloGroup
|] |]
templateDir _ = "examples"
instance YesodTemplates HelloWorld where
templates (HelloWorld g) = g
helloWorld :: Handler HelloWorld TemplateFile helloWorld :: Handler HelloWorld TemplateFile
helloWorld = return $ TemplateFile "examples/template.html" $ cs helloWorld = return $ TemplateFile "examples/template.html" $ cs
@ -22,11 +20,10 @@ helloWorld = return $ TemplateFile "examples/template.html" $ cs
, ("content", "Hey look!! I'm <auto escaped>!") , ("content", "Hey look!! I'm <auto escaped>!")
] ]
helloGroup = template "real-template" $ cs "foo" helloGroup = template "real-template" "foo" (cs "bar") $ return []
main :: IO () main :: IO ()
main = do main = do
putStrLn "Running..." putStrLn "Running..."
stg <- loadTemplates "examples" run 3000 $ toHackApp HelloWorld
run 3000 (toHackApp $ HelloWorld stg)
\end{code} \end{code}

View File

@ -1 +1,2 @@
This is a more realistic template. This is a more realistic template.
foo: $foo$

View File

@ -2,6 +2,7 @@
{-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE QuasiQuotes #-}
import Yesod import Yesod
import Text.StringTemplate (nullGroup)
data MyYesod = MyYesod data MyYesod = MyYesod
@ -54,7 +55,7 @@ ph h = do
rr = error "No raw request" rr = error "No raw request"
y = MyYesod y = MyYesod
cts = [TypeHtml] cts = [TypeHtml]
res <- runHandler h eh rr y cts res <- runHandler h eh rr y nullGroup cts
print res print res
main :: IO () main :: IO ()

View File

@ -51,7 +51,8 @@ library
HStringTemplate >= 0.6.2 && < 0.7, HStringTemplate >= 0.6.2 && < 0.7,
data-object-json >= 0.0.0 && < 0.1, data-object-json >= 0.0.0 && < 0.1,
attempt >= 0.2.1 && < 0.3, attempt >= 0.2.1 && < 0.3,
template-haskell template-haskell,
failure >= 0.0.0 && < 0.1
exposed-modules: Yesod exposed-modules: Yesod
Yesod.Constants Yesod.Constants
Yesod.Rep Yesod.Rep
@ -62,7 +63,7 @@ library
Yesod.Handler Yesod.Handler
Yesod.Resource Yesod.Resource
Yesod.Yesod Yesod.Yesod
Yesod.Templates Yesod.Template
Data.Object.Html Data.Object.Html
Hack.Middleware.MethodOverride Hack.Middleware.MethodOverride
Hack.Middleware.ClientSession Hack.Middleware.ClientSession