registry-0.3.0.0: test/Test/Tutorial/Application.hs
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE StrictData #-}
module Test.Tutorial.Application where
import qualified Data.ByteString.Char8 as BS8
import Protolude
import System.Directory (doesFileExist)
import System.Random
data App = App
{ userInput :: UserInput IO,
secretReader :: SecretReader IO,
rng :: Rng IO,
console :: Console IO
}
startApp :: App -> IO ()
startApp app@App {..} = do
userAnswer <- askQuestion userInput
continue <-
case userAnswer of
Maybe -> randomBool rng
No -> pure False
Yes -> pure True
if continue
then do
secret <- readSecret secretReader
case secret of
Nothing -> write console "Sorry I actually don't know"
Just s -> do
write console ("the answer is " <> s)
startApp app
else write console "bye"
data Logger m = Logger
{ info :: Text -> m (),
error :: Text -> m ()
}
newLogger :: Logger IO
newLogger =
Logger
{ info = \t -> print $ "[INFO] " <> t,
error = \t -> print $ "[ERROR] " <> t
}
data UserAnswer = Yes | No | Maybe deriving (Eq, Show)
data UserInput m = UserInput
{ askQuestion :: m UserAnswer
}
newUserInput :: Console IO -> UserInput IO
newUserInput console =
let userInput =
UserInput
{ askQuestion = do
write console "Do you want to know the answer to Life, the Universe and Everything? (Yes/No/Maybe)"
answer <- read console
case answer of
"Yes" -> pure Yes
"No" -> pure No
"Maybe" -> pure Maybe
_ -> write console "Please enter Yes, No or Maybe" >> askQuestion userInput
}
in userInput
data Rng m = Rng
{ randomBool :: m Bool
}
newRng :: Logger IO -> Rng IO
newRng logger =
Rng
{ randomBool = do
b <- randomIO
info logger ("generated a random boolean " <> show b)
pure b
}
-- Get the secret answer and return Nothing if not found
data SecretReader m = SecretReader
{ readSecret :: m (Maybe Text)
}
data SecretReaderConfig = SecretReaderConfig Text deriving (Eq, Show)
newSecretReader :: SecretReaderConfig -> Logger IO -> SecretReader IO
newSecretReader (SecretReaderConfig path) logger =
SecretReader
{ readSecret = do
exists <- doesFileExist (toS path)
if exists
then Just . decodeUtf8 <$> BS8.readFile (toS path)
else error logger ("file does not exist at " <> path) $> Nothing
}
data Console m = Console
{ write :: Text -> m (),
read :: m Text
}
newConsole :: Console IO
newConsole = Console putStrLn (toS <$> getLine)