scotty 0.8.0 → 0.8.1
raw patch · 11 files changed
+185/−150 lines, 11 filesdep +lifted-basedep +monad-controldep +transformers-basePVP ok
version bump matches the API change (PVP)
Dependencies added: lifted-base, monad-control, transformers-base
API changes (from Hackage documentation)
+ Web.Scotty.Internal.Types: ActionError :: e -> ActionError e
+ Web.Scotty.Internal.Types: ActionT :: ErrorT (ActionError e) (ReaderT ActionEnv (StateT ScottyResponse m)) a -> ActionT e m a
+ Web.Scotty.Internal.Types: Capture :: Text -> RoutePattern
+ Web.Scotty.Internal.Types: ContentBuilder :: Builder -> Content
+ Web.Scotty.Internal.Types: ContentFile :: FilePath -> Content
+ Web.Scotty.Internal.Types: ContentStream :: StreamingBody -> Content
+ Web.Scotty.Internal.Types: Env :: Request -> [Param] -> ByteString -> [File] -> ActionEnv
+ Web.Scotty.Internal.Types: Function :: (Request -> Maybe [Param]) -> RoutePattern
+ Web.Scotty.Internal.Types: Literal :: Text -> RoutePattern
+ Web.Scotty.Internal.Types: Next :: ActionError e
+ Web.Scotty.Internal.Types: Options :: Int -> Settings -> Options
+ Web.Scotty.Internal.Types: Redirect :: Text -> ActionError e
+ Web.Scotty.Internal.Types: SR :: Status -> ResponseHeaders -> Content -> ScottyResponse
+ Web.Scotty.Internal.Types: ScottyState :: [Middleware] -> [Middleware m] -> ErrorHandler e m -> ScottyState e m
+ Web.Scotty.Internal.Types: ScottyT :: StateT (ScottyState e m) m a -> ScottyT e m a
+ Web.Scotty.Internal.Types: addHandler :: ErrorHandler e m -> ScottyState e m -> ScottyState e m
+ Web.Scotty.Internal.Types: addMiddleware :: Middleware -> ScottyState e m -> ScottyState e m
+ Web.Scotty.Internal.Types: addRoute :: Monad m => Middleware m -> ScottyState e m -> ScottyState e m
+ Web.Scotty.Internal.Types: class ScottyError e
+ Web.Scotty.Internal.Types: data ActionEnv
+ Web.Scotty.Internal.Types: data ActionError e
+ Web.Scotty.Internal.Types: data Content
+ Web.Scotty.Internal.Types: data Options
+ Web.Scotty.Internal.Types: data RoutePattern
+ Web.Scotty.Internal.Types: data ScottyResponse
+ Web.Scotty.Internal.Types: data ScottyState e m
+ Web.Scotty.Internal.Types: getBody :: ActionEnv -> ByteString
+ Web.Scotty.Internal.Types: getFiles :: ActionEnv -> [File]
+ Web.Scotty.Internal.Types: getParams :: ActionEnv -> [Param]
+ Web.Scotty.Internal.Types: getReq :: ActionEnv -> Request
+ Web.Scotty.Internal.Types: handler :: ScottyState e m -> ErrorHandler e m
+ Web.Scotty.Internal.Types: instance (Monad m, Functor m) => Applicative (ActionT e m)
+ Web.Scotty.Internal.Types: instance (Monad m, Functor m) => Applicative (ScottyT e m)
+ Web.Scotty.Internal.Types: instance (Monad m, ScottyError e) => Monad (ActionT e m)
+ Web.Scotty.Internal.Types: instance (MonadBase b m, ScottyError e) => MonadBase b (ActionT e m)
+ Web.Scotty.Internal.Types: instance (MonadIO m, ScottyError e) => MonadIO (ActionT e m)
+ Web.Scotty.Internal.Types: instance (ScottyError e, Monad m) => MonadError (ActionError e) (ActionT e m)
+ Web.Scotty.Internal.Types: instance (ScottyError e, MonadBaseControl b m) => MonadBaseControl b (ActionT e m)
+ Web.Scotty.Internal.Types: instance Default Options
+ Web.Scotty.Internal.Types: instance Default ScottyResponse
+ Web.Scotty.Internal.Types: instance Functor m => Functor (ActionT e m)
+ Web.Scotty.Internal.Types: instance Functor m => Functor (ScottyT e m)
+ Web.Scotty.Internal.Types: instance IsString RoutePattern
+ Web.Scotty.Internal.Types: instance Monad m => Default (ScottyState e m)
+ Web.Scotty.Internal.Types: instance Monad m => Monad (ScottyT e m)
+ Web.Scotty.Internal.Types: instance MonadIO m => MonadIO (ScottyT e m)
+ Web.Scotty.Internal.Types: instance MonadTrans (ScottyT e)
+ Web.Scotty.Internal.Types: instance ScottyError Text
+ Web.Scotty.Internal.Types: instance ScottyError e => Error (ActionError e)
+ Web.Scotty.Internal.Types: instance ScottyError e => MonadTrans (ActionT e)
+ Web.Scotty.Internal.Types: instance ScottyError e => MonadTransControl (ActionT e)
+ Web.Scotty.Internal.Types: instance ScottyError e => ScottyError (ActionError e)
+ Web.Scotty.Internal.Types: middlewares :: ScottyState e m -> [Middleware]
+ Web.Scotty.Internal.Types: newtype ActionT e m a
+ Web.Scotty.Internal.Types: newtype ScottyT e m a
+ Web.Scotty.Internal.Types: routes :: ScottyState e m -> [Middleware m]
+ Web.Scotty.Internal.Types: runAM :: ActionT e m a -> ErrorT (ActionError e) (ReaderT ActionEnv (StateT ScottyResponse m)) a
+ Web.Scotty.Internal.Types: runS :: ScottyT e m a -> StateT (ScottyState e m) m a
+ Web.Scotty.Internal.Types: settings :: Options -> Settings
+ Web.Scotty.Internal.Types: showError :: ScottyError e => e -> Text
+ Web.Scotty.Internal.Types: srContent :: ScottyResponse -> Content
+ Web.Scotty.Internal.Types: srHeaders :: ScottyResponse -> ResponseHeaders
+ Web.Scotty.Internal.Types: srStatus :: ScottyResponse -> Status
+ Web.Scotty.Internal.Types: stringError :: ScottyError e => String -> e
+ Web.Scotty.Internal.Types: type Application m = Request -> m Response
+ Web.Scotty.Internal.Types: type ErrorHandler e m = Maybe (e -> ActionT e m ())
+ Web.Scotty.Internal.Types: type File = (Text, FileInfo ByteString)
+ Web.Scotty.Internal.Types: type Middleware m = Application m -> Application m
+ Web.Scotty.Internal.Types: type Param = (Text, Text)
+ Web.Scotty.Internal.Types: verbose :: Options -> Int
Files
- README.md +4/−0
- Web/Scotty.hs +1/−1
- Web/Scotty/Action.hs +1/−1
- Web/Scotty/Internal/Types.hs +161/−0
- Web/Scotty/Route.hs +1/−1
- Web/Scotty/Trans.hs +2/−2
- Web/Scotty/Types.hs +0/−139
- Web/Scotty/Util.hs +1/−1
- changelog.md +6/−0
- examples/globalstate.hs +3/−3
- scotty.cabal +5/−2
README.md view
@@ -31,4 +31,8 @@ As for the name: Sinatra + Warp = Scotty. +### Development & Support++Open an issue on GitHub or join `#scotty` on Freenode.+ Copyright (c) 2012-2013 Andrew Farmer
Web/Scotty.hs view
@@ -48,7 +48,7 @@ import Network.Wai (Application, Middleware, Request, StreamingBody) import Network.Wai.Handler.Warp (Port) -import Web.Scotty.Types (ScottyT, ActionT, Param, RoutePattern, Options, File)+import Web.Scotty.Internal.Types (ScottyT, ActionT, Param, RoutePattern, Options, File) type ScottyM = ScottyT Text IO type ActionM = ActionT Text IO
Web/Scotty/Action.hs view
@@ -50,7 +50,7 @@ import Network.HTTP.Types import Network.Wai -import Web.Scotty.Types+import Web.Scotty.Internal.Types import Web.Scotty.Util -- Nothing indicates route failed (due to Next) and pattern matching should continue.
+ Web/Scotty/Internal/Types.hs view
@@ -0,0 +1,161 @@+{-# LANGUAGE GeneralizedNewtypeDeriving, FlexibleInstances, MultiParamTypeClasses, UndecidableInstances, TypeFamilies #-}+module Web.Scotty.Internal.Types where++import Blaze.ByteString.Builder (Builder)++import Control.Applicative+import qualified Control.Exception as E+import Control.Monad.Base (MonadBase, liftBase, liftBaseDefault)+import Control.Monad.Error+import Control.Monad.Reader+import Control.Monad.State+import Control.Monad.Trans.Control (MonadBaseControl, StM, liftBaseWith, restoreM, ComposeSt, defaultLiftBaseWith, defaultRestoreM, MonadTransControl, StT, liftWith, restoreT)+++import Data.ByteString.Lazy.Char8 (ByteString)+import Data.Default (Default, def)+import Data.Monoid (mempty)+import Data.String (IsString(..))+import Data.Text.Lazy (Text, pack)++import Network.HTTP.Types++import Network.Wai hiding (Middleware, Application)+import qualified Network.Wai as Wai+import Network.Wai.Handler.Warp (Settings, defaultSettings, setFdCacheDuration)+import Network.Wai.Parse (FileInfo)++--------------------- Options -----------------------+data Options = Options { verbose :: Int -- ^ 0 = silent, 1(def) = startup banner+ , settings :: Settings -- ^ Warp 'Settings'+ -- Note: to work around an issue in warp,+ -- the default FD cache duration is set to 0+ -- so changes to static files are always picked+ -- up. This likely has performance implications,+ -- so you may want to modify this for production+ -- servers using `setFdCacheDuration`.+ }++instance Default Options where+ def = Options 1 (setFdCacheDuration 0 defaultSettings)++----- Transformer Aware Applications/Middleware -----+type Middleware m = Application m -> Application m+type Application m = Request -> m Response++--------------- Scotty Applications -----------------+data ScottyState e m =+ ScottyState { middlewares :: [Wai.Middleware]+ , routes :: [Middleware m]+ , handler :: ErrorHandler e m+ }++instance Monad m => Default (ScottyState e m) where+ def = ScottyState [] [] Nothing++addMiddleware :: Wai.Middleware -> ScottyState e m -> ScottyState e m+addMiddleware m s@(ScottyState {middlewares = ms}) = s { middlewares = m:ms }++addRoute :: Monad m => Middleware m -> ScottyState e m -> ScottyState e m+addRoute r s@(ScottyState {routes = rs}) = s { routes = r:rs }++addHandler :: ErrorHandler e m -> ScottyState e m -> ScottyState e m+addHandler h s = s { handler = h }++newtype ScottyT e m a = ScottyT { runS :: StateT (ScottyState e m) m a }+ deriving ( Functor, Applicative, Monad, MonadIO )++instance MonadTrans (ScottyT e) where+ lift = ScottyT . lift++------------------ Scotty Errors --------------------+data ActionError e = Redirect Text+ | Next+ | ActionError e++-- | In order to use a custom exception type (aside from 'Text'), you must+-- define an instance of 'ScottyError' for that type.+class ScottyError e where+ stringError :: String -> e+ showError :: e -> Text++instance ScottyError Text where+ stringError = pack+ showError = id++instance ScottyError e => ScottyError (ActionError e) where+ stringError = ActionError . stringError+ showError (Redirect url) = url+ showError Next = pack "Next"+ showError (ActionError e) = showError e++instance ScottyError e => Error (ActionError e) where+ strMsg = stringError++type ErrorHandler e m = Maybe (e -> ActionT e m ())++------------------ Scotty Actions -------------------+type Param = (Text, Text)++type File = (Text, FileInfo ByteString)++data ActionEnv = Env { getReq :: Request+ , getParams :: [Param]+ , getBody :: ByteString+ , getFiles :: [File]+ }++data Content = ContentBuilder Builder+ | ContentFile FilePath+ | ContentStream StreamingBody++data ScottyResponse = SR { srStatus :: Status+ , srHeaders :: ResponseHeaders+ , srContent :: Content+ }++instance Default ScottyResponse where+ def = SR status200 [] (ContentBuilder mempty)++newtype ActionT e m a = ActionT { runAM :: ErrorT (ActionError e) (ReaderT ActionEnv (StateT ScottyResponse m)) a }+ deriving ( Functor, Applicative, Monad )++instance (MonadIO m, ScottyError e) => MonadIO (ActionT e m) where+ liftIO io = ActionT $ do+ r <- liftIO $ liftM Right io `E.catch` (\ e -> return $ Left $ stringError $ show (e :: E.SomeException))+ either throwError return r++instance ScottyError e => MonadTrans (ActionT e) where+ lift = ActionT . lift . lift . lift++instance (ScottyError e, Monad m) => MonadError (ActionError e) (ActionT e m) where+ throwError = ActionT . throwError++ catchError (ActionT m) f = ActionT (catchError m (runAM . f))+++instance (MonadBase b m, ScottyError e) => MonadBase b (ActionT e m) where+ liftBase = liftBaseDefault+++instance (ScottyError e) => MonadTransControl (ActionT e) where+ newtype StT (ActionT e) a = StAction {unStAction :: StT (StateT ScottyResponse) (StT (ReaderT ActionEnv) (StT (ErrorT (ActionError e)) a))}+ liftWith = \f ->+ ActionT $ liftWith $ \run ->+ liftWith $ \run' ->+ liftWith $ \run'' ->+ f $ liftM StAction . run'' . run' . run . runAM+ restoreT = ActionT . restoreT . restoreT . restoreT . liftM unStAction++instance (ScottyError e, MonadBaseControl b m) => MonadBaseControl b (ActionT e m) where+ newtype StM (ActionT e m) a = STMAction {unStMActionT :: ComposeSt (ActionT e) m a}+ liftBaseWith = defaultLiftBaseWith STMAction+ restoreM = defaultRestoreM unStMActionT++------------------ Scotty Routes --------------------+data RoutePattern = Capture Text+ | Literal Text+ | Function (Request -> Maybe [Param])++instance IsString RoutePattern where+ fromString = Capture . pack
Web/Scotty/Route.hs view
@@ -25,7 +25,7 @@ import qualified Text.Regex as Regex import Web.Scotty.Action-import Web.Scotty.Types+import Web.Scotty.Internal.Types import Web.Scotty.Util -- | get = 'addroute' 'GET'
Web/Scotty/Trans.hs view
@@ -55,8 +55,8 @@ import Web.Scotty.Action hiding (source) import qualified Web.Scotty.Action as Action import Web.Scotty.Route-import Web.Scotty.Types hiding (Application, Middleware)-import qualified Web.Scotty.Types as Scotty+import Web.Scotty.Internal.Types hiding (Application, Middleware)+import qualified Web.Scotty.Internal.Types as Scotty -- | Set the body of the response to a Source. Doesn't set the -- \"Content-Type\" header, so you probably want to do that on your
− Web/Scotty/Types.hs
@@ -1,139 +0,0 @@-{-# LANGUAGE GeneralizedNewtypeDeriving, FlexibleInstances, MultiParamTypeClasses #-}-module Web.Scotty.Types where--import Blaze.ByteString.Builder (Builder)--import Control.Applicative-import qualified Control.Exception as E-import Control.Monad.Error-import Control.Monad.Reader-import Control.Monad.State--import Data.ByteString.Lazy.Char8 (ByteString)-import Data.Default (Default, def)-import Data.Monoid (mempty)-import Data.String (IsString(..))-import Data.Text.Lazy (Text, pack)--import Network.HTTP.Types--import Network.Wai hiding (Middleware, Application)-import qualified Network.Wai as Wai-import Network.Wai.Handler.Warp (Settings, defaultSettings, setFdCacheDuration)-import Network.Wai.Parse (FileInfo)----------------------- Options ------------------------data Options = Options { verbose :: Int -- ^ 0 = silent, 1(def) = startup banner- , settings :: Settings -- ^ Warp 'Settings'- -- Note: to work around an issue in warp,- -- the default FD cache duration is set to 0- -- so changes to static files are always picked- -- up. This likely has performance implications,- -- so you may want to modify this for production- -- servers using `setFdCacheDuration`.- }--instance Default Options where- def = Options 1 (setFdCacheDuration 0 defaultSettings)------- Transformer Aware Applications/Middleware ------type Middleware m = Application m -> Application m-type Application m = Request -> m Response----------------- Scotty Applications ------------------data ScottyState e m =- ScottyState { middlewares :: [Wai.Middleware]- , routes :: [Middleware m]- , handler :: ErrorHandler e m- }--instance Monad m => Default (ScottyState e m) where- def = ScottyState [] [] Nothing--addMiddleware :: Wai.Middleware -> ScottyState e m -> ScottyState e m-addMiddleware m s@(ScottyState {middlewares = ms}) = s { middlewares = m:ms }--addRoute :: Monad m => Middleware m -> ScottyState e m -> ScottyState e m-addRoute r s@(ScottyState {routes = rs}) = s { routes = r:rs }--addHandler :: ErrorHandler e m -> ScottyState e m -> ScottyState e m-addHandler h s = s { handler = h }--newtype ScottyT e m a = ScottyT { runS :: StateT (ScottyState e m) m a }- deriving ( Functor, Applicative, Monad, MonadIO )--instance MonadTrans (ScottyT e) where- lift = ScottyT . lift-------------------- Scotty Errors ---------------------data ActionError e = Redirect Text- | Next- | ActionError e---- | In order to use a custom exception type (aside from 'Text'), you must--- define an instance of 'ScottyError' for that type.-class ScottyError e where- stringError :: String -> e- showError :: e -> Text--instance ScottyError Text where- stringError = pack- showError = id--instance ScottyError e => ScottyError (ActionError e) where- stringError = ActionError . stringError- showError (Redirect url) = url- showError Next = pack "Next"- showError (ActionError e) = showError e--instance ScottyError e => Error (ActionError e) where- strMsg = stringError--type ErrorHandler e m = Maybe (e -> ActionT e m ())-------------------- Scotty Actions --------------------type Param = (Text, Text)--type File = (Text, FileInfo ByteString)--data ActionEnv = Env { getReq :: Request- , getParams :: [Param]- , getBody :: ByteString- , getFiles :: [File]- }--data Content = ContentBuilder Builder- | ContentFile FilePath- | ContentStream StreamingBody--data ScottyResponse = SR { srStatus :: Status- , srHeaders :: ResponseHeaders- , srContent :: Content- }--instance Default ScottyResponse where- def = SR status200 [] (ContentBuilder mempty)--newtype ActionT e m a = ActionT { runAM :: ErrorT (ActionError e) (ReaderT ActionEnv (StateT ScottyResponse m)) a }- deriving ( Functor, Applicative, Monad )--instance (MonadIO m, ScottyError e) => MonadIO (ActionT e m) where- liftIO io = ActionT $ do- r <- liftIO $ liftM Right io `E.catch` (\ e -> return $ Left $ stringError $ show (e :: E.SomeException))- either throwError return r--instance ScottyError e => MonadTrans (ActionT e) where- lift = ActionT . lift . lift . lift--instance (ScottyError e, Monad m) => MonadError (ActionError e) (ActionT e m) where- throwError = ActionT . throwError-- catchError (ActionT m) f = ActionT (catchError m (runAM . f))-------------------- Scotty Routes ---------------------data RoutePattern = Capture Text- | Literal Text- | Function (Request -> Maybe [Param])--instance IsString RoutePattern where- fromString = Capture . pack
Web/Scotty/Util.hs view
@@ -17,7 +17,7 @@ import qualified Data.Text.Lazy as T import qualified Data.Text.Encoding as ES -import Web.Scotty.Types+import Web.Scotty.Internal.Types lazyTextToStrictByteString :: T.Text -> B.ByteString lazyTextToStrictByteString = ES.encodeUtf8 . T.toStrict
changelog.md view
@@ -1,3 +1,9 @@+## 0.8.1++* Export internal types+* Added `MonadBase`, `MonadTransControl` and `MonadBaseControl` instances for+ `ActionT`+ ## 0.8.0 * Upgrade to wai/wai-extra/warp 3.0
examples/globalstate.hs view
@@ -10,7 +10,7 @@ module Main where import Control.Concurrent.STM-import Control.Monad.Reader +import Control.Monad.Reader import Data.Default import Data.String@@ -30,9 +30,9 @@ -- to provide the state to _every action_, and save the resulting -- state, using an MVar. This means actions would be blocking, -- effectively meaning only one request could be serviced at a time.--- The 'ReaderT' solution means only actions that actually modify +-- The 'ReaderT' solution means only actions that actually modify -- the state need to block/retry.--- +-- -- Also note: your monad must be an instance of 'MonadIO' for -- Scotty to use it. newtype WebM a = WebM { runWebM :: ReaderT (TVar AppState) IO a }
scotty.cabal view
@@ -1,5 +1,5 @@ Name: scotty-Version: 0.8.0+Version: 0.8.1 Synopsis: Haskell web framework inspired by Ruby's Sinatra, using WAI and Warp Homepage: https://github.com/scotty-web/scotty Bug-reports: https://github.com/scotty-web/scotty/issues@@ -63,9 +63,9 @@ Library Exposed-modules: Web.Scotty Web.Scotty.Trans+ Web.Scotty.Internal.Types other-modules: Web.Scotty.Action Web.Scotty.Route- Web.Scotty.Types Web.Scotty.Util default-language: Haskell2010 build-depends: aeson >= 0.6.2.1 && < 0.8,@@ -77,9 +77,11 @@ data-default >= 0.5.3 && < 0.6, http-types >= 0.8.2 && < 0.9, mtl >= 2.1.2 && < 2.3,+ monad-control >= 0.3.2.3 && < 0.4, regex-compat >= 0.95.1 && < 0.96, text >= 0.11.3.1 && < 1.2, transformers >= 0.3.0.0 && < 0.5,+ transformers-base >= 0.4.1 && < 0.5, wai >= 3.0.0 && < 3.1, wai-extra >= 3.0.0 && < 3.1, warp >= 3.0.0 && < 3.1@@ -94,6 +96,7 @@ build-depends: base, bytestring, http-types,+ lifted-base, wai, hspec >= 1.9.2, wai-extra >= 3.0.0,