From 4262ffb38f0eed4393606ac06057def9c9a391bc Mon Sep 17 00:00:00 2001 From: Michael Snoyman Date: Sun, 15 Nov 2009 01:30:45 +0200 Subject: [PATCH] Completely migrated from Raw to Text --- Data/Object/Instances.hs | 119 ++++++++++++++++++++----------------- Web/Restful/Application.hs | 18 +++--- Web/Restful/Handler.hs | 4 +- Web/Restful/Response.hs | 36 +++++------ restful.cabal | 5 +- 5 files changed, 98 insertions(+), 84 deletions(-) diff --git a/Data/Object/Instances.hs b/Data/Object/Instances.hs index 60cc6666..609ce8d0 100644 --- a/Data/Object/Instances.hs +++ b/Data/Object/Instances.hs @@ -1,4 +1,6 @@ {-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE MultiParamTypeClasses #-} --------------------------------------------------------- -- -- Module : Data.Object.Instances @@ -16,84 +18,91 @@ module Data.Object.Instances ( Json (..) , Yaml (..) , Html (..) - , SafeFromObject (..) ) where import Data.Object -import Data.Object.Raw +import Data.Object.Text import qualified Data.ByteString.Lazy as B -import Data.ByteString.Class import Web.Encodings (encodeJson) -import Text.Yaml (encode) +import Text.Yaml (encodeText) +import qualified Data.Text.Lazy as LT +import Data.Text.Lazy (Text) +import Data.Convertible -class SafeFromObject a where - safeFromObject :: RawObject -> a - -newtype Json = Json { unJson :: B.ByteString } -instance SafeFromObject Json where - safeFromObject = Json . helper where - helper :: RawObject -> B.ByteString - helper (Scalar (Raw s)) = B.concat - [ toLazyByteString "\"" - , encodeJson $ fromLazyByteString s - , toLazyByteString "\"" +newtype Json = Json { unJson :: Text } +instance ConvertAttempt (Object Text Text) Json where + convertAttempt = return . convertSuccess +instance ConvertSuccess (Object Text Text) Json where + convertSuccess = Json . helper where + helper :: TextObject -> Text + helper (Scalar s) = LT.concat + [ LT.pack "\"" + , bsToText $ encodeJson $ convertSuccess s + , LT.pack "\"" ] - helper (Sequence s) = B.concat - [ toLazyByteString "[" - , B.intercalate (toLazyByteString ",") $ map helper s - , toLazyByteString "]" + helper (Sequence s) = LT.concat + [ LT.pack "[" + , LT.intercalate (LT.pack ",") $ map helper s + , LT.pack "]" ] - helper (Mapping m) = B.concat - [ toLazyByteString "{" - , B.intercalate (toLazyByteString ",") $ map helper2 m - , toLazyByteString "}" + helper (Mapping m) = LT.concat + [ LT.pack "{" + , LT.intercalate (LT.pack ",") $ map helper2 m + , LT.pack "}" ] - helper2 :: (Raw, RawObject) -> B.ByteString - helper2 (Raw k, v) = B.concat - [ toLazyByteString "\"" - , encodeJson $ fromLazyByteString k - , toLazyByteString "\":" + helper2 :: (Text, TextObject) -> Text + helper2 (k, v) = LT.concat + [ LT.pack "\"" + , bsToText $ encodeJson $ convertSuccess k + , LT.pack "\":" , helper v ] -newtype Yaml = Yaml { unYaml :: B.ByteString } -instance SafeFromObject Yaml where - safeFromObject = Yaml . encode +bsToText :: B.ByteString -> Text +bsToText = convertSuccess + +newtype Yaml = Yaml { unYaml :: Text } +instance ConvertAttempt (Object Text Text) Yaml where + convertAttempt = return . convertSuccess +instance ConvertSuccess (Object Text Text) Yaml where + convertSuccess = Yaml . encodeText -- | Represents as an entire HTML 5 document by using the following: -- -- * A scalar is a paragraph. -- * A sequence is an unordered list. -- * A mapping is a definition list. -newtype Html = Html { unHtml :: B.ByteString } +newtype Html = Html { unHtml :: Text } -instance SafeFromObject Html where - safeFromObject o = Html $ B.concat - [ toLazyByteString "\n" -- FIXME full doc or just fragment? +instance ConvertAttempt (Object Text Text) Html where + convertAttempt = return . convertSuccess +instance ConvertSuccess (Object Text Text) Html where + convertSuccess o = Html $ LT.concat + [ LT.pack "\n" -- FIXME full doc or just fragment? , helper o - , toLazyByteString "" + , LT.pack "" ] where - helper :: RawObject -> B.ByteString - helper (Scalar (Raw s)) = B.concat - [ toLazyByteString "

" - , toLazyByteString s - , toLazyByteString "

" + helper :: TextObject -> Text + helper (Scalar s) = LT.concat + [ LT.pack "

" + , s + , LT.pack "

" ] - helper (Sequence []) = toLazyByteString "" - helper (Sequence s) = B.concat - [ toLazyByteString "" + helper (Sequence []) = LT.pack "" + helper (Sequence s) = LT.concat + [ LT.pack "" ] - helper (Mapping m) = B.concat $ - toLazyByteString "
" : + helper (Mapping m) = LT.concat $ + LT.pack "
" : map helper2 m ++ - [ toLazyByteString "
" ] - helper2 :: (Raw, RawObject) -> B.ByteString - helper2 (Raw k, v) = B.concat - [ toLazyByteString "
" - , toLazyByteString k - , toLazyByteString "
" + [ LT.pack "
" ] + helper2 :: (Text, TextObject) -> Text + helper2 (k, v) = LT.concat + [ LT.pack "
" + , k + , LT.pack "
" , helper v - , toLazyByteString "
" + , LT.pack "" ] diff --git a/Web/Restful/Application.hs b/Web/Restful/Application.hs index d5c01581..3f1b8a2b 100644 --- a/Web/Restful/Application.hs +++ b/Web/Restful/Application.hs @@ -23,9 +23,11 @@ module Web.Restful.Application ) where import Web.Encodings -import Data.Object.Raw +import Data.Object +import Data.Object.Text import Data.Enumerable import Control.Monad (when) +import qualified Data.Text.Lazy as LT import qualified Hack import Hack.Middleware.CleanPath @@ -59,18 +61,18 @@ class ResourceName a => RestfulApp a where -- | Output error response pages. errorHandler :: Monad m => a -> RawRequest -> ErrorResult -> [RepT m] -- FIXME better type sig? - errorHandler _ rr NotFound = reps $ toRawObject $ "Not found: " ++ show rr + errorHandler _ rr NotFound = reps $ toTextObject $ "Not found: " ++ show rr errorHandler _ _ (Redirect url) = - reps $ toRawObject $ "Redirect to: " ++ url + reps $ toTextObject $ "Redirect to: " ++ url errorHandler _ _ (InternalError e) = - reps $ toRawObject $ "Internal server error: " ++ e + reps $ toTextObject $ "Internal server error: " ++ e errorHandler _ _ (InvalidArgs ia) = - reps $ toRawObject - [ ("errorMsg", toRawObject "Invalid arguments") - , ("messages", toRawObject ia) + reps $ Mapping + [ (LT.pack "errorMsg", toTextObject "Invalid arguments") + , (LT.pack "messages", toTextObject ia) ] errorHandler _ _ PermissionDenied = - reps $ toRawObject "Permission denied" + reps $ toTextObject "Permission denied" -- | Whether or not we should check for overlapping resource names. checkOverlaps :: a -> Bool diff --git a/Web/Restful/Handler.hs b/Web/Restful/Handler.hs index 4494384b..8b06eebd 100644 --- a/Web/Restful/Handler.hs +++ b/Web/Restful/Handler.hs @@ -88,7 +88,9 @@ runHandler h rr cts = do where takeAllExceptions :: IO (Attempt x) -> IO (Attempt x) takeAllExceptions ioa = - Control.Exception.catch ioa (return . Failure) + Control.Exception.catch ioa (return . someFailure) + someFailure :: Control.Exception.SomeException -> Attempt v + someFailure = Failure toErrorResult :: Exception e => e -> ErrorResult toErrorResult e = case cast e of diff --git a/Web/Restful/Response.hs b/Web/Restful/Response.hs index cd768bf9..7f822d09 100644 --- a/Web/Restful/Response.hs +++ b/Web/Restful/Response.hs @@ -27,7 +27,6 @@ module Web.Restful.Response , Content , ToContent (..) , runContent - , lbsContent , translateContent -- * Abnormal responses , ErrorResult (..) @@ -46,11 +45,10 @@ module Web.Restful.Response import Data.Time.Clock import Data.Object -import Data.Object.Raw +import Data.Object.Text import Data.Object.Translate import Data.Object.Instances import qualified Data.ByteString.Lazy as LBS -import Data.ByteString.Class import qualified Data.Text.Lazy as LT import qualified Data.Text.Lazy.Encoding as LTE @@ -61,6 +59,9 @@ import Test.Framework (testGroup, Test) import Data.Generics import Control.Exception (Exception) import Data.Maybe (fromJust) +import Data.Convertible + +import Data.Text.Lazy (Text) data Response = Response Int [Header] ContentType Content @@ -81,14 +82,13 @@ instance ToContent LBS.ByteString where toContent = ByteString instance ToContent String where toContent = Text . LT.pack +instance ToContent Text where + toContent = Text instance ToContent ([Language] -> String) where toContent f = TransText $ LT.pack . f instance ToContent Translator where toContent = TransText -lbsContent :: LazyByteString lbs => lbs -> Content -lbsContent = ByteString . toLazyByteString - translateContent :: CanTranslate t => t -> Content translateContent t = toContent $ translate t @@ -159,28 +159,28 @@ toPair (Header key value) = return (key, value) ------ Generic responses -- FIXME move these to Handler? -- | Return a response with an arbitrary content type. -genResponse :: (Monad m, LazyByteString lbs) +genResponse :: (Monad m, ConvertSuccess t Text) => ContentType - -> lbs + -> t -> [RepT m] -genResponse ct lbs = [(ct, return $ lbsContent lbs)] +genResponse ct t = [(ct, return $ Text $ convertSuccess t)] -- | Return a response with a text/html content type. -htmlResponse :: (Monad m, LazyByteString lbs) => lbs -> [RepT m] +htmlResponse :: (Monad m, ConvertSuccess t Text) => t -> [RepT m] htmlResponse = genResponse "text/html" --- | Return a response from an Object. FIXME use TextObject -objectResponse :: (Monad m, ToObject o Raw Raw) => o -> [RepT m] -objectResponse = reps . toRawObject +-- | Return a response from an Object. +objectResponse :: (Monad m, ToObject o Text Text) => o -> [RepT m] +objectResponse = reps . toTextObject -- HasReps instances instance Monad m => HasReps () m where - reps _ = [("text/plain", return $ lbsContent "")] -instance Monad m => HasReps RawObject m where -- FIXME TextObject + reps _ = [("text/plain", return $ toContent "")] +instance Monad m => HasReps TextObject m where reps o = - [ ("text/html", return $ lbsContent $ unHtml $ safeFromObject o) - , ("application/json", return $ lbsContent $ unJson $ safeFromObject o) - , ("text/yaml", return $ lbsContent $ unYaml $ safeFromObject o) + [ ("text/html", return $ toContent $ unHtml $ convertSuccess o) + , ("application/json", return $ toContent $ unJson $ convertSuccess o) + , ("text/yaml", return $ toContent $ unYaml $ convertSuccess o) ] {- FIXME diff --git a/restful.cabal b/restful.cabal index b7cfd4d9..12cfd6bb 100644 --- a/restful.cabal +++ b/restful.cabal @@ -40,9 +40,10 @@ library directory >= 1, transformers >= 0.1.4.0, monads-fd >= 0.0.0.1, - attempt, + attempt >= 0.0.2, syb, - text >= 0.5 + text >= 0.5, + convertible >= 1.2.0 exposed-modules: Web.Restful, Web.Restful.Constants, Web.Restful.Request,