mkYesodGeneral arguments can now be monomorphic or polymorphic types. It is possible to impose class instances to polymorphic type arguments.
This commit is contained in:
parent
366bfbd319
commit
ea62a38464
@ -11,6 +11,7 @@ module Yesod.Core.Dispatch
|
|||||||
, parseRoutesFile
|
, parseRoutesFile
|
||||||
, parseRoutesFileNoCheck
|
, parseRoutesFileNoCheck
|
||||||
, mkYesod
|
, mkYesod
|
||||||
|
, mkYesodWith
|
||||||
-- ** More fine-grained
|
-- ** More fine-grained
|
||||||
, mkYesodData
|
, mkYesodData
|
||||||
, mkYesodSubData
|
, mkYesodSubData
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import qualified Network.Wai as W
|
|||||||
import Data.ByteString.Lazy.Char8 ()
|
import Data.ByteString.Lazy.Char8 ()
|
||||||
import Data.List (foldl')
|
import Data.List (foldl')
|
||||||
import Control.Monad (replicateM)
|
import Control.Monad (replicateM)
|
||||||
|
import Data.Either (partitionEithers)
|
||||||
|
|
||||||
import Yesod.Routes.TH
|
import Yesod.Routes.TH
|
||||||
import Yesod.Routes.Parse
|
import Yesod.Routes.Parse
|
||||||
@ -32,6 +33,12 @@ mkYesod :: String -- ^ name of the argument datatype
|
|||||||
-> Q [Dec]
|
-> Q [Dec]
|
||||||
mkYesod name = fmap (uncurry (++)) . mkYesodGeneral name [] False
|
mkYesod name = fmap (uncurry (++)) . mkYesodGeneral name [] False
|
||||||
|
|
||||||
|
mkYesodWith :: String
|
||||||
|
-> [Either String [String]]
|
||||||
|
-> [ResourceTree String]
|
||||||
|
-> Q [Dec]
|
||||||
|
mkYesodWith name args = fmap (uncurry (++)) . mkYesodGeneral name args False
|
||||||
|
|
||||||
-- | Sometimes, you will want to declare your routes in one file and define
|
-- | Sometimes, you will want to declare your routes in one file and define
|
||||||
-- your handlers elsewhere. For example, this is the only way to break up a
|
-- your handlers elsewhere. For example, this is the only way to break up a
|
||||||
-- monolithic file into smaller parts. Use this function, paired with
|
-- monolithic file into smaller parts. Use this function, paired with
|
||||||
@ -45,7 +52,7 @@ mkYesodSubData name res = mkYesodDataGeneral name True res
|
|||||||
mkYesodDataGeneral :: String -> Bool -> [ResourceTree String] -> Q [Dec]
|
mkYesodDataGeneral :: String -> Bool -> [ResourceTree String] -> Q [Dec]
|
||||||
mkYesodDataGeneral name isSub res = do
|
mkYesodDataGeneral name isSub res = do
|
||||||
let (name':rest) = words name
|
let (name':rest) = words name
|
||||||
fmap fst $ mkYesodGeneral name' rest isSub res
|
fmap fst $ mkYesodGeneral name' (fmap Left rest) isSub res
|
||||||
|
|
||||||
-- | See 'mkYesodData'.
|
-- | See 'mkYesodData'.
|
||||||
mkYesodDispatch :: String -> [ResourceTree String] -> Q [Dec]
|
mkYesodDispatch :: String -> [ResourceTree String] -> Q [Dec]
|
||||||
@ -60,9 +67,12 @@ masterTypeSyns vs site =
|
|||||||
$ ConT ''WidgetT `AppT` site `AppT` ConT ''IO `AppT` ConT ''()
|
$ ConT ''WidgetT `AppT` site `AppT` ConT ''IO `AppT` ConT ''()
|
||||||
]
|
]
|
||||||
|
|
||||||
|
-- | 'Left' arguments indicate a monomorphic type, a 'Right' argument
|
||||||
|
-- indicates a polymorphic type, and provides the list of classes
|
||||||
|
-- the type must be instance of.
|
||||||
mkYesodGeneral :: String -- ^ foundation type
|
mkYesodGeneral :: String -- ^ foundation type
|
||||||
-> [String] -- ^ arguments for the type
|
-> [Either String [String]] -- ^ arguments for the type
|
||||||
-> Bool -- ^ it this a subsite
|
-> Bool -- ^ is this a subsite
|
||||||
-> [ResourceTree String]
|
-> [ResourceTree String]
|
||||||
-> Q([Dec],[Dec])
|
-> Q([Dec],[Dec])
|
||||||
mkYesodGeneral name args isSub resS = do
|
mkYesodGeneral name args isSub resS = do
|
||||||
@ -75,17 +85,22 @@ mkYesodGeneral name args isSub resS = do
|
|||||||
NewtypeD _ _ vs _ _ -> length vs
|
NewtypeD _ _ vs _ _ -> length vs
|
||||||
_ -> 0
|
_ -> 0
|
||||||
_ -> 0
|
_ -> 0
|
||||||
|
(mtys,ptys) = partitionEithers args
|
||||||
-- Generate as many variable names as the arity indicates
|
-- Generate as many variable names as the arity indicates
|
||||||
vns <- replicateM arity $ newName "t"
|
vns <- replicateM (arity - length mtys) $ newName "t"
|
||||||
-- Variables for type parameters
|
|
||||||
let vs = fmap VarT vns
|
|
||||||
-- Base type (site type with variables)
|
-- Base type (site type with variables)
|
||||||
basety = foldl' AppT (ConT $ mkName name) vs
|
let (argtypes,cxt) = (\(ns,r,cs) -> (ns ++ fmap VarT r, cs)) $
|
||||||
site = foldl' AppT basety (map (VarT . mkName) args)
|
foldr (\arg (xs,n:ns,cs) ->
|
||||||
|
case arg of
|
||||||
|
Left t -> ( ConT (mkName t):xs, n:ns, cs )
|
||||||
|
Right ts -> ( VarT n :xs, ns
|
||||||
|
, fmap (\t -> AppT (ConT $ mkName t) (VarT n)) ts ++ cs )
|
||||||
|
) ([],vns,[]) args
|
||||||
|
site = foldl' AppT (ConT $ mkName name) argtypes
|
||||||
res = map (fmap parseType) resS
|
res = map (fmap parseType) resS
|
||||||
renderRouteDec <- mkRenderRouteInstance site res
|
renderRouteDec <- mkRenderRouteInstance site res
|
||||||
routeAttrsDec <- mkRouteAttrsInstance site res
|
routeAttrsDec <- mkRouteAttrsInstance site res
|
||||||
dispatchDec <- mkDispatchInstance site res
|
dispatchDec <- mkDispatchInstance site cxt res
|
||||||
parse <- mkParseRouteInstance site res
|
parse <- mkParseRouteInstance site res
|
||||||
let rname = mkName $ "resources" ++ name
|
let rname = mkName $ "resources" ++ name
|
||||||
eres <- lift resS
|
eres <- lift resS
|
||||||
@ -128,12 +143,13 @@ mkMDS rh = MkDispatchSettings
|
|||||||
-- when writing library/plugin for yesod, this combinator becomes
|
-- when writing library/plugin for yesod, this combinator becomes
|
||||||
-- handy.
|
-- handy.
|
||||||
mkDispatchInstance :: Type -- ^ The master site type
|
mkDispatchInstance :: Type -- ^ The master site type
|
||||||
|
-> Cxt -- ^ Context of the instance
|
||||||
-> [ResourceTree a] -- ^ The resource
|
-> [ResourceTree a] -- ^ The resource
|
||||||
-> DecsQ
|
-> DecsQ
|
||||||
mkDispatchInstance master res = do
|
mkDispatchInstance master cxt res = do
|
||||||
clause' <- mkDispatchClause (mkMDS [|yesodRunner|]) res
|
clause' <- mkDispatchClause (mkMDS [|yesodRunner|]) res
|
||||||
let thisDispatch = FunD 'yesodDispatch [clause']
|
let thisDispatch = FunD 'yesodDispatch [clause']
|
||||||
return [InstanceD [] yDispatch [thisDispatch]]
|
return [InstanceD cxt yDispatch [thisDispatch]]
|
||||||
where
|
where
|
||||||
yDispatch = ConT ''YesodDispatch `AppT` master
|
yDispatch = ConT ''YesodDispatch `AppT` master
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user