packages feed

polysemy-fs (empty) → 0.1.0.0

raw patch · 5 files changed

+210/−0 lines, 5 filesdep +basedep +bytestringdep +path

Dependencies added: base, bytestring, path, polysemy, rio, temporary, text, unliftio-path

Files

+ ChangeLog.md view
@@ -0,0 +1,5 @@+# Changelog for polysemy-fs++## v0.1.0.0++* Small filesystem effects for polysemy.
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Daniel Firth (c) 2020++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Daniel Firth nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,52 @@+# polysemy-fs++This package offers small filesystem effects for polysemy, such as:++```+data FSExist m a where+  DoesFileExist :: Path b File -> FSExist m Bool+  DoesDirExist  :: Path b Dir  -> FSExist m Bool+```++It should be noted that these are very weak semantic abstractions, as it does+not provide a way to speak to the filesystem as a whole, and therefore is+somewhat unsuitable for mocking. These effects exist primarily to give+interpreters a way to be precise in the type of filesystem operations they use,+and should be treated in the same way as `Embed IO` in that regard. However, if+you need a quick fix - then using this directly in application code is a slight+improvement over using `Embed IO` directly.++Using these as very low level compilation units allows you to inject debugging+everywhere you use a filesystem operation. For example, using [co-log-polysemy](https://hackage.haskell.org/package/co-log-polysemy) we can do this:++```+data FileExists where+  FileExists    :: Path b File -> FileExists+  FileNotExists :: Path b File -> FileExists++data DirExists where+  DirExists    :: Path b Dir -> DirExists+  DirNotExists :: Path b Dir -> DirExists++logFileExists :: Members '[FSExist, Log FileExists] r => Sem r a -> Sem r a+logFileExists = intercept \case+  DoesFileExist x -> do+    z <- doesFileExist x+    case z of+      True  -> log $ FileExists x+      False -> log $ FileNotExists x+    return z+  DoesDirExist x -> doesDirExist x++logDirExists :: Members '[FSExist, Log DirExists] r => Sem r a -> Sem r a+logDirExists = intercept \case+  DoesDirExist x  -> do+    z <- doesDirExist x+    case z of+      True  -> log $ DirExists x+      False -> log $ DirNotExists x+    return z+  DoesFileExist x -> doesFileExist x+```++For a look at a unified version of filesystem operations, check out [polysemy-fskvstore](https://hackage.haskell.org/package/fskv-store)
+ polysemy-fs.cabal view
@@ -0,0 +1,41 @@+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.34.2.+--+-- see: https://github.com/sol/hpack++name:           polysemy-fs+version:        0.1.0.0+synopsis:       Low level filesystem operations for polysemy.+category:       Polysemy Filesystem+author:         Daniel Firth+maintainer:     dan.firth@homotopic.tech+copyright:      dan.firth@homotopic.tech+license:        BSD3+license-file:   LICENSE+build-type:     Simple+extra-source-files:+    README.md+    ChangeLog.md++source-repository head+  type: git+  location: https://gitlab.com/homotopic-tech/polysemy-fs++library+  exposed-modules:+      Polysemy.FS+  other-modules:+      Paths_polysemy_fs+  hs-source-dirs:+      src+  build-depends:+      base >=4.7 && <5+    , bytestring+    , path+    , polysemy+    , rio+    , temporary+    , text+    , unliftio-path+  default-language: Haskell2010
+ src/Polysemy/FS.hs view
@@ -0,0 +1,82 @@+{-# LANGUAGE BlockArguments #-}+{-# LANGUAGE DataKinds      #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GADTs          #-}+{-# LANGUAGE LambdaCase     #-}+{-# LANGUAGE PolyKinds      #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeOperators  #-}+module Polysemy.FS where++import Polysemy+import qualified UnliftIO.Path.Directory as U+import Data.Text (Text)+import qualified System.IO.Temp as U+import RIO+import Path+import qualified Data.ByteString as BS++data FSExist m a where+  DoesFileExist :: Path b File -> FSExist m Bool+  DoesDirExist  :: Path b Dir  -> FSExist m Bool++makeSem ''FSExist++data FSRead m a where+  ReadFileBS   :: Path b File -> FSRead m BS.ByteString+  ReadFileUtf8 :: Path b File -> FSRead m Text++makeSem ''FSRead++data FSWrite m a where+  WriteFileBS   :: Path b File -> BS.ByteString -> FSWrite m ()+  WriteFileUtf8 :: Path b File -> Text -> FSWrite m ()++makeSem ''FSWrite++data FSCopy m a where+  CopyFile :: Path b File -> Path b' File -> FSCopy m ()++makeSem ''FSCopy++data FSTemp m a where+  CreateTempDirectory :: FSTemp m (Path Abs Dir)++makeSem ''FSTemp++data FSDir m a where+  CreateDirectory :: Path b Dir -> FSDir m ()+  RemoveDirectory :: Path b Dir -> FSDir m ()++makeSem ''FSDir++runFSExist :: Member (Embed IO) r => Sem (FSExist ': r) a -> Sem r a+runFSExist = interpret \case+  DoesFileExist x -> U.doesFileExist x+  DoesDirExist x  -> U.doesDirectoryExist  x++runFSRead :: Member (Embed IO) r => Sem (FSRead ': r) a -> Sem r a+runFSRead = interpret \case+  ReadFileBS x   -> embed $ BS.readFile (toFilePath x)+  ReadFileUtf8 x -> RIO.readFileUtf8 (toFilePath x)++runFSWrite :: Member (Embed IO) r => Sem (FSWrite ': r) a -> Sem r a+runFSWrite = interpret \case+  WriteFileBS x y -> embed $ BS.writeFile (toFilePath x) y+  WriteFileUtf8 x y -> RIO.writeFileUtf8 (toFilePath x) y++runFSCopy :: Member (Embed IO) r => Sem (FSCopy ': r) a -> Sem r a+runFSCopy = interpret \case+  CopyFile x y -> U.copyFile x y++runFSDir :: Member (Embed IO) r => Sem (FSDir ': r) a -> Sem r a+runFSDir = interpret \case+  CreateDirectory x -> U.createDirectoryIfMissing True x+  RemoveDirectory x -> U.removeDirectoryRecursive x++runFSTemp :: Member (Embed IO) r => Sem (FSTemp ': r) a -> Sem r a+runFSTemp = interpret \case+  CreateTempDirectory -> do+    x <- embed U.getCanonicalTemporaryDirectory+    embed $ U.createTempDirectory x "" >>= parseAbsDir