packages feed

formlets (empty) → 0.1

raw patch · 5 files changed

+189/−0 lines, 5 filesdep +applicative-extrasdep +basedep +haskell98setup-changed

Dependencies added: applicative-extras, base, haskell98, mtl, xhtml

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2008, Tupil++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Tupil nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ Text/Formlets.hs view
@@ -0,0 +1,78 @@+{-# LANGUAGE TypeOperators #-}+module Text.Formlets ( module Text.Formlets.Form+                     , input , password , inputF , passwordF,ensure+                     , FailingForm, validate, runFormState, inputIntegerF+                     , check, liftForm+                     )+                     where++import Text.Formlets.Form+import Control.Applicative+import Control.Applicative.Compose+import Control.Applicative.Error+import Control.Applicative.State+import Text.XHtml.Strict ((!))+import qualified Text.XHtml.Strict as X++-- | Apply a predicate to a value and return Success or Failure as appropriate+ensure :: Show a +       => (a -> Bool) -- ^ The predicate+       -> String      -- ^ The error message, in case the predicate fails+       -> a           -- ^ The value+       -> Failing a+ensure p msg x | p x = Success x+               | otherwise = Failure [msg]++-- | Helper function for genereting input components based.+input' :: (String -> String -> X.Html) -> Maybe String -> Form String+input' i defaultValue = Form $ \env -> mkInput env <$> freshName+   where mkInput :: Env -> String -> (Collector String, Xml)+         mkInput env name = (`queryParam` name,+                             i name (value name env))+         value name env = maybe (maybe "" id defaultValue) id (lookup name env)++-- | A form whose output may fail+type FailingForm a = (Form :+: Failing) a++runFormState :: Env             -- ^ A previously filled environment (may be empty)+             -> FailingForm a   -- ^ The form+             -> FormState       -- ^ Initial form state+             -> ((Collector (Failing a), Xml), FormState)+runFormState e f s = (runState (deform (decompose f) e) s)++-- | Lifts a function on a Form to a function on a composed form.+liftForm :: (Form (f a) -> Form (f a)) -> (Form :+: f) a -> (Form :+: f) a+liftForm f = Compose . f . decompose++-- | Lift a form component to a failing form component+validate :: Form a -> FailingForm a+validate f = Compose $ pure Success <*> f++-- | Add additional validation to an already validated component+check :: FailingForm a -> (a -> Failing b) -> FailingForm b+check form f = decompose form `chk` checker f+   where chk :: Form a -> (a -> Failing b) -> FailingForm b+         chk form validator = Compose $ pure validator <*> form+         checker :: (a -> Failing b) -> (Failing a -> Failing b)+         checker f (Failure x) = Failure x+         checker f (Success x) = f x++-- | Component: an input field with an optional value+input :: Maybe String -> Form String+input = input' (\n v -> X.textfield n ! [X.value v])++-- | Component: a password field with an optional value+password :: Maybe String -> Form String+password = input' (\n v -> X.password n ! [X.value v])++-- | A trivially validated input component+inputF :: Maybe String -> FailingForm String+inputF = validate . input++-- | A trivially validated password component+passwordF :: Maybe String -> FailingForm String+passwordF = validate . password++-- | A validated integer component+inputIntegerF :: Maybe Integer -> FailingForm Integer+inputIntegerF x = validate (input $ fmap show x) `check` asInteger
+ Text/Formlets/Form.hs view
@@ -0,0 +1,59 @@+module Text.Formlets.Form where++import Control.Applicative+import Control.Applicative.State+import Text.XHtml.Strict ((+++))+import Text.XHtml.Strict as X++type Env = [(String, String)]+type FormState = Names+type Names = Integer+type Name = String+type Xml = X.Html++queryParam :: Env -> Name -> String+queryParam env name = case (name `lookup` env) of+                           Nothing -> error $ "Couldn't find " ++ name+                           Just x  -> x++newtype Form a = Form { deform :: Env -> State FormState (Collector a, X.Html) }++instance Functor Form where+  fmap f (Form a) = Form $ \env -> (fmap . fmapFst . fmap) f (a env)+   where fmapFst f (a, b) = (f a, b)++type Collector a = Env -> a++instance Applicative Form where+   pure = pureF+   (<*>) = applyF++pureF :: a -> Form a+pureF v = Form $ \env -> pure (const v, X.noHtml) -- K++applyF :: Form (a -> b) -> Form a -> Form b+(Form f) `applyF` (Form v) = Form $ \env -> pure combine <*> f env <*> v env+   where combine (f, x) (v, y) = (\e -> f e (v e), x +++ y)++-- TODO ORYO+freshName :: State FormState String+freshName = do n <- get+               put $ n + 1+               return $ "input_" ++ show n++currentName :: State FormState String+currentName = gets $ (++) "input_" . show++{- component: just some xml -}+xml :: X.Html -> Form ()+xml x = Form $ \env -> pure (const (), x)++{- component: just some text -}+text :: String -> Form ()+text s = Form $ \env -> pure (const (), toHtml s)++{- transform the XML component -}+plug :: (Xml -> Xml) -> Form a -> Form a+f `plug` (Form m) = Form $ \env -> pure plugin <*> m env+   where plugin :: (a, Xml) -> (a, Xml)+         plugin (c, x) = (c, f x)
+ formlets.cabal view
@@ -0,0 +1,20 @@+Name:            formlets+Version:         0.1+Synopsis:        Formlets implemented in Haskell+Description:     A modular way to build forms based on applicative functors, as+                 described in:+                 .+                  * Ezra Cooper, Samuel Lindley, Philip Wadler and Jeremy Yallop+                    \"An idiom's guide to formlets\"+                    Technical Report, EDI-INF-RR-1263.+                    <http://groups.inf.ed.ac.uk/links/formlets/>+Category:        XML, Web, User Interfaces, Text+License:         BSD3+License-file:    LICENSE+Copyright:       (c) Jeremy Yallop / Tupil+Author:          Jeremy Yallop / Chris Eidhof+Maintainer:      Chris Eidhof <ce+hackage@tupil.com>+Exposed-Modules:   Text.Formlets.Form+                 , Text.Formlets+Build-Type:      Simple+Build-Depends:   base, haskell98, mtl, xhtml, applicative-extras