-
Notifications
You must be signed in to change notification settings - Fork 0
/
Stubs.hs
76 lines (61 loc) · 2.77 KB
/
Stubs.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ExplicitNamespaces #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeOperators #-}
module Maintainability.Freer.Stubs where
import qualified Data.Text as T
import Control.Monad.Freer (Eff, interpret, reinterpret)
import Control.Monad.Freer.State (State, evalState, get, put)
import Control.Monad.Freer.Writer (runWriter, tell)
import Control.Natural (type (~>))
import Data.Text (Text)
import Data.Time.Clock (NominalDiffTime, UTCTime, addUTCTime)
import Maintainability.Freer.Effects
--------------------------------------------------------------------------------
-- Simple effects
runArgumentsPure :: [Text] -> Eff (Arguments ': effs) ~> Eff effs
runArgumentsPure args = interpret $ \case
GetArgs -> pure args
runFileSystemPure :: [(Text, Text)] -> Eff (FileSystem ': effs) ~> Eff effs
runFileSystemPure fs = interpret $ \case
ReadFile path ->
maybe (fail $ "readFile: no such file ‘" ++ T.unpack path ++ "’")
pure (lookup path fs)
runLogPure :: Eff (Log ': effs) a -> Eff effs (a, [Text])
runLogPure = runWriter . reinterpret (\case
Log txt -> tell [txt])
--------------------------------------------------------------------------------
-- Time
data ClockState
= ClockStopped !UTCTime
| ClockTick !UTCTime ClockState
| ClockEndOfTime
deriving (Eq, Show)
runClockPure :: ClockState -> Eff (Time ': effs) ~> Eff effs
runClockPure initialState action = evalState initialState (handle action)
where
handle :: Eff (Time ': effs) ~> Eff (State ClockState ': effs)
handle = reinterpret $ \case
CurrentTime -> get >>= \case
ClockStopped t -> pure t
ClockTick t s -> put s >> pure t
ClockEndOfTime -> fail "currentTime: end of time"
-- | Runs a computation with a constant time that never changes.
runStoppedClockPure :: UTCTime -> Eff (Time ': effs) ~> Eff effs
runStoppedClockPure time = runClockPure (ClockStopped time)
-- | Runs a computation with a clock that advances by 1 second every time the
-- time is read.
runTickingClockPure :: UTCTime -> Eff (Time ': effs) ~> Eff effs
runTickingClockPure = runTickingClockPure' 1
-- | Runs a computation with a clock that advances by the given interval every
-- time the time is read.
runTickingClockPure' :: NominalDiffTime -> UTCTime -> Eff (Time ': effs) ~> Eff effs
runTickingClockPure' d t = runClockPure (ticks t)
where ticks t' = ClockTick t' (ticks (addUTCTime d t'))
-- | Runs a computation with a clock that replays the provided list of times, in
-- order. If the time list of times is exhausted, 'currentTime' will throw an
-- exception the next time it is called.
runPresetClockPure :: [UTCTime] -> Eff (Time ': effs) ~> Eff effs
runPresetClockPure ts = runClockPure (foldr ClockTick ClockEndOfTime ts)