packages feed

formlets 0.3 → 0.4

raw patch · 3 files changed

+54/−33 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Text.Formlets: instance (Plus xml) => Applicative (Form xml)
- Text.Formlets: instance Functor (Form xml)
+ Text.Formlets: checkM :: (Monad m) => Form xml m a -> (a -> m (Failing b)) -> Form xml m b
+ Text.Formlets: ensureM :: (Monad m, Show a) => (a -> m Bool) -> String -> a -> m (Failing a)
+ Text.Formlets: instance (Functor m, Monad m) => Functor (Form xml m)
+ Text.Formlets: instance (Monad m, Applicative m, Plus xml) => Applicative (Form xml m)
- Text.Formlets: check :: Form xml a -> (a -> Failing b) -> Form xml b
+ Text.Formlets: check :: (Monad m) => Form xml m a -> (a -> Failing b) -> Form xml m b
- Text.Formlets: data Form xml a
+ Text.Formlets: data Form xml m a
- Text.Formlets: input' :: (String -> String -> xml) -> Maybe String -> Form xml String
+ Text.Formlets: input' :: (Monad m) => (String -> String -> xml) -> Maybe String -> Form xml m String
- Text.Formlets: inputFile :: (String -> xml) -> Form xml File
+ Text.Formlets: inputFile :: (Monad m) => (String -> xml) -> Form xml m File
- Text.Formlets: plug :: (Plus xml) => (xml -> xml) -> Form xml a -> Form xml a
+ Text.Formlets: plug :: (Plus xml) => (xml -> xml) -> Form xml m a -> Form xml m a
- Text.Formlets: runFormState :: Env -> Form xml a -> (Collector (Failing a), xml, FormContentType)
+ Text.Formlets: runFormState :: (Monad m) => Env -> Form xml m a -> (Collector (m (Failing a)), xml, FormContentType)
- Text.Formlets: xml :: xml -> Form xml ()
+ Text.Formlets: xml :: (Monad m) => xml -> Form xml m ()
- Text.XHtml.Strict.Formlets: enumRadio :: (Enum a) => [(a, String)] -> Maybe a -> XHtmlForm a
+ Text.XHtml.Strict.Formlets: enumRadio :: (Monad m, Enum a) => [(a, String)] -> Maybe a -> XHtmlForm m a
- Text.XHtml.Strict.Formlets: file :: XHtmlForm File
+ Text.XHtml.Strict.Formlets: file :: (Monad m) => XHtmlForm m File
- Text.XHtml.Strict.Formlets: hidden :: Maybe String -> XHtmlForm String
+ Text.XHtml.Strict.Formlets: hidden :: (Monad m) => Maybe String -> XHtmlForm m String
- Text.XHtml.Strict.Formlets: input :: Maybe String -> XHtmlForm String
+ Text.XHtml.Strict.Formlets: input :: (Monad m) => Maybe String -> XHtmlForm m String
- Text.XHtml.Strict.Formlets: inputInteger :: Maybe Integer -> XHtmlForm Integer
+ Text.XHtml.Strict.Formlets: inputInteger :: (Monad m) => Maybe Integer -> XHtmlForm m Integer
- Text.XHtml.Strict.Formlets: password :: Maybe String -> XHtmlForm String
+ Text.XHtml.Strict.Formlets: password :: (Monad m) => Maybe String -> XHtmlForm m String
- Text.XHtml.Strict.Formlets: radio :: [(String, String)] -> Maybe String -> XHtmlForm String
+ Text.XHtml.Strict.Formlets: radio :: (Monad m) => [(String, String)] -> Maybe String -> XHtmlForm m String
- Text.XHtml.Strict.Formlets: textarea :: Maybe String -> XHtmlForm String
+ Text.XHtml.Strict.Formlets: textarea :: (Monad m) => Maybe String -> XHtmlForm m String
- Text.XHtml.Strict.Formlets: type XHtmlForm a = Form Html a
+ Text.XHtml.Strict.Formlets: type XHtmlForm m a = Form Html m a

Files

Text/Formlets.hs view
@@ -1,5 +1,5 @@ module Text.Formlets ( input', inputFile, fmapFst-                     , check, ensure, ensures+                     , check, ensure, ensures, ensureM, checkM                      , runFormState                       , xml, plug                      , Env , Form , Plus (..)@@ -12,6 +12,7 @@ import Control.Applicative.State import Data.Maybe (isJust) import qualified Data.ByteString.Lazy as BS+import qualified Data.Traversable as T  -- Form stuff type Env = [(String, Either String File)]@@ -20,7 +21,7 @@ type Name = String type Collector a = Env -> a data FormContentType = UrlEncoded | MultiPart deriving (Eq, Show, Read)-newtype Form xml a = Form { deform :: Env -> State FormState (Collector (Failing a), xml, FormContentType) }+newtype Form xml m a = Form { deform :: Env -> State FormState (Collector (m (Failing a)), xml, FormContentType) } data File = File {content :: BS.ByteString, fileName :: String, contentType :: ContentType} deriving (Eq, Show, Read) data ContentType = ContentType { ctType :: String                                , ctSubtype :: String@@ -41,6 +42,14 @@ ensure p msg x | p x = Success x                | otherwise = Failure [msg] +ensureM :: (Monad m, Show a)+       => (a -> m Bool) -- ^ The predicate+       -> String      -- ^ The error message, in case the predicate fails+       -> a           -- ^ The value+       -> m (Failing a)+ensureM p msg x = do result <- p x+                     return $ if result then Success x else Failure [msg]+ -- | Apply multiple predicates to a value, return Success or all the Failure messages ensures :: Show a         => [(a -> Bool, String)] -- ^ List of predicate functions and error messages, in case the predicate fails@@ -51,9 +60,9 @@     where errors = [ err | (p, err) <- ps, not $ p x ]  -- | Helper function for genereting input components based forms.-input' :: (String -> String -> xml) -> Maybe String -> Form xml String+input' :: Monad m => (String -> String -> xml) -> Maybe String -> Form xml m String input' i defaultValue = Form $ \env -> mkInput env <$> freshName-   where mkInput env name = (fromLeft name . (lookup name),+   where mkInput env name = (return . fromLeft name . (lookup name),                              i name (value name env), UrlEncoded)          value name env = maybe (maybe "" id defaultValue) fromLeft' (lookup name env)          fromLeft' (Left x) = x@@ -62,44 +71,56 @@          fromLeft n (Just (Left x)) = Success x          fromLeft n _               = Failure [n ++ " is a file."] -inputFile :: (String -> xml) -> Form xml File+inputFile :: Monad m => (String -> xml) -> Form xml m File inputFile i = Form $ \env -> mkInput env <$> freshName-  where  mkInput env name    = (fromRight name . (lookup name), i name, MultiPart)+  where  mkInput env name    = (return . fromRight name . (lookup name), i name, MultiPart)          fromRight n Nothing          = Failure [n ++ " is not in the data"]          fromRight n (Just (Right x)) = Success x          fromRight n _                = Failure [n ++ " is not a file"]   -- | Runs the form state-runFormState :: Env             -- ^ A previously filled environment (may be empty)-             -> Form xml a      -- ^ The form-             -> (Collector (Failing a), xml, FormContentType)+runFormState :: Monad m +             => Env             -- ^ A previously filled environment (may be empty)+             -> Form xml m a      -- ^ The form+             -> (Collector (m (Failing a)), xml, FormContentType) runFormState e (Form f) = evalState (f e) 0  -- | Add additional validation to an already validated component-check :: Form xml a -> (a -> Failing b) -> Form xml b-check (Form frm) f = Form $ \e -> checker (frm e)- where checker = fmap $ fmapFst3 (f' .)+check :: (Monad m) => Form xml m a -> (a -> Failing b) -> Form xml m b+check (Form frm) f = Form $ fmap checker frm+ where checker = fmap $ fmapFst3 (fmap . liftM $ f') -- fmap $ fmapFst3 (fmap (f' f .))        f' (Failure x) = Failure x-       f' (Success x) = f x+       f' (Success x)  = f x +-- | Add additional validation to an already validated component+checkM :: (Monad m) => Form xml m a -> (a -> m (Failing b)) -> Form xml m b+checkM (Form frm) f = Form $ fmap checker frm+ where checker = fmap $ fmapFst3 (fmap f') -- fmap $ fmapFst3 (fmap (f' f .))+       f' v' = do v <- v'+                  case v of+                       Failure msg -> return $ Failure msg+                       Success x   -> f x -instance Functor (Form xml) where-  fmap f (Form a) = Form $ \env -> (fmap . fmapFst3 . fmap . fmap) f (a env)+instance (Functor m, Monad m) => Functor (Form xml m) where+  fmap f (Form a) = Form $ \env -> (fmap . fmapFst3 . liftM . fmap . fmap) f (a env)  fmapFst  f (a, b)    = (f a, b) fmapFst3 f (a, b, c) = (f a, b, c) -instance Plus xml => Applicative (Form xml) where+instance (Monad m, Applicative m, Plus xml) => Applicative (Form xml m) where    pure = pureF    (<*>) = applyF -pureF :: Plus xml => a -> Form xml a-pureF v = Form $ \env -> pure (const (Success v), zero, UrlEncoded)+pureF :: (Monad m, Plus xml) => a -> Form xml m a+pureF v = Form $ \env -> pure (const (return $ Success v), zero, UrlEncoded) -applyF :: Plus xml => Form xml (a -> b) -> Form xml a -> Form xml b+applyF :: (Monad m, Applicative m, Plus xml) => Form xml m (a -> b) -> Form xml m a -> Form xml m b (Form f) `applyF` (Form v) = Form $ \env -> pure combine <*> f env <*> v env-  where combine (v1, xml1, t1) (v2, xml2, t2) = (\e -> v1 e <*> v2 e, xml1 `plus` xml2, t1 `orT` t2)+  where combine (v1, xml1, t1) (v2, xml2, t2) = (first v1 v2, xml1 `plus` xml2, t1 `orT` t2)+        first v1 v2 e = do x <- v1 e +                           y <- v2 e+                           return $ x <*> y  orT UrlEncoded x = x orT x UrlEncoded = x@@ -107,11 +128,11 @@   -- | Component: just some xml-xml :: xml -> Form xml ()-xml x = Form $ \env -> pure (const $ Success (), x, UrlEncoded)+xml :: Monad m => xml -> Form xml m ()+xml x = Form $ \env -> pure (const $ return $ Success (), x, UrlEncoded)  -- | Transform the XML component-plug :: Plus xml => (xml -> xml) -> Form xml a -> Form xml a+plug :: Plus xml => (xml -> xml) -> Form xml m a -> Form xml m a f `plug` (Form m) = Form $ \env -> pure plugin <*> m env    where plugin (c, x, t) = (c, f x, t) 
Text/XHtml/Strict/Formlets.hs view
@@ -9,36 +9,36 @@ import Text.XHtml.Strict ((!), (+++)) import Control.Applicative.Error -type XHtmlForm a = Form X.Html a+type XHtmlForm m a = Form X.Html m a  instance Plus X.Html where   zero = X.noHtml   plus = (+++)  -- | An input field with an optional value-input :: Maybe String -> XHtmlForm String+input :: Monad m => Maybe String -> XHtmlForm m String input = input' (\n v -> X.textfield n ! [X.value v]) -textarea :: Maybe String -> XHtmlForm String+textarea :: Monad m => Maybe String -> XHtmlForm m String textarea = input' (\n v -> X.textarea (X.toHtml v) ! [X.name n])  -- | A password field with an optional value-password :: Maybe String -> XHtmlForm String+password :: Monad m => Maybe String -> XHtmlForm m String password = input' (\n v -> X.password n ! [X.value v])  -- | A hidden input field-hidden  :: Maybe String -> XHtmlForm String+hidden  :: Monad m => Maybe String -> XHtmlForm m String hidden  =  input' X.hidden  -- | A validated integer component-inputInteger :: Maybe Integer -> XHtmlForm Integer+inputInteger :: Monad m => Maybe Integer -> XHtmlForm m Integer inputInteger x = input (fmap show x) `check` asInteger  -file :: XHtmlForm File+file :: Monad m => XHtmlForm m File file = inputFile X.afile  -- | A radio choice-radio :: [(String, String)] -> Maybe String -> XHtmlForm String+radio :: Monad m => [(String, String)] -> Maybe String -> XHtmlForm m String radio choices = input' mkRadios -- todo: validate that the result was in the choices  where radio n v i = X.input ! [X.thetype "radio", X.name n, X.identifier i, X.theclass "radio", X.value v]        mkRadios name selected = X.concatHtml $ map (mkRadio name selected) (zip choices [1..])@@ -48,7 +48,7 @@                     | otherwise = []               ident = name ++ "_" ++ show idx -enumRadio :: (Enum a) => [(a, String)] -> Maybe a -> XHtmlForm a+enumRadio :: (Monad m, Enum a) => [(a, String)] -> Maybe a -> XHtmlForm m a enumRadio values defaultValue = radio (map toS values) (fmap (show . fromEnum) defaultValue)                                  `check` convert `check` tryToEnum  where toS = fmapFst (show . fromEnum)
formlets.cabal view
@@ -1,5 +1,5 @@ Name:            formlets-Version:         0.3+Version:         0.4 Synopsis:        Formlets implemented in Haskell Description:     A modular way to build forms based on applicative functors, as                  described in: