Lots of cases

This commit is contained in:
Michael Snoyman 2011-01-28 09:37:14 +02:00
parent 7f51c7fd20
commit 21bdab3602
3 changed files with 228 additions and 95 deletions

View File

@ -9,8 +9,9 @@
module Yesod.Core module Yesod.Core
( -- * Type classes ( -- * Type classes
Yesod (..) Yesod (..)
, YesodSite (..) , YesodDispatch (..)
, YesodSubSite (..) , YesodSubSite (..)
, RenderRoute (..)
-- ** Breadcrumbs -- ** Breadcrumbs
, YesodBreadcrumbs (..) , YesodBreadcrumbs (..)
, breadcrumbs , breadcrumbs
@ -45,7 +46,6 @@ import qualified Web.ClientSession as CS
import qualified Data.ByteString as S import qualified Data.ByteString as S
import qualified Data.ByteString.Char8 as S8 import qualified Data.ByteString.Char8 as S8
import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString.Lazy.Char8 as L8
import Data.Monoid import Data.Monoid
import Control.Monad.Trans.Writer import Control.Monad.Trans.Writer
import Control.Monad.Trans.State hiding (get, put) import Control.Monad.Trans.State hiding (get, put)
@ -77,25 +77,19 @@ import qualified Data.Text.Encoding
#define HAMLET $hamlet #define HAMLET $hamlet
#endif #endif
-- FIXME ditch the whole Site thing and just have render and dispatch? class Eq u => RenderRoute u where
renderRoute :: u -> ([String], [(String, String)])
-- FIXME unify YesodSite and YesodSubSite
-- | This class is automatically instantiated when you use the template haskell -- | This class is automatically instantiated when you use the template haskell
-- mkYesod function. You should never need to deal with it directly. -- mkYesod function. You should never need to deal with it directly.
class Eq (Route y) => YesodSite y where class RenderRoute (Route y) => YesodDispatch y where
getSite :: Site (Route y) (Method -> Maybe (GHandler y y ChooseRep)) yesodDispatch :: y -> Maybe CS.Key -> [String] -> Maybe W.Application
getSite' :: y -> Site (Route y) (Method -> Maybe (GHandler y y ChooseRep))
getSite' _ = getSite
dispatchToSubsite :: y -> Maybe CS.Key -> [String] -> Maybe W.Application
type Method = String
-- | Same as 'YesodSite', but for subsites. Once again, users should not need -- | Same as 'YesodSite', but for subsites. Once again, users should not need
-- to deal with it directly, as mkYesodSub creates instances appropriately. -- to deal with it directly, as mkYesodSub creates instances appropriately.
class Eq (Route s) => YesodSubSite s y where class (RenderRoute (Route s)) => YesodSubSite s y where
getSubSite :: Site (Route s) (Method -> Maybe (GHandler s y ChooseRep)) dispatchSubsite :: (Yesod y)
getSubSite' :: s -> y -> Site (Route s) (Method -> Maybe (GHandler s y ChooseRep))
getSubSite' _ _ = getSubSite
dispatchSubsite :: (Yesod y, YesodSite y)
=> y => y
-> Maybe CS.Key -> Maybe CS.Key
-> [String] -> [String]
@ -103,17 +97,18 @@ class Eq (Route s) => YesodSubSite s y where
-> s -> s
-> W.Application -> W.Application
dispatchToSubSubsite dispatchToSubSubsite
:: (Yesod y, YesodSite y) :: (Yesod y)
=> y => y
-> Maybe CS.Key -> Maybe CS.Key
-> [String] -> [String]
-> (Route s -> Route y) -> (Route s -> Route y)
-> s -> s
-> Maybe W.Application -> Maybe W.Application
dispatchSubLocal :: y -> Maybe CS.Key -> [String] -> (Route s -> Route y) -> s -> Maybe W.Application
-- | Define settings for a Yesod applications. The only required setting is -- | Define settings for a Yesod applications. The only required setting is
-- 'approot'; other than that, there are intelligent defaults. -- 'approot'; other than that, there are intelligent defaults.
class Eq (Route a) => Yesod a where class RenderRoute (Route a) => Yesod a where
-- | An absolute URL to the root of the application. Do not include -- | An absolute URL to the root of the application. Do not include
-- trailing slash. -- trailing slash.
-- --
@ -251,10 +246,10 @@ class Eq (Route a) => Yesod a where
sessionIpAddress :: a -> Bool sessionIpAddress :: a -> Bool
sessionIpAddress _ = True sessionIpAddress _ = True
yesodRunner :: YesodSite a => a -> Maybe CS.Key -> Maybe (Route a) -> GHandler a a ChooseRep -> W.Application yesodRunner :: a -> Maybe CS.Key -> Maybe (Route a) -> GHandler a a ChooseRep -> W.Application
yesodRunner = defaultYesodRunner yesodRunner = defaultYesodRunner
defaultYesodRunner :: (Yesod a, YesodSite a) defaultYesodRunner :: Yesod a
=> a => a
-> Maybe CS.Key -> Maybe CS.Key
-> Maybe (Route a) -> Maybe (Route a)
@ -501,7 +496,7 @@ $maybe j <- jscript
yesodVersion :: String yesodVersion :: String
yesodVersion = showVersion Paths_yesod_core.version yesodVersion = showVersion Paths_yesod_core.version
yesodRender :: (Yesod y, YesodSite y) yesodRender :: Yesod y
=> y => y
-> Route y -> Route y
-> [(String, String)] -> [(String, String)]
@ -511,7 +506,7 @@ yesodRender y u qs =
(joinPath y (approot y) ps $ qs ++ qs') (joinPath y (approot y) ps $ qs ++ qs')
(urlRenderOverride y u) (urlRenderOverride y u)
where where
(ps, qs') = formatPathSegments (getSite' y) u (ps, qs') = renderRoute u
#if TEST #if TEST
coreTestSuite :: Test coreTestSuite :: Test

View File

@ -56,7 +56,7 @@ import Control.Monad
import Data.Maybe import Data.Maybe
import Web.ClientSession import Web.ClientSession
import qualified Web.ClientSession as CS import qualified Web.ClientSession as CS
import Data.Char (isUpper) import Data.Char (isUpper, toLower)
import Web.Cookie (parseCookies, SetCookie (..), renderSetCookie) import Web.Cookie (parseCookies, SetCookie (..), renderSetCookie)
import Data.Serialize import Data.Serialize
@ -64,7 +64,7 @@ import qualified Data.Serialize as Ser
import Network.Wai.Parse hiding (FileInfo) import Network.Wai.Parse hiding (FileInfo)
import qualified Network.Wai.Parse as NWP import qualified Network.Wai.Parse as NWP
import Data.String (fromString) import Data.String (fromString)
import Web.Routes import Web.Routes (decodePathInfo)
import Control.Arrow (first) import Control.Arrow (first)
import System.Random (randomR, newStdGen) import System.Random (randomR, newStdGen)
@ -73,6 +73,7 @@ import qualified Data.Map as Map
import Control.Applicative ((<$>), (<*>)) import Control.Applicative ((<$>), (<*>))
import Data.Enumerator (($$), run_, Iteratee) import Data.Enumerator (($$), run_, Iteratee)
import Control.Monad.IO.Class (liftIO) import Control.Monad.IO.Class (liftIO)
import Data.List (foldl')
#if TEST #if TEST
import Test.Framework (testGroup, Test) import Test.Framework (testGroup, Test)
@ -134,8 +135,8 @@ mkYesodSubDispatch :: String -> Cxt -> [Resource] -> Q [Dec]
mkYesodSubDispatch name clazzes = fmap snd . mkYesodGeneral name' rest clazzes True mkYesodSubDispatch name clazzes = fmap snd . mkYesodGeneral name' rest clazzes True
where (name':rest) = words name where (name':rest) = words name
mkYesodGeneral :: String -- ^ argument name mkYesodGeneral :: String -- ^ foundation name
-> [String] -- ^ parameters for site argument -> [String] -- ^ parameters for foundation
-> Cxt -- ^ classes -> Cxt -- ^ classes
-> Bool -- ^ is subsite? -> Bool -- ^ is subsite?
-> [Resource] -> [Resource]
@ -144,20 +145,19 @@ mkYesodGeneral name args clazzes isSub res = do
let name' = mkName name let name' = mkName name
args' = map mkName args args' = map mkName args
arg = foldl AppT (ConT name') $ map VarT args' arg = foldl AppT (ConT name') $ map VarT args'
th' <- mapM (thResourceFromResource arg) res -- FIXME now we cannot have multi-nested subsites th' <- mapM (thResourceFromResource arg) res
let th = map fst th' let th = map fst th'
w' <- createRoutes th w' <- createRoutes th
let routesName = mkName $ name ++ "Route" let routesName = mkName $ name ++ "Route"
let w = DataD [] routesName [] w' [''Show, ''Read, ''Eq] let w = DataD [] routesName [] w' [''Show, ''Read, ''Eq]
let x = TySynInstD ''Route [arg] $ ConT routesName let x = TySynInstD ''Route [arg] $ ConT routesName
parse' <- createParse th
parse'' <- newName "parse"
let parse = LetE [FunD parse'' parse'] $ VarE parse''
render' <- createRender th render' <- createRender th
render'' <- newName "render" render'' <- newName "render"
let render = LetE [FunD render'' render'] $ VarE render'' let render = LetE [FunD render'' render'] $ VarE render''
let x' = InstanceD [] (ConT ''RenderRoute `AppT` ConT routesName)
[ FunD (mkName "renderRoute") render'
]
tmh <- [|toMasterHandlerDyn|] tmh <- [|toMasterHandlerDyn|]
modMaster <- [|fmap chooseRep|] modMaster <- [|fmap chooseRep|]
@ -165,13 +165,16 @@ mkYesodGeneral name args clazzes isSub res = do
dispatch'' <- newName "dispatch" dispatch'' <- newName "dispatch"
let dispatch = LetE [FunD dispatch'' dispatch'] $ LamE [WildP] $ VarE dispatch'' let dispatch = LetE [FunD dispatch'' dispatch'] $ LamE [WildP] $ VarE dispatch''
site <- [|Site|] {- FIXME
let site' = site `AppE` dispatch `AppE` render `AppE` parse
let (ctx, ytyp, yfunc) = let (ctx, ytyp, yfunc) =
if isSub if isSub
then (clazzes, ConT ''YesodSubSite `AppT` arg `AppT` VarT (mkName "master"), "getSubSite") then (clazzes, ConT ''YesodSubSite `AppT` arg `AppT` VarT (mkName "master"), "getSubSite")
else ([], ConT ''YesodSite `AppT` arg, "getSite") else ([], ConT ''YesodSite `AppT` arg, "getSite")
subsiteClauses <- catMaybes <$> mapM sc th' -}
let sortedRes = filter (not . isSubSite) th' ++ filter isSubSite th'
yd <- mkYesodDispatch' sortedRes
localClauses <- catMaybes <$> mapM mkDispatchLocal th'
subsiteClauses <- catMaybes <$> mapM mkDispatchToSubsite th'
let subSubsiteClauses = [] -- FIXME subSubsiteClauses let subSubsiteClauses = [] -- FIXME subSubsiteClauses
nothing <- [|Nothing|] nothing <- [|Nothing|]
dds <- [|defaultDispatchSubsite|] dds <- [|defaultDispatchSubsite|]
@ -184,37 +187,186 @@ mkYesodGeneral name args clazzes isSub res = do
else [ FunD (mkName "dispatchToSubsite") else [ FunD (mkName "dispatchToSubsite")
(subsiteClauses ++ [Clause [WildP, WildP, WildP] (NormalB nothing) []]) (subsiteClauses ++ [Clause [WildP, WildP, WildP] (NormalB nothing) []])
] ]
let y = InstanceD ctx ytyp let mkYSS = InstanceD clazzes (ConT ''YesodSubSite `AppT` arg `AppT` VarT (mkName "master"))
[
]
mkYS = InstanceD [] (ConT ''YesodDispatch `AppT` arg) [FunD (mkName "yesodDispatch") [yd]]
let y = if isSub then mkYSS else mkYS {-InstanceD ctx ytyp
$ FunD (mkName yfunc) [Clause [] (NormalB site') []] $ FunD (mkName yfunc) [Clause [] (NormalB site') []]
: otherMethods : otherMethods -}
return ([w, x], [y]) return ([w, x, x'], [y])
isSubSite ((_, SubSite{}), _) = True
isSubSite _ = False
mkYesodDispatch' sortedRes = do
master <- newName "master"
mkey <- newName "mkey"
segments <- newName "segments"
nothing <- [|Nothing|]
body <- foldM (go master mkey segments) nothing sortedRes
return $ Clause
[VarP master, VarP mkey, VarP segments]
(NormalB body)
[]
where where
sc ((constr, SubSite { ssPieces = pieces }), Just toSub) = do go master mkey segments onFail ((constr, SubSite { ssPieces = pieces }), Just toSub) = return onFail
master <- newName "master" go master mkey segments onFail ((constr, Simple pieces methods), Nothing) = do
mkey <- newName "mkey" test <- mkSimpleExp segments pieces id (master, mkey, constr, methods)
just <- [|Just|] just <- [|Just|]
(pat', tma', rest, toMaster) app <- newName "app"
<- mkPat' pieces return $ CaseE test
(ConE $ mkName constr) [ Match (ConP (mkName "Nothing") []) (NormalB onFail) []
$ just `AppE` (VarE (mkName toSub) `AppE` VarE master) , Match (ConP (mkName "Just") [VarP app]) (NormalB $ just `AppE` VarE app) []
ds <- [|dispatchSubsite|] ]
goodParse <- (`AppE` tma') <$> [|isJust|]
tma'' <- (`AppE` tma') <$> [|fromJust|] mkSimpleExp segments [] frontVars (master, mkey, constr, methods) = do
let body' = ds `AppE` VarE master `AppE` VarE mkey `AppE` rest `AppE` toMaster just <- [|Just|]
fmap' <- [|(<$>)|] nothing <- [|Nothing|]
let body = InfixE (Just body') fmap' $ Just tma' onSuccess <- newName "onSuccess"
return $ Just $ Clause req <- newName "req"
[ VarP master badMethod' <- [|badMethod|]
, VarP mkey rm <- [|W.requestMethod|]
, pat' let caseExp = rm `AppE` VarE req
] (GuardedB [(NormalG goodParse, body)]) [] yr <- [|yesodRunner|]
sc _ = return Nothing cr <- [|fmap chooseRep|]
let url = foldl' AppE (ConE $ mkName constr) $ frontVars []
let runHandlerVars h = runHandler $ foldl' AppE (cr `AppE` (VarE $ mkName h)) $ frontVars []
runHandler h = NormalB $ yr `AppE` VarE master `AppE` VarE mkey `AppE` (just `AppE` url) `AppE` h `AppE` VarE req
let match m = Match (LitP $ StringL m) (runHandlerVars $ map toLower m ++ constr) []
let clauses =
case methods of
[] -> [Clause [] (runHandlerVars $ "handle" ++ constr) []]
_ -> [Clause [VarP req] (NormalB $ CaseE caseExp $ map match methods ++
[Match WildP (runHandler badMethod') []]) []]
let exp = CaseE (VarE segments)
[ Match
(ConP (mkName "[]") [])
(NormalB $ just `AppE` VarE onSuccess)
[FunD onSuccess clauses]
, Match
WildP
(NormalB nothing)
[]
]
return exp
mkSimpleExp segments (StaticPiece s:pieces) frontVars x = do
srest <- newName "segments"
innerExp <- mkSimpleExp srest pieces frontVars x
nothing <- [|Nothing|]
let exp = CaseE (VarE segments)
[ Match
(InfixP (LitP $ StringL s) (mkName ":") (VarP srest))
(NormalB innerExp)
[]
, Match WildP (NormalB nothing) []
]
return exp
mkSimpleExp segments (SinglePiece s:pieces) frontVars x = do
srest <- newName "segments"
next' <- newName "next'"
innerExp <- mkSimpleExp srest pieces (frontVars . (:) (VarE next')) x
nothing <- [|Nothing|]
next <- newName "next"
fsp <- [|fromSinglePiece|]
let exp' = CaseE (fsp `AppE` VarE next)
[ Match
(ConP (mkName "Left") [WildP])
(NormalB nothing)
[]
, Match
(ConP (mkName "Right") [VarP next'])
(NormalB innerExp)
[]
]
let exp = CaseE (VarE segments)
[ Match
(InfixP (VarP next) (mkName ":") (VarP srest))
(NormalB exp')
[]
, Match WildP (NormalB nothing) []
]
return exp
{-
mkPat' (SinglePiece s:rest) url = do
fsp <- [|either (const Nothing) Just . fromSinglePiece|]
v <- newName $ "var" ++ s
be <- [|(<*>)|]
let url' = InfixE (Just url) be $ Just $ fsp `AppE` VarE v
(x, rest, url'') <- mkPat' rest url'
return (InfixP (VarP v) (mkName ":") x, rest, url'')
mkPat' [] url = do
rest <- newName "rest"
return (VarP rest, VarE rest, url)
-}
mkDispatchLocal ((constr, Simple pieces methods), Nothing) = do
master <- newName "master"
mkey <- newName "mkey"
req <- newName "req"
just <- [|Just|]
(pat', rest, url) <- mkPat' pieces $ just `AppE` (ConE $ mkName constr)
goodParse <- (`AppE` url) <$> [|isJust|]
tma'' <- (`AppE` url) <$> [|fromJust|]
nothing <- [|Nothing|]
let body = if null methods
then VarE $ mkName $ "handle" ++ constr
else CaseE (VarE req) $ map mkMatch methods ++ [Match WildP (NormalB nothing) []]
return $ Just $ Clause
[ VarP master
, VarP mkey
, pat'
] (GuardedB [(NormalG goodParse, body)]) [] -- FIXME
where
singleToMApp :: GHandler s m c -> Maybe W.Application
singleToMApp = undefined
multiToMApp = undefined
-- FIXME requires OverloadedStrings
mkMatch method = Match (LitP $ StringL method) (NormalB $ VarE $ mkName $ map toLower method ++ constr) []
mkPat' :: [Piece] -> Exp -> Q (Pat, Exp, Exp)
mkPat' (StaticPiece s:rest) url = do
(x, rest', url') <- mkPat' rest url
let sp = LitP $ StringL s
return (InfixP sp (mkName ":") x, rest', url')
mkPat' (SinglePiece s:rest) url = do
fsp <- [|either (const Nothing) Just . fromSinglePiece|]
v <- newName $ "var" ++ s
be <- [|(<*>)|]
let url' = InfixE (Just url) be $ Just $ fsp `AppE` VarE v
(x, rest, url'') <- mkPat' rest url'
return (InfixP (VarP v) (mkName ":") x, rest, url'')
mkPat' [] url = do
rest <- newName "rest"
return (VarP rest, VarE rest, url)
mkDispatchLocal _ = return Nothing
mkDispatchToSubsite ((constr, SubSite { ssPieces = pieces }), Just toSub) = do
master <- newName "master"
mkey <- newName "mkey"
just <- [|Just|]
(pat', tma', rest, toMaster)
<- mkPat' pieces
(ConE $ mkName constr)
$ just `AppE` (VarE (mkName toSub) `AppE` VarE master)
ds <- [|dispatchSubsite|]
goodParse <- (`AppE` tma') <$> [|isJust|]
tma'' <- (`AppE` tma') <$> [|fromJust|]
let body' = ds `AppE` VarE master `AppE` VarE mkey `AppE` rest `AppE` toMaster
fmap' <- [|(<$>)|]
let body = InfixE (Just body') fmap' $ Just tma'
return $ Just $ Clause
[ VarP master
, VarP mkey
, pat'
] (GuardedB [(NormalG goodParse, body)]) []
where
mkPat' :: [Piece] -> Exp -> Exp -> Q (Pat, Exp, Exp, Exp) mkPat' :: [Piece] -> Exp -> Exp -> Q (Pat, Exp, Exp, Exp)
mkPat' (MultiPiece _:_) _ _ = error "MultiPiece not allowed as part of a subsite" mkPat' (MultiPiece _:_) _ _ = error "MultiPiece not allowed as part of a subsite"
mkPat' (StaticPiece s:rest) toMaster tma = do mkPat' (StaticPiece s:rest) toMaster tma = do
(x, tma, rest', toMaster') <- mkPat' rest toMaster tma (x, tma', rest', toMaster') <- mkPat' rest toMaster tma
let sp = LitP $ StringL s let sp = LitP $ StringL s
return (InfixP sp (mkName ":") x, tma, rest', toMaster') return (InfixP sp (mkName ":") x, tma', rest', toMaster')
mkPat' (SinglePiece s:rest) toMaster tma = do mkPat' (SinglePiece s:rest) toMaster tma = do
fsp <- [|either (const Nothing) Just . fromSinglePiece|] fsp <- [|either (const Nothing) Just . fromSinglePiece|]
v <- newName $ "var" ++ s v <- newName $ "var" ++ s
@ -226,6 +378,7 @@ mkYesodGeneral name args clazzes isSub res = do
mkPat' [] toMaster parse = do mkPat' [] toMaster parse = do
rest <- newName "rest" rest <- newName "rest"
return (VarP rest, parse, VarE rest, toMaster) return (VarP rest, parse, VarE rest, toMaster)
mkDispatchToSubsite _ = return Nothing
isStatic :: Piece -> Bool isStatic :: Piece -> Bool
isStatic StaticPiece{} = True isStatic StaticPiece{} = True
@ -238,7 +391,8 @@ thResourceFromResource master (Resource n ps [stype, toSubArg])
-- static route to subsite -- static route to subsite
= do = do
let stype' = ConT $ mkName stype let stype' = ConT $ mkName stype
gss <- [|getSubSite|] {-
gss <- [|error "FIXME getSubSite"|]
let inside = ConT ''Maybe `AppT` let inside = ConT ''Maybe `AppT`
(ConT ''GHandler `AppT` stype' `AppT` master `AppT` (ConT ''GHandler `AppT` stype' `AppT` master `AppT`
ConT ''ChooseRep) ConT ''ChooseRep)
@ -252,6 +406,10 @@ thResourceFromResource master (Resource n ps [stype, toSubArg])
let render = render' `AppE` gss' let render = render' `AppE` gss'
dispatch' <- [|flip handleSite (error "Cannot use subsite render function")|] dispatch' <- [|flip handleSite (error "Cannot use subsite render function")|]
let dispatch = dispatch' `AppE` gss' let dispatch = dispatch' `AppE` gss'
-}
parse <- [|error "ssParse"|]
dispatch <- [|error "ssDispatch"|]
render <- [|renderRoute|]
tmg <- mkToMasterArg ps toSubArg tmg <- mkToMasterArg ps toSubArg
return ((n, SubSite return ((n, SubSite
{ ssType = ConT ''Route `AppT` stype' { ssType = ConT ''Route `AppT` stype'
@ -282,7 +440,7 @@ mkToMasterArg ps fname = do
-- handler. This is the same as 'toWaiAppPlain', except it includes three -- handler. This is the same as 'toWaiAppPlain', except it includes three
-- middlewares: GZIP compression, JSON-P and path cleaning. This is the -- middlewares: GZIP compression, JSON-P and path cleaning. This is the
-- recommended approach for most users. -- recommended approach for most users.
toWaiApp :: (Yesod y, YesodSite y) => y -> IO W.Application toWaiApp :: (Yesod y, YesodDispatch y) => y -> IO W.Application
toWaiApp y = do toWaiApp y = do
a <- toWaiAppPlain y a <- toWaiAppPlain y
return $ gzip False return $ gzip False
@ -291,12 +449,12 @@ toWaiApp y = do
-- | Convert the given argument into a WAI application, executable with any WAI -- | Convert the given argument into a WAI application, executable with any WAI
-- handler. This differs from 'toWaiApp' in that it uses no middlewares. -- handler. This differs from 'toWaiApp' in that it uses no middlewares.
toWaiAppPlain :: (Yesod y, YesodSite y) => y -> IO W.Application toWaiAppPlain :: (Yesod y, YesodDispatch y) => y -> IO W.Application
toWaiAppPlain a = do toWaiAppPlain a = do
key' <- encryptKey a key' <- encryptKey a
return $ toWaiApp' a key' return $ toWaiApp' a key'
toWaiApp' :: (Yesod y, YesodSite y) toWaiApp' :: (Yesod y, YesodDispatch y)
=> y => y
-> Maybe Key -> Maybe Key
-> W.Application -> W.Application
@ -306,10 +464,14 @@ toWaiApp' y key' env = do
"":x -> x "":x -> x
x -> x x -> x
liftIO $ print (W.pathInfo env, segments) liftIO $ print (W.pathInfo env, segments)
case dispatchToSubsite y key' segments of case yesodDispatch y key' segments of
Just app -> app env
Nothing -> Nothing ->
case cleanPath y segments of case cleanPath y segments of
Nothing -> normalDispatch y key' segments env Nothing ->
case yesodDispatch y key' segments of
Just app -> app env
Nothing -> yesodRunner y key' Nothing notFound env
Just segments' -> Just segments' ->
let dest = joinPath y (approot y) segments' [] let dest = joinPath y (approot y) segments' []
dest' = dest' =
@ -324,26 +486,9 @@ toWaiApp' y key' env = do
[ ("Content-Type", "text/plain") [ ("Content-Type", "text/plain")
, ("Location", dest') , ("Location", dest')
] "Redirecting" ] "Redirecting"
Just app -> app env
normalDispatch :: (Yesod m, YesodSite m)
=> m -> Maybe Key -> [String]
-> W.Application
normalDispatch y key' segments env =
yesodRunner y key' murl handler env
where
method = B.unpack $ W.requestMethod env
murl = either (const Nothing) Just $ parsePathSegments (getSite' y) segments
handler =
case murl of
Nothing -> notFound
Just url ->
case handleSite (getSite' y) (yesodRender y) url method of
Nothing -> badMethod
Just h -> h
defaultDispatchSubsite defaultDispatchSubsite
:: (Yesod m, YesodSite m, YesodSubSite s m) :: (Yesod m, YesodDispatch m, YesodSubSite s m)
=> m -> Maybe Key -> [String] => m -> Maybe Key -> [String]
-> (Route s -> Route m) -> (Route s -> Route m)
-> s -> s
@ -351,18 +496,10 @@ defaultDispatchSubsite
defaultDispatchSubsite y key' segments toMasterRoute s env = defaultDispatchSubsite y key' segments toMasterRoute s env =
case dispatchToSubSubsite y key' segments toMasterRoute s of case dispatchToSubSubsite y key' segments toMasterRoute s of
Just app -> app env Just app -> app env
Nothing -> yesodRunner y key' (fmap toMasterRoute murl) handler env Nothing ->
where case dispatchSubLocal y key' segments toMasterRoute s of
method = B.unpack $ W.requestMethod env Just app -> app env
murl = either (const Nothing) Just $ parsePathSegments (getSubSite' s y) segments Nothing -> yesodRunner y key' Nothing notFound env
handler = toMasterHandlerMaybe toMasterRoute (const s) murl handler'
handler' =
case murl of
Nothing -> notFound
Just url ->
case handleSite (getSubSite' s y) (yesodRender y . toMasterRoute) url method of
Nothing -> badMethod
Just h -> h
#if TEST #if TEST

View File

@ -5,7 +5,7 @@ import Yesod.Core
import Yesod.Dispatch import Yesod.Dispatch
import Yesod.Content import Yesod.Content
import Yesod.Handler import Yesod.Handler
import Network.Wai.Handler.Warp (run) import Network.Wai.Handler.Warp (runEx)
data Subsite = Subsite String data Subsite = Subsite String
@ -26,5 +26,6 @@ mkYesod "HelloWorld" [$parseRoutes|
/subsite/#String SubsiteR Subsite getSubsite /subsite/#String SubsiteR Subsite getSubsite
|] |]
instance Yesod HelloWorld where approot _ = "" instance Yesod HelloWorld where approot _ = ""
getRootR :: GHandler HelloWorld HelloWorld RepPlain -- FIXME remove type sig
getRootR = return $ RepPlain "Hello World" getRootR = return $ RepPlain "Hello World"
main = toWaiApp (HelloWorld Subsite) >>= run 3000 main = toWaiApp (HelloWorld Subsite) >>= runEx print 3000