Fix time formatting and add documentation
This commit is contained in:
parent
d2d07eb15a
commit
2d9491d2fb
1 changed files with 59 additions and 20 deletions
|
|
@ -1,10 +1,13 @@
|
||||||
|
{-# LANGUAGE MultiWayIf #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
|
||||||
|
-- | This module contains a few utility functions that don't deserve their own
|
||||||
|
-- modules.
|
||||||
|
|
||||||
module Haboli.Euphoria.Util
|
module Haboli.Euphoria.Util
|
||||||
( formatUTCTime
|
(
|
||||||
, formatNominalDiffTime
|
|
||||||
-- * Events
|
-- * Events
|
||||||
, respondingToPing
|
respondingToPing
|
||||||
, respondingToBounce
|
, respondingToBounce
|
||||||
, respondingToBounce'
|
, respondingToBounce'
|
||||||
, untilConnected
|
, untilConnected
|
||||||
|
|
@ -13,6 +16,9 @@ module Haboli.Euphoria.Util
|
||||||
, nickMention
|
, nickMention
|
||||||
, nickNormalize
|
, nickNormalize
|
||||||
, nickEqual
|
, nickEqual
|
||||||
|
-- * Time formatting
|
||||||
|
, formatUTCTime
|
||||||
|
, formatNominalDiffTime
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Monad.Trans.Class
|
import Control.Monad.Trans.Class
|
||||||
|
|
@ -26,25 +32,9 @@ import Data.Time
|
||||||
import Haboli.Euphoria.Api
|
import Haboli.Euphoria.Api
|
||||||
import Haboli.Euphoria.Client
|
import Haboli.Euphoria.Client
|
||||||
|
|
||||||
formatUTCTime :: UTCTime -> T.Text
|
|
||||||
formatUTCTime t = T.pack $ formatTime defaultTimeLocale "%F %T" t
|
|
||||||
|
|
||||||
formatNominalDiffTime :: NominalDiffTime -> T.Text
|
|
||||||
formatNominalDiffTime t = T.intercalate " " $ map T.pack $ concat
|
|
||||||
[ [show days ++ "d" | days /= 0]
|
|
||||||
, [show hours ++ "h" | hours /= 0]
|
|
||||||
, [show minutes ++ "m" | minutes /= 0]
|
|
||||||
, [show seconds ++ "s"]
|
|
||||||
]
|
|
||||||
where
|
|
||||||
totalSeconds = round $ nominalDiffTimeToSeconds t :: Integer
|
|
||||||
(days, secondsAfterDays) = totalSeconds `quotRem` (60 * 60 * 24)
|
|
||||||
(hours, secondsAfterHours) = secondsAfterDays `quotRem` (60 * 60)
|
|
||||||
(minutes, seconds) = secondsAfterHours `quotRem` 60
|
|
||||||
|
|
||||||
{- Events -}
|
{- Events -}
|
||||||
|
|
||||||
-- | Respond to 'EventPing's according to the documentation (see
|
-- | Respond to 'EventPing's according to the euphoria documentation (see
|
||||||
-- <http://api.euphoria.io/#ping-event>). Passes through all events unmodified.
|
-- <http://api.euphoria.io/#ping-event>). Passes through all events unmodified.
|
||||||
--
|
--
|
||||||
-- This utility function is meant to be wrapped directly or indirectly around
|
-- This utility function is meant to be wrapped directly or indirectly around
|
||||||
|
|
@ -59,9 +49,19 @@ respondingToPing getEvent = do
|
||||||
_ -> pure ()
|
_ -> pure ()
|
||||||
pure event
|
pure event
|
||||||
|
|
||||||
|
-- | Respond to 'EventBounce's according to the euphoria documentation. If no
|
||||||
|
-- password is provided but an 'EventBounce' is encountered, throw a 'T.Text'
|
||||||
|
-- exception.
|
||||||
|
--
|
||||||
|
-- This utility function is meant to be wrapped directly or indirectly around
|
||||||
|
-- 'nextEvent':
|
||||||
|
--
|
||||||
|
-- > event <- respondingToBounce (Just passwd) nextEvent
|
||||||
respondingToBounce :: Maybe T.Text -> Client T.Text Event -> Client T.Text Event
|
respondingToBounce :: Maybe T.Text -> Client T.Text Event -> Client T.Text Event
|
||||||
respondingToBounce = respondingToBounce' id
|
respondingToBounce = respondingToBounce' id
|
||||||
|
|
||||||
|
-- | A variant of 'respondingToBounce' that allows wrapping the exception into a
|
||||||
|
-- custom type.
|
||||||
respondingToBounce' :: (T.Text -> e) -> Maybe T.Text -> Client e Event -> Client e Event
|
respondingToBounce' :: (T.Text -> e) -> Maybe T.Text -> Client e Event -> Client e Event
|
||||||
respondingToBounce' onError mPasswd getEvent = do
|
respondingToBounce' onError mPasswd getEvent = do
|
||||||
event <- getEvent
|
event <- getEvent
|
||||||
|
|
@ -77,9 +77,15 @@ respondingToBounce' onError mPasswd getEvent = do
|
||||||
_ -> pure ()
|
_ -> pure ()
|
||||||
pure event
|
pure event
|
||||||
|
|
||||||
|
-- | Receive events until both an 'EventHello' and 'EventSnapshot' were
|
||||||
|
-- received, then return those. Throw a 'T.Text' exception if an invalid 'Event'
|
||||||
|
-- was encountered. Valid events are 'EventPing', 'EventBounce', 'EventHello'
|
||||||
|
-- and 'EventSnapshot'.
|
||||||
untilConnected :: Client T.Text Event -> Client T.Text (HelloEvent, SnapshotEvent)
|
untilConnected :: Client T.Text Event -> Client T.Text (HelloEvent, SnapshotEvent)
|
||||||
untilConnected = untilConnected' id
|
untilConnected = untilConnected' id
|
||||||
|
|
||||||
|
-- | A variant of 'untilConnected' that allows wrapping the exception into a
|
||||||
|
-- custom type.
|
||||||
untilConnected' :: (T.Text -> e) -> Client e Event -> Client e (HelloEvent, SnapshotEvent)
|
untilConnected' :: (T.Text -> e) -> Client e Event -> Client e (HelloEvent, SnapshotEvent)
|
||||||
untilConnected' onError getEvent = evalStateT helper (Nothing, Nothing)
|
untilConnected' onError getEvent = evalStateT helper (Nothing, Nothing)
|
||||||
where
|
where
|
||||||
|
|
@ -98,6 +104,8 @@ untilConnected' onError getEvent = evalStateT helper (Nothing, Nothing)
|
||||||
|
|
||||||
{- Nick -}
|
{- Nick -}
|
||||||
|
|
||||||
|
-- | Modify a nick such that — when prepended with an @\@@ — it will (hopefully)
|
||||||
|
-- ping the person with that nick on euphoria.
|
||||||
nickMention :: T.Text -> T.Text
|
nickMention :: T.Text -> T.Text
|
||||||
nickMention name
|
nickMention name
|
||||||
| T.length name > 1 = T.filter isMentionChar name
|
| T.length name > 1 = T.filter isMentionChar name
|
||||||
|
|
@ -106,10 +114,41 @@ nickMention name
|
||||||
isMentionChar c = not $ isSpace c || c `Set.member` terminatingChars
|
isMentionChar c = not $ isSpace c || c `Set.member` terminatingChars
|
||||||
terminatingChars = Set.fromList ",.!?;&<'\""
|
terminatingChars = Set.fromList ",.!?;&<'\""
|
||||||
|
|
||||||
|
-- | Normalize nicks (for nick comparison purposes) by removing all space
|
||||||
|
-- characters and converting the rest into a case-insensitive representation.
|
||||||
nickNormalize :: T.Text -> T.Text
|
nickNormalize :: T.Text -> T.Text
|
||||||
nickNormalize name
|
nickNormalize name
|
||||||
| T.length name > 1 = T.toCaseFold $ T.filter (not . isSpace) name
|
| T.length name > 1 = T.toCaseFold $ T.filter (not . isSpace) name
|
||||||
| otherwise = T.toCaseFold name
|
| otherwise = T.toCaseFold name
|
||||||
|
|
||||||
|
-- | Check two nicks for equality by comparing their normalized versions.
|
||||||
nickEqual :: T.Text -> T.Text -> Bool
|
nickEqual :: T.Text -> T.Text -> Bool
|
||||||
nickEqual = (==) `on` nickNormalize
|
nickEqual = (==) `on` nickNormalize
|
||||||
|
|
||||||
|
{- Time formatting -}
|
||||||
|
|
||||||
|
-- | Convert a 'UTCTime' into the format @yyyy-mm-dd HH:MM:SS@.
|
||||||
|
formatUTCTime :: UTCTime -> T.Text
|
||||||
|
formatUTCTime t = T.pack $ formatTime defaultTimeLocale "%F %T" t
|
||||||
|
|
||||||
|
-- | Convert a 'NominalDiffTime' into the format @[[[\<days\>d ]\<hours\>h
|
||||||
|
-- ]\<minutes\>m ]\<seconds\>s@ where the square brackets denote optional parts.
|
||||||
|
-- Only those parts required to fully display the time span are output. If the
|
||||||
|
-- 'NominalDiffTime' is negative, a @-@ is prefixed.
|
||||||
|
formatNominalDiffTime :: NominalDiffTime -> T.Text
|
||||||
|
formatNominalDiffTime t = (sign <>) $ T.intercalate " " $ map T.pack $ if
|
||||||
|
| days /= 0 -> [fDays, fHours, fMinutes, fSeconds]
|
||||||
|
| hours /= 0 -> [ fHours, fMinutes, fSeconds]
|
||||||
|
| minutes /= 0 -> [ fMinutes, fSeconds]
|
||||||
|
| otherwise -> [ fSeconds]
|
||||||
|
where
|
||||||
|
diffSeconds = round $ nominalDiffTimeToSeconds t :: Integer
|
||||||
|
sign = if diffSeconds < 0 then "-" else ""
|
||||||
|
totalSeconds = abs diffSeconds
|
||||||
|
(days, secondsAfterDays) = totalSeconds `quotRem` (60 * 60 * 24)
|
||||||
|
(hours, secondsAfterHours) = secondsAfterDays `quotRem` (60 * 60)
|
||||||
|
(minutes, seconds) = secondsAfterHours `quotRem` 60
|
||||||
|
fDays = show days ++ "d"
|
||||||
|
fHours = show hours ++ "h"
|
||||||
|
fMinutes = show minutes ++ "m"
|
||||||
|
fSeconds = show seconds ++ "s"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue