Completely migrated from Raw to Text

This commit is contained in:
Michael Snoyman 2009-11-15 01:30:45 +02:00
parent 1decaa742b
commit 4262ffb38f
5 changed files with 98 additions and 84 deletions

View File

@ -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 "<!DOCTYPE html>\n<html><body>" -- 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 "<!DOCTYPE html>\n<html><body>" -- FIXME full doc or just fragment?
, helper o
, toLazyByteString "</body></html>"
, LT.pack "</body></html>"
] where
helper :: RawObject -> B.ByteString
helper (Scalar (Raw s)) = B.concat
[ toLazyByteString "<p>"
, toLazyByteString s
, toLazyByteString "</p>"
helper :: TextObject -> Text
helper (Scalar s) = LT.concat
[ LT.pack "<p>"
, s
, LT.pack "</p>"
]
helper (Sequence []) = toLazyByteString "<ul></ul>"
helper (Sequence s) = B.concat
[ toLazyByteString "<ul><li>"
, B.intercalate (toLazyByteString "</li><li>") $ map helper s
, toLazyByteString "</li></ul>"
helper (Sequence []) = LT.pack "<ul></ul>"
helper (Sequence s) = LT.concat
[ LT.pack "<ul><li>"
, LT.intercalate (LT.pack "</li><li>") $ map helper s
, LT.pack "</li></ul>"
]
helper (Mapping m) = B.concat $
toLazyByteString "<dl>" :
helper (Mapping m) = LT.concat $
LT.pack "<dl>" :
map helper2 m ++
[ toLazyByteString "</dl>" ]
helper2 :: (Raw, RawObject) -> B.ByteString
helper2 (Raw k, v) = B.concat
[ toLazyByteString "<dt>"
, toLazyByteString k
, toLazyByteString "</dt><dd>"
[ LT.pack "</dl>" ]
helper2 :: (Text, TextObject) -> Text
helper2 (k, v) = LT.concat
[ LT.pack "<dt>"
, k
, LT.pack "</dt><dd>"
, helper v
, toLazyByteString "</dd>"
, LT.pack "</dd>"
]

View File

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

View File

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

View File

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

View File

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