packages feed

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 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,