Implement --date option to evaluate the situation at a different date than when the command is run

This commit is contained in:
Tissevert 2019-04-21 22:29:56 +02:00
parent e1f338f1f1
commit 3ac6c2d40c
3 changed files with 43 additions and 24 deletions

View file

@ -1,30 +1,47 @@
module CLI ( module CLI (
Invocation(..) Invocation(..)
, Mode(..)
, invoked , invoked
) where ) where
import Options.Applicative ( import Options.Applicative (
Parser, execParser, flag, flag', fullDesc, header, help, helper, info, long, short Parser, auto, execParser, flag, fullDesc, header, help, helper, info
, infoOption, long, option, short, value
) )
import Control.Applicative ((<**>), (<|>)) import Control.Applicative ((<**>), optional)
import Data.Monoid ((<>)) import Data.Monoid ((<>))
import Data.Time (Day)
import Data.Version (showVersion) import Data.Version (showVersion)
import qualified Paths_pilu as Pilu (version) import qualified Paths_pilu as Pilu (version)
data Invocation = Inventory | Schedule | Version String data Mode = Inventory | Schedule
data Invocation = Invocation {
mode :: Mode
, date :: Maybe Day
}
versionStr :: String versionStr :: String
versionStr = showVersion Pilu.version versionStr = showVersion Pilu.version
version :: Parser (Invocation -> Invocation)
version =
infoOption versionStr
(short 'v' <> long "version" <> help "Show the version number")
invocation :: Parser Invocation invocation :: Parser Invocation
invocation = invocation = Invocation
flag' Inventory <$> flag Schedule Inventory
(short 'i' <> long "inventory" <> help "Show a full inventory") (short 'i' <> long "inventory" <> help "Show a full inventory")
<|> flag Schedule (Version versionStr) <*> option (optional auto) (
(long "version" <> help "Show the version number") value Nothing
<> short 'd'
<> long "date"
<> help "Evaluate the situation at that date"
)
invoked :: IO Invocation invoked :: IO Invocation
invoked = execParser $ invoked = execParser $
info info
(invocation <**> helper) (invocation <**> version <**> helper)
(fullDesc <> header ("Pilu v" ++ versionStr)) (fullDesc <> header ("Pilu v" ++ versionStr))

View file

@ -1,11 +1,11 @@
{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE NamedFieldPuns #-}
module Main where module Main where
import CLI (Invocation(..), invoked) import CLI (Invocation(..), Mode(..), invoked)
import CSV (Row, parse) import CSV (Row, parse)
import Data.Time (UTCTime(..), getCurrentTime) import Data.Time (Day, UTCTime(..), getCurrentTime)
import Medicine (Pharmacy, pharmacy) import Medicine (Pharmacy, pharmacy)
import System.Exit (exitFailure, exitSuccess) import System.Exit (exitFailure)
import Schedule (schedule) import Schedule (schedule)
import Timeline (State(..), stateAt) import Timeline (State(..), stateAt)
import YAML (encode) import YAML (encode)
@ -17,20 +17,19 @@ readCSV filePath = do
Left e -> (putStrLn $ show e) >> exitFailure Left e -> (putStrLn $ show e) >> exitFailure
Right rows -> return rows Right rows -> return rows
getState :: Pharmacy -> IO State getState :: Pharmacy -> Maybe Day -> IO State
getState aPharmacy = getState aPharmacy atDate =
stateAt stateAt
<$> (utctDay <$> getCurrentTime) <$> maybe (utctDay <$> getCurrentTime) return atDate
<*> (return aPharmacy) <*> return aPharmacy
<*> readCSV "timeline.csv" <*> readCSV "timeline.csv"
main :: IO () main :: IO ()
main = do main = do
invocation <- invoked invocation <- invoked
display <- case invocation of
Inventory -> return $ const encode
Schedule -> return $ \ph -> encode . schedule ph
Version version -> putStrLn version >> exitSuccess
thePharmacy <- pharmacy <$> readCSV "medicine.csv" thePharmacy <- pharmacy <$> readCSV "medicine.csv"
theState <- getState thePharmacy theState <- getState thePharmacy $ date invocation
putStrLn $ display thePharmacy theState let display = case mode invocation of
Inventory -> encode
Schedule -> encode . schedule thePharmacy
putStrLn $ display theState

View file

@ -51,7 +51,10 @@ setDay newDay state@(State {day, stock, consumptionRate}) = state {
max 0 $ initialAmount - duration * (consumptionRate ! medicineName) max 0 $ initialAmount - duration * (consumptionRate ! medicineName)
stateAt :: Day -> Pharmacy -> [Event] -> State stateAt :: Day -> Pharmacy -> [Event] -> State
stateAt targetDay pharmacy events = stateAt targetDay pharmacy =
setDay targetDay lastState setDay targetDay . lastState
where where
lastState = foldl applyEvent (initState pharmacy) (sortOn date events) lastState =
foldl applyEvent (initState pharmacy)
. sortOn date
. filter ((<= targetDay) . date)