packages feed

digestive-functors-0.7.1.1: tests/Text/Digestive/Tests/Fixtures.hs

--------------------------------------------------------------------------------
{-# LANGUAGE OverloadedStrings #-}
module Text.Digestive.Tests.Fixtures
    ( -- * Pokemon!
      TrainerM
    , runTrainerM
    , Type (..)
    , Pokemon (..)
    , pokemonForm
    , ValidateOptionalData (..)
    , validateOptionalForm
    , IndependentValidationsData (..)
    , independentValidationsForm
    , Ball (..)
    , ballForm
    , Catch (..)
    , catchForm

      -- * Store/product
    , Database
    , runDatabase
    , sector9
    , earthwing
    , comet
    , Product (..)
    , productForm
    , Order (..)
    , orderForm
    , ordersForm

      -- * Various
    , floatForm
    ) where


--------------------------------------------------------------------------------
import           Control.Applicative          ((<$>), (<*>))
import           Control.Monad                ((>=>))
import           Control.Monad.Reader         (Reader, ask, runReader)
import           Data.Text                    (Text)
import qualified Data.Text                    as T


--------------------------------------------------------------------------------
import           Text.Digestive.Form
import           Text.Digestive.Types
import           Text.Digestive.Util


--------------------------------------------------------------------------------
-- Maximum level
type TrainerM = Reader Int


--------------------------------------------------------------------------------
-- Default max level: 20
runTrainerM :: TrainerM a -> a
runTrainerM = flip runReader 20


--------------------------------------------------------------------------------
data Type = Water | Fire | Leaf
    deriving (Eq, Show)


--------------------------------------------------------------------------------
typeForm :: Monad m => Form Text m Type
typeForm = choice [(Water, "Water"), (Fire, "Fire"), (Leaf, "Leaf")] Nothing


--------------------------------------------------------------------------------
data Pokemon = Pokemon
    { pokemonName  :: Text
    , pokemonLevel :: Maybe Int
    , pokemonType  :: Type
    , pokemonRare  :: Bool
    } deriving (Eq, Show)


--------------------------------------------------------------------------------
levelForm :: Form Text TrainerM (Maybe Int)
levelForm =
    checkM "This pokemon will not obey you!" checkMaxLevel      $
    check  "Level should be at least 1"      (maybe True (> 1)) $
    optionalStringRead "Cannot parse level" Nothing
  where
    checkMaxLevel Nothing  = return True
    checkMaxLevel (Just l) = do
        maxLevel <- ask
        return $ l <= maxLevel


--------------------------------------------------------------------------------
pokemonForm :: Form Text TrainerM Pokemon
pokemonForm = Pokemon
    <$> "name"  .: validate isPokemon (text Nothing)
    <*> "level" .: levelForm
    <*> "type"  .: typeForm
    <*> "rare"  .: bool Nothing
  where
    definitelyNoPokemon = ["dog", "cat"]
    isPokemon name
        | name `notElem` definitelyNoPokemon = Success name
        | otherwise                          =
            Error $ name `T.append` " is not a pokemon!"


--------------------------------------------------------------------------------
data Ball = Poke | Great | Ultra | Master
    deriving (Eq, Show)


--------------------------------------------------------------------------------
ballForm :: Monad m => Form Text m Ball
ballForm = choice
    [(Poke, "Poke"), (Great, "Great"), (Ultra, "Ultra"), (Master, "Master")]
    Nothing


--------------------------------------------------------------------------------
data ValidateOptionalData = ValidateOptionalData
    { firstValidateOptionalField  :: Maybe Integer
    } deriving (Eq, Show)


--------------------------------------------------------------------------------
validateOptionalForm :: Monad m => Form Text m ValidateOptionalData
validateOptionalForm = ValidateOptionalData
    <$> "first_field"  .: validateOptional (integer >=> even' >=> greaterThan 0) (optionalString Nothing)
  where
    integer s = maybe (Error "not an integer") Success (readMaybe s)
    even' n
      | n `mod` 2 == 0 = Success n
      | otherwise      = Error "input must be even"
    greaterThan x n
      | n > x     = Success n
      | otherwise = Error "input is too small"


--------------------------------------------------------------------------------
data IndependentValidationsData = IndependentValidationsData
    { firstIndependentValidationField :: Integer
    } deriving (Eq, Show)


--------------------------------------------------------------------------------
independentValidationsForm :: Monad m => Form [Text] m IndependentValidationsData
independentValidationsForm = IndependentValidationsData
    <$> "first_field"  .: validate (notEmpty >=> integer >=> conditions [even', greaterThan 10]) (string Nothing)
  where
    notEmpty x = if (null x)
      then Error ["is empty"]
      else Success x
    integer s = maybe (Error ["not an integer"]) Success (readMaybe s)
    even' n
      | n `mod` 2 == 0 = Success n
      | otherwise      = Error "input must be even"
    greaterThan x n
      | n > x     = Success n
      | otherwise = Error "input is too small"


--------------------------------------------------------------------------------
data Catch = Catch
    { catchPokemon :: Pokemon
    , catchBall    :: Ball
    } deriving (Eq, Show)


--------------------------------------------------------------------------------
catchForm :: Form Text TrainerM Catch
catchForm = check "You need a better ball" canCatch $ Catch
    <$> "pokemon" .: pokemonForm
    <*> "ball"    .: ballForm


--------------------------------------------------------------------------------
canCatch :: Catch -> Bool
canCatch (Catch (Pokemon _ _ _ False) _)      = True
canCatch (Catch (Pokemon _ _ _ True)  Ultra)  = True
canCatch (Catch (Pokemon _ _ _ True)  Master) = True
canCatch _                                    = False


--------------------------------------------------------------------------------
type Database = Reader [Product]


--------------------------------------------------------------------------------
runDatabase :: Database a -> a
runDatabase = flip runReader [sector9, earthwing, comet]


--------------------------------------------------------------------------------
sector9 :: Product
sector9 = Product "s9_ao" "Sector 9 Agent Orange"


--------------------------------------------------------------------------------
earthwing :: Product
earthwing = Product "ew_br" "Earthwing Belly Racer"


--------------------------------------------------------------------------------
comet :: Product
comet = Product "cm_gs" "Comet Grease Shark"


--------------------------------------------------------------------------------
data Product = Product
    { productId   :: Text
    , productName :: Text
    } deriving (Eq, Show)


--------------------------------------------------------------------------------
productForm :: Formlet Text Database Product
productForm def = monadic $ do
    products <- ask
    return $ choiceWith (map makeChoice products) def
  where
    makeChoice p = (productId p, (p, productName p))


--------------------------------------------------------------------------------
data Order = Order
    { orderProduct  :: Product
    , orderQuantity :: Int
    } deriving (Eq, Show)


--------------------------------------------------------------------------------
orderForm :: Formlet Text Database Order
orderForm def = Order
    <$> "product"  .: productForm              (orderProduct <$> def)
    <*> "quantity" .: stringRead "Can't parse" (orderQuantity <$> def)


--------------------------------------------------------------------------------
ordersForm :: Formlet Text Database (Text, [Order])
ordersForm def = (,)
    -- This field is disabled.
    <$> disable ("name"   .: text            (fst <$> def))
    -- id is here because of a regression
    <*> (id <$> "orders" .: listOf orderForm (snd <$> def))


--------------------------------------------------------------------------------
floatForm :: Monad m => Form Text m Float
floatForm = "f" .: stringRead "Can't parse float" Nothing