----------------------------------------------------------------------------- -- | -- Module : Data.Yaml.Pretty.Extras -- Copyright : (c) Daniel Firth 2018 -- License : BSD3 -- Maintainer : locallycompact@gmail.com -- Stability : experimental -- -- This file defines yaml pretty printers with additional MonadThrow helpers -- and RIO display functionality. -- ----------------------------------------------------------------------------- module Data.Yaml.Pretty.Extras ( module Data.Yaml , module Data.Yaml.Pretty -- * Yaml Pretty Printers , ToPrettyYaml(..) , encodeFilePretty -- * RIO Helpers (Codecs and Logging) , decodeFileThrow , displayPrettyYaml , decodeFileThrowLogged , encodeFilePrettyLogged ) where import Data.Typeable import Data.Yaml import Data.Yaml.Pretty import RIO import qualified RIO.ByteString as BS import RIO.List listElemCmp as x y = fromMaybe LT $ liftA2 compare (elemIndex x as) (elemIndex y as) {- | Augments ToJSON by allowing specification of a fieldOrder for printing. > data Person = { name :: Text, age :: Int, job :: Text } > deriving (Eq, FromJSON, Generic, Show, ToJSON) > > instance ToPrettyYaml Person where > fieldOrder = const ["name", "age", "job"] -} class ToJSON a => ToPrettyYaml a where -- | The order that detected fields should be printed in, fields that aren't found in this function -- will be printed non-deterministically. fieldOrder :: a -> [Text] -- | Whether to drop null elements on this type. dropNull :: a -> Bool dropNull = const True -- | Prints a Yaml ByteString according to specified fieldOrder. toPrettyYaml :: a -> BS.ByteString toPrettyYaml = encodePretty =<< liftM2 setConfDropNull dropNull (flip setConfCompare defConfig . listElemCmp . fieldOrder) -- | A version of Data.Yaml's encodeFile using `toPrettyYaml` instead of `toJSON` encodeFilePretty :: (MonadIO m) => ToPrettyYaml a => FilePath -> a -> m () encodeFilePretty f x = BS.writeFile f (toPrettyYaml x) -- | Displays a ToPrettyYaml instance as Utf8, for use with RIO log functions displayPrettyYaml :: ToPrettyYaml a => a -> Utf8Builder displayPrettyYaml = displayBytesUtf8 . toPrettyYaml -- | A version of Data.Yaml's decodeFileEither lifted to MonadThrow decodeFileThrow :: (MonadIO m, FromJSON c, MonadThrow m) => FilePath -> m c decodeFileThrow = liftIO . decodeFileEither >=> either throwM return -- | decodeFileThrow with info logging, reports what was parsed via RIO's logInfo decodeFileThrowLogged :: ( MonadReader env m , MonadThrow m , MonadIO m , HasLogFunc env , FromJSON b , ToPrettyYaml b , Typeable b ) => FilePath -> m b decodeFileThrowLogged x = do logInfo $ "Loading " <> displayShow x (t :: b) <- decodeFileThrow x logInfo $ mconcat [ "Loaded " , displayShow x , " as " , displayShow (typeOf t) , " with contents\n" , displayPrettyYaml t ] return t -- | encodeFilePretty with info logging, reports what was saved to disk via RIO's logInfo encodeFilePrettyLogged :: ( MonadReader env m , MonadThrow m , MonadIO m , HasLogFunc env , ToPrettyYaml b , Typeable b ) => FilePath -> b -> m () encodeFilePrettyLogged x d = do logInfo $ mconcat [ "Saving " , displayShow (typeOf d) , " with contents:\n" , displayPrettyYaml d , " to " , displayShow x ] encodeFilePretty x d logInfo $ "Saved " <> displayShow x