shikensu 0.1.3 → 0.2.0
raw patch · 15 files changed
+755/−554 lines, 15 filesdep ~basedep ~textPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base, text
API changes (from Hackage documentation)
- Shikensu.Utilities: cleanPath :: FilePath -> FilePath
- Shikensu.Utilities: commonDirectory :: Pattern -> FilePath
- Shikensu.Utilities: compileParentPath :: FilePath -> Maybe FilePath
- Shikensu.Utilities: compilePathToRoot :: FilePath -> FilePath
- Shikensu.Utilities: compilePatterns :: [Pattern] -> [Pattern]
- Shikensu.Utilities: globDir :: FilePath -> [Pattern] -> IO [[FilePath]]
- Shikensu.Utilities: replaceSingleDot :: String -> String
- Shikensu.Utilities: stripPrefix :: String -> String -> String
- Shikensu.Utilities: takeDirName :: FilePath -> FilePath
+ Shikensu: listF :: [Pattern] -> FilePath -> IO Dictionary
+ Shikensu.Internal.Utilities: cleanPath :: FilePath -> FilePath
+ Shikensu.Internal.Utilities: commonDirectory :: Pattern -> FilePath
+ Shikensu.Internal.Utilities: compileParentPath :: FilePath -> Maybe FilePath
+ Shikensu.Internal.Utilities: compilePathToRoot :: FilePath -> FilePath
+ Shikensu.Internal.Utilities: compilePatterns :: [Pattern] -> [Pattern]
+ Shikensu.Internal.Utilities: globDir :: FilePath -> [Pattern] -> IO [[FilePath]]
+ Shikensu.Internal.Utilities: replaceSingleDot :: String -> String
+ Shikensu.Internal.Utilities: stripPrefix :: String -> String -> String
+ Shikensu.Internal.Utilities: takeDirName :: FilePath -> FilePath
+ Shikensu.Utilities: (⚡) :: (FromJSON a, ToJSON a) => Metadata -> Text -> Maybe a
+ Shikensu.Utilities: (⚡⚡) :: (FromJSON a, ToJSON a) => Metadata -> Text -> a
+ Shikensu.Utilities: lsequence :: Monad m => [(String, m a)] -> m [(String, a)]
- Shikensu: list :: [Pattern] -> FilePath -> IO Dictionary
+ Shikensu: list :: FilePath -> [Pattern] -> IO Dictionary
Files
- shikensu.cabal +10/−4
- src/Shikensu.hs +64/−57
- src/Shikensu/Contrib.hs +78/−70
- src/Shikensu/Contrib/IO.hs +27/−25
- src/Shikensu/Internal/Utilities.hs +113/−0
- src/Shikensu/Metadata.hs +22/−22
- src/Shikensu/Sorting.hs +3/−3
- src/Shikensu/Types.hs +26/−26
- src/Shikensu/Utilities.hs +69/−85
- tests/Test.hs +8/−6
- tests/Test/Contrib.hs +137/−135
- tests/Test/Example.hs +25/−24
- tests/Test/Helpers.hs +22/−15
- tests/Test/Shikensu.hs +82/−82
- tests/Test/Utilities.hs +69/−0
shikensu.cabal view
@@ -1,5 +1,5 @@ name: shikensu-version: 0.1.3+version: 0.2.0 category: File IO synopsis:@@ -40,6 +40,7 @@ Shikensu, Shikensu.Contrib, Shikensu.Contrib.IO,+ Shikensu.Internal.Utilities, Shikensu.Metadata, Shikensu.Sorting, Shikensu.Types,@@ -53,13 +54,17 @@ filepath == 1.4.*, flow == 1.0.*, Glob == 0.7.*,- unordered-containers == 0.2.*+ unordered-containers == 0.2.*,+ text >= 1.2 && < 2 test-suite tests default-language: Haskell2010 + default-extensions:+ OverloadedStrings+ ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N @@ -76,7 +81,8 @@ Test.Contrib, Test.Example, Test.Helpers,- Test.Shikensu+ Test.Shikensu,+ Test.Utilities build-depends: aeson,@@ -88,5 +94,5 @@ shikensu, tasty == 0.11.*, tasty-hunit == 0.9.*,- text >= 1.2 && < 2,+ text, unordered-containers
src/Shikensu.hs view
@@ -4,16 +4,17 @@ -} module Shikensu- ( list+ ( list+ , listF - , forkDefinition- , makeDefinition- , makeDictionary- ) where+ , forkDefinition+ , makeDefinition+ , makeDictionary+ ) where import Flow+import Shikensu.Internal.Utilities import Shikensu.Types-import Shikensu.Utilities import System.FilePath import qualified Data.HashMap.Strict as HashMap (empty)@@ -24,7 +25,7 @@ -- IO -{-| Make a single dictionary based on multiple glob patterns and a path to a directory.+{-| Make a single dictionary based on a path to a directory and multiple glob patterns. 1. Compile patterns so `globDir` can use them. 2. Run `globDir` function on the given (root) path.@@ -34,18 +35,23 @@ 5. Merge the dictionaries into one dictionary. -}-list :: [Pattern] -> FilePath -> IO Dictionary-list patterns rootDir =- patterns- |> compilePatterns- |> globDir rootDir- |> fmap (List.zip patterns)- |> fmap (List.map (uncurry . makeDictionary $ rootDir))- |> fmap (List.concat)+list :: FilePath -> [Pattern] -> IO Dictionary+list rootDir patterns =+ patterns+ |> compilePatterns+ |> globDir rootDir+ |> fmap (List.zip patterns)+ |> fmap (List.map (uncurry . makeDictionary $ rootDir))+ |> fmap (List.concat) +listF :: [Pattern] -> FilePath -> IO Dictionary+listF patterns rootDir =+ list rootDir patterns ++ -- PURE @@ -53,20 +59,20 @@ -} forkDefinition :: FilePath -> Definition -> Definition forkDefinition newLocalPath def =- Definition- { basename = takeBaseName newLocalPath- , dirname = takeDirName newLocalPath- , extname = takeExtension newLocalPath- , pattern = (pattern def)- , rootDirname = (rootDirname def)- , workingDirname = (workingDirname def)+ Definition+ { basename = takeBaseName newLocalPath+ , dirname = takeDirName newLocalPath+ , extname = takeExtension newLocalPath+ , pattern = (pattern def)+ , rootDirname = (rootDirname def)+ , workingDirname = (workingDirname def) - -- Additional properties- , content = (content def)- , metadata = (metadata def)- , parentPath = compileParentPath $ takeDirName newLocalPath- , pathToRoot = compilePathToRoot $ takeDirName newLocalPath- }+ -- Additional properties+ , content = (content def)+ , metadata = (metadata def)+ , parentPath = compileParentPath $ takeDirName newLocalPath+ , pathToRoot = compilePathToRoot $ takeDirName newLocalPath+ } @@ -79,44 +85,45 @@ - the workspace path `example/test/hello.md` > Definition-> { basename = "hello"-> , dirname = "test"-> , extname = ".md"-> , pattern = "example/**/*.md"-> , rootDirname = "/Users/icidasset/Projects/shikensu"-> , workingDirname = "example"+> { basename = "hello"+> , dirname = "test"+> , extname = ".md"+> , pattern = "example/**/*.md"+> , rootDirname = "/Users/icidasset/Projects/shikensu"+> , workingDirname = "example" >-> , content = Nothing-> , metadata = HashMap.empty-> , parentPath = "../"-> , pathToRoot = "../../"-> }+> , content = Nothing+> , metadata = HashMap.empty+> , parentPath = "../"+> , pathToRoot = "../../"+> } -} makeDefinition :: FilePath -> Pattern -> FilePath -> Definition makeDefinition _rootDirname _pattern _workspacePath =- let- workingDir = cleanPath . (commonDirectory) $ _pattern- localPath = cleanPath . (stripPrefix workingDir) . cleanPath $ _workspacePath- in- Definition- { basename = takeBaseName localPath- , dirname = takeDirName localPath- , extname = takeExtension localPath- , pattern = _pattern- , rootDirname = dropTrailingPathSeparator _rootDirname- , workingDirname = workingDir+ let+ workingDir = cleanPath . (commonDirectory) $ _pattern+ localPath = cleanPath . (stripPrefix workingDir) . cleanPath $ _workspacePath+ in+ Definition+ { basename = takeBaseName localPath+ , dirname = takeDirName localPath+ , extname = takeExtension localPath+ , pattern = _pattern+ , rootDirname = dropTrailingPathSeparator _rootDirname+ , workingDirname = workingDir - -- Additional properties- , content = Nothing- , metadata = HashMap.empty- , parentPath = compileParentPath $ takeDirName localPath- , pathToRoot = compilePathToRoot $ takeDirName localPath- }+ -- Additional properties+ , content = Nothing+ , metadata = HashMap.empty+ , parentPath = compileParentPath $ takeDirName localPath+ , pathToRoot = compilePathToRoot $ takeDirName localPath+ } {-| Make a Dictionary. -} makeDictionary :: FilePath -> Pattern -> [FilePath] -> Dictionary-makeDictionary _rootDirname _pattern = List.map (makeDefinition _rootDirname _pattern)+makeDictionary _rootDirname _pattern =+ List.map (makeDefinition _rootDirname _pattern)
src/Shikensu/Contrib.hs view
@@ -2,34 +2,34 @@ -} module Shikensu.Contrib- ( clearMetadata- , clearMetadataDef- , clone- , copyPropsToMetadata- , copyPropsToMetadataDef- , exclude- , insertMetadata- , insertMetadataDef- , permalink- , permalinkDef- , prefixDirname- , prefixDirnameDef- , rename- , renameDef- , renameExt- , renameExtDef- , renderContent- , renderContentDef- , replaceMetadata- , replaceMetadataDef- ) where+ ( clearMetadata+ , clearMetadataDef+ , clone+ , copyPropsToMetadata+ , copyPropsToMetadataDef+ , exclude+ , insertMetadata+ , insertMetadataDef+ , permalink+ , permalinkDef+ , prefixDirname+ , prefixDirnameDef+ , rename+ , renameDef+ , renameExt+ , renameExtDef+ , renderContent+ , renderContentDef+ , replaceMetadata+ , replaceMetadataDef+ ) where import Data.ByteString (ByteString) import Flow import Shikensu (forkDefinition)+import Shikensu.Internal.Utilities (cleanPath, compileParentPath, compilePathToRoot) import Shikensu.Metadata (transposeToMetadata) import Shikensu.Types-import Shikensu.Utilities (cleanPath, compileParentPath, compilePathToRoot) import System.FilePath (FilePath, combine) import qualified Data.HashMap.Strict as HashMap (empty, union)@@ -40,11 +40,13 @@ Replace the current hash map with an empty one. -} clearMetadata :: Dictionary -> Dictionary-clearMetadata = fmap (clearMetadataDef)+clearMetadata =+ fmap (clearMetadataDef) clearMetadataDef :: Definition -> Definition-clearMetadataDef def = def { metadata = HashMap.empty }+clearMetadataDef def =+ def { metadata = HashMap.empty } @@ -58,13 +60,13 @@ -} clone :: FilePath -> FilePath -> Dictionary -> Dictionary clone existingPath newPath dict =- let- makeNew = \def acc ->- if (localPath def) == existingPath- then acc ++ [forkDefinition newPath def]- else acc- in- dict ++ (foldr makeNew [] dict)+ let+ makeNew = \def acc ->+ if (localPath def) == existingPath+ then acc ++ [forkDefinition newPath def]+ else acc+ in+ dict ++ (foldr makeNew [] dict) @@ -74,13 +76,14 @@ to see what properties get put in here. -} copyPropsToMetadata :: Dictionary -> Dictionary-copyPropsToMetadata = fmap (copyPropsToMetadataDef)+copyPropsToMetadata =+ fmap (copyPropsToMetadataDef) copyPropsToMetadataDef :: Definition -> Definition-copyPropsToMetadataDef def = def {- metadata = HashMap.union (transposeToMetadata def) (metadata def)- }+copyPropsToMetadataDef def =+ def+ { metadata = HashMap.union (transposeToMetadata def) (metadata def) } @@ -89,7 +92,8 @@ Filter out the definitions that have the given `localPath`. -} exclude :: FilePath -> Dictionary -> Dictionary-exclude path = filter (\def -> (localPath def) /= path)+exclude path =+ filter (\def -> (localPath def) /= path) @@ -98,11 +102,13 @@ Merge the current hash map with another one. -} insertMetadata :: Metadata -> Dictionary -> Dictionary-insertMetadata a = fmap (insertMetadataDef a)+insertMetadata a =+ fmap (insertMetadataDef a) insertMetadataDef :: Metadata -> Definition -> Definition-insertMetadataDef given def = def { metadata = HashMap.union given (metadata def) }+insertMetadataDef given def =+ def { metadata = HashMap.union given (metadata def) } @@ -115,26 +121,24 @@ > permalink "index" dictionary -} permalink :: String -> Dictionary -> Dictionary-permalink a = fmap (permalinkDef a)+permalink a =+ fmap (permalinkDef a) permalinkDef :: String -> Definition -> Definition permalinkDef newBasename def =- if (basename def) /= newBasename- then- let- newDirname = cleanPath $ combine (dirname def) (basename def)- in- def {- basename = newBasename- , dirname = newDirname-- , parentPath = compileParentPath $ newDirname- , pathToRoot = compilePathToRoot $ newDirname- }-+ if (basename def) /= newBasename then+ let+ newDirname = cleanPath $ combine (dirname def) (basename def)+ in+ def+ { basename = newBasename+ , dirname = newDirname+ , parentPath = compileParentPath $ newDirname+ , pathToRoot = compilePathToRoot $ newDirname+ } else- def+ def @@ -148,15 +152,14 @@ prefixDirnameDef :: String -> Definition -> Definition prefixDirnameDef prefix def =- let- newDirname = prefix ++ (dirname def)- in- def {- dirname = newDirname-- , parentPath = compileParentPath $ newDirname- , pathToRoot = compilePathToRoot $ newDirname- }+ let+ newDirname = prefix ++ (dirname def)+ in+ def+ { dirname = newDirname+ , parentPath = compileParentPath $ newDirname+ , pathToRoot = compilePathToRoot $ newDirname+ } @@ -190,14 +193,15 @@ > -- now have the extname ".html" -} renameExt :: String -> String -> Dictionary -> Dictionary-renameExt a b = fmap (renameExtDef a b)+renameExt a b =+ fmap (renameExtDef a b) renameExtDef :: String -> String -> Definition -> Definition renameExtDef oldExtname newExtname def =- if (extname def) == oldExtname- then def { extname = newExtname }- else def+ if (extname def) == oldExtname+ then def { extname = newExtname }+ else def @@ -209,11 +213,13 @@ You can use this to render templates, markdown, etc. -} renderContent :: (Definition -> Maybe ByteString) -> Dictionary -> Dictionary-renderContent a = fmap (renderContentDef a)+renderContent a =+ fmap (renderContentDef a) renderContentDef :: (Definition -> Maybe ByteString) -> Definition -> Definition-renderContentDef renderer def = def { content = renderer def }+renderContentDef renderer def =+ def { content = renderer def } @@ -222,8 +228,10 @@ Replace the current hash map with another one. -} replaceMetadata :: Metadata -> Dictionary -> Dictionary-replaceMetadata a = fmap (replaceMetadataDef a)+replaceMetadata a =+ fmap (replaceMetadataDef a) replaceMetadataDef :: Metadata -> Definition -> Definition-replaceMetadataDef given def = def { metadata = given }+replaceMetadataDef given def =+ def { metadata = given }
src/Shikensu/Contrib/IO.hs view
@@ -2,11 +2,11 @@ -} module Shikensu.Contrib.IO- ( Shikensu.Contrib.IO.read- , Shikensu.Contrib.IO.readDef- , Shikensu.Contrib.IO.write- , Shikensu.Contrib.IO.writeDef- ) where+ ( Shikensu.Contrib.IO.read+ , Shikensu.Contrib.IO.readDef+ , Shikensu.Contrib.IO.write+ , Shikensu.Contrib.IO.writeDef+ ) where import Data.Maybe (fromMaybe) import Flow@@ -24,22 +24,23 @@ put that content in the `content` property. -} read :: Dictionary -> IO Dictionary-read = Utilities.mapIO (readDef)+read =+ Utilities.mapIO (readDef) readDef :: Definition -> IO Definition readDef def =- let- absPath = absolutePath def- in- doesFileExist absPath >>= \exists ->- if exists then- fmap- (\c -> def { content = Just c })- (B.readFile absPath)- else- return- def { content = Nothing }+ let+ absPath = absolutePath def+ in+ doesFileExist absPath >>= \exists ->+ if exists then+ fmap+ (\c -> def { content = Just c })+ (B.readFile absPath)+ else+ return+ def { content = Nothing } @@ -49,15 +50,16 @@ The path of the new file is `joinPath [rootDirname, givenDirectoryName, localPath]`. -} write :: FilePath -> Dictionary -> IO Dictionary-write dest = Utilities.mapIO (writeDef dest)+write dest =+ Utilities.mapIO (writeDef dest) writeDef :: FilePath -> Definition -> IO Definition writeDef dest def =- let- path = joinPath [rootDirname def, dest, localPath def]- cont = fromMaybe B.empty (content def)- in- createDirectoryIfMissing True (takeDirectory path)- >> B.writeFile path cont- >> return def+ let+ path = joinPath [rootDirname def, dest, localPath def]+ cont = fromMaybe B.empty (content def)+ in+ createDirectoryIfMissing True (takeDirectory path)+ >> B.writeFile path cont+ >> return def
+ src/Shikensu/Internal/Utilities.hs view
@@ -0,0 +1,113 @@+{-| Internal utility functions.++-}+module Shikensu.Internal.Utilities+ ( cleanPath+ , commonDirectory+ , compilePatterns+ , compileParentPath+ , compilePathToRoot+ , globDir+ , replaceSingleDot+ , stripPrefix+ , takeDirName+ ) where++import Data.Maybe (fromMaybe)+import Flow+import Shikensu.Types (Pattern)+import System.FilePath++import qualified Data.List as List (map, stripPrefix)+import qualified System.FilePath.Glob as Glob+++{-| "Clean up" a path.++> `/directory/./nested/` -> `directory/nested`+> `./` -> ``+> `.` -> ``++-}+cleanPath :: FilePath -> FilePath+cleanPath =+ normalise .> dropTrailingPathSeparator .> dropDrive .> replaceSingleDot+++{-| Get the common directory from a Pattern.+-}+commonDirectory :: Pattern -> FilePath+commonDirectory pattern =+ (Glob.compile .> Glob.commonDirectory .> fst) pattern+++{-| Compile a list of `Pattern`s to `Glob.Pattern`s.+-}+compilePatterns :: [Pattern] -> [Glob.Pattern]+compilePatterns =+ List.map Glob.compile+++{-| Path to parent, when there is one.++> Just "../" or Nothing++-}+compileParentPath :: FilePath -> Maybe FilePath+compileParentPath dirname =+ case dirname of+ "" -> Nothing+ _ -> Just "../"+++{-| Path to root.++Example, if `dirname` is 'example/subdir',+then this will be `../../`.++If the `dirname` is empty,+then this will be empty as well.++-}+compilePathToRoot :: FilePath -> FilePath+compilePathToRoot dirname =+ if dirname == "" then+ ""+ else+ dirname+ |> splitDirectories+ |> fmap (\_ -> "..")+ |> joinPath+ |> addTrailingPathSeparator+++{-| List contents of a directory using a glob pattern.+Returns a relative path, based on the given rootDirname.+-}+globDir :: FilePath -> [Glob.Pattern] -> IO [[FilePath]]+globDir rootDir patterns =+ Glob.globDir patterns rootDir+ |> fmap (fst)+ |> fmap (List.map . List.map . makeRelative $ rootDir)+++{-| If the path is a single dot, return an empty string.+Otherwise return the path.+-}+replaceSingleDot :: String -> String+replaceSingleDot path =+ if path == "." then "" else path+++{-| Strip prefix.+-}+stripPrefix :: String -> String -> String+stripPrefix prefix target =+ fromMaybe target (List.stripPrefix prefix target)+++{-| Take dirname and replace single dot.+-}+takeDirName :: FilePath -> FilePath+takeDirName =+ replaceSingleDot . takeDirectory
src/Shikensu/Metadata.hs view
@@ -2,9 +2,9 @@ -} module Shikensu.Metadata- ( transposeMetadata- , transposeToMetadata- ) where+ ( transposeMetadata+ , transposeToMetadata+ ) where import Flow import Shikensu.Types@@ -20,35 +20,35 @@ which implements the Aeson.FromJSON instance. > data Example =-> Example { some :: Text }-> deriving (Generic, FromJSON)+> Example { some :: Text }+> deriving (Generic, FromJSON) > > hashMap = HashMap.fromList [ ("some", "metadata") ] > defaultEx = Example { some = "default" }-> example = transposeMetadata hashMap defaultExample :: Example+> example = transposeMetadata hashMap defaultEx :: Example -} transposeMetadata :: Aeson.FromJSON a => Metadata -> a -> a transposeMetadata hashMap fallback =- let- result = hashMap- |> Aeson.toJSON- |> Aeson.fromJSON :: Aeson.FromJSON b => Aeson.Result b- in- case result of- Aeson.Success x -> x- Aeson.Error _ -> fallback+ let+ result = hashMap+ |> Aeson.toJSON+ |> Aeson.fromJSON :: Aeson.FromJSON b => Aeson.Result b+ in+ case result of+ Aeson.Success x -> x+ Aeson.Error _ -> fallback {-| Inverse of `transposeMetadata`. -} transposeToMetadata :: (Aeson.ToJSON a) => a -> Metadata transposeToMetadata generic =- let- result = generic- |> Aeson.toJSON- |> Aeson.fromJSON :: Aeson.FromJSON b => Aeson.Result b- in- case result of- Aeson.Success x -> x- Aeson.Error _ -> HashMap.empty+ let+ result = generic+ |> Aeson.toJSON+ |> Aeson.fromJSON :: Aeson.FromJSON b => Aeson.Result b+ in+ case result of+ Aeson.Success x -> x+ Aeson.Error _ -> HashMap.empty
src/Shikensu/Sorting.hs view
@@ -2,8 +2,8 @@ -} module Shikensu.Sorting- ( sortByAbsolutePath- ) where+ ( sortByAbsolutePath+ ) where import Shikensu.Types (Definition, absolutePath) @@ -15,4 +15,4 @@ -} sortByAbsolutePath :: Definition -> Definition -> Ordering sortByAbsolutePath defA defB =- compare (absolutePath defA) (absolutePath defB)+ compare (absolutePath defA) (absolutePath defB)
src/Shikensu/Types.hs view
@@ -11,33 +11,33 @@ {-| A file definition, along with some additional properties. -} data Definition =- Definition- { basename :: String- , dirname :: FilePath- , extname :: String- , pattern :: Pattern- , rootDirname :: FilePath- , workingDirname :: FilePath+ Definition+ { basename :: String+ , dirname :: FilePath+ , extname :: String+ , pattern :: Pattern+ , rootDirname :: FilePath+ , workingDirname :: FilePath - -- Additional properties- , content :: Maybe ByteString- , metadata :: Metadata- , parentPath :: Maybe FilePath- , pathToRoot :: FilePath- } deriving (Eq, Show)+ -- Additional properties+ , content :: Maybe ByteString+ , metadata :: Metadata+ , parentPath :: Maybe FilePath+ , pathToRoot :: FilePath+ } deriving (Eq, Show) instance ToJSON Definition where- toJSON def =- object- [ "basename" .= basename def- , "dirname" .= dirname def- , "extname" .= extname def- , "pattern" .= pattern def- , "workingDirname" .= workingDirname def- , "parentPath" .= parentPath def- , "pathToRoot" .= pathToRoot def- ]+ toJSON def =+ object+ [ "basename" .= basename def+ , "dirname" .= dirname def+ , "extname" .= extname def+ , "pattern" .= pattern def+ , "workingDirname" .= workingDirname def+ , "parentPath" .= parentPath def+ , "pathToRoot" .= pathToRoot def+ ] @@ -57,14 +57,14 @@ absolutePath :: Definition -> String absolutePath def =- joinPath [rootDirname def, workspacePath def]+ joinPath [rootDirname def, workspacePath def] localPath :: Definition -> String localPath def =- joinPath [dirname def, (basename def) ++ (extname def)]+ joinPath [dirname def, (basename def) ++ (extname def)] workspacePath :: Definition -> String workspacePath def =- joinPath [workingDirname def, localPath def]+ joinPath [workingDirname def, localPath def]
src/Shikensu/Utilities.hs view
@@ -1,120 +1,104 @@-{-| Utilities, mainly for internal use.---} module Shikensu.Utilities- ( cleanPath- , commonDirectory- , compilePatterns- , compileParentPath- , compilePathToRoot- , globDir- , io- , mapIO- , replaceSingleDot- , stripPrefix- , takeDirName- ) where+ ( io+ , mapIO+ , lsequence -import Data.Maybe (fromMaybe)-import Data.Tuple (fst)+ , (⚡)+ , (⚡⚡)+ ) where++import Data.Aeson (FromJSON, ToJSON, fromJSON)+import Data.Text (Text) import Flow import Shikensu.Types-import System.FilePath -import qualified Data.List as List (map, stripPrefix)-import qualified System.FilePath.Glob as Glob+import qualified Data.Aeson as Json (Object, Result(..), encode)+import qualified Data.HashMap.Strict as HashMap (lookup)+import qualified Data.List as List (unzip, zip)+import qualified Data.Tuple as Tuple (fst, snd)+import qualified Data.Text as Text (concat, unpack)+import qualified Data.Text.Lazy as Lazy.Text (unpack)+import qualified Data.Text.Lazy.Encoding as Lazy.Text (decodeUtf8) -{-| "Clean up" a path.--> `/directory/./nested/` -> `directory/nested`-> `./` -> ``-> `.` -> ``---}-cleanPath :: FilePath -> FilePath-cleanPath = normalise .> dropTrailingPathSeparator .> dropDrive .> replaceSingleDot+-- IO -{-| Get the common directory from a Pattern.+{-| IO Sequence helpers -}-commonDirectory :: Pattern -> FilePath-commonDirectory pattern = (Glob.compile .> Glob.commonDirectory .> fst) pattern+io :: ([Definition] -> [IO Definition]) -> Dictionary -> IO Dictionary+io fn =+ fn .> sequence -{-| Compile a list of `Pattern`s to `Glob.Pattern`s.--}-compilePatterns :: [Pattern] -> [Glob.Pattern]-compilePatterns = List.map Glob.compile+mapIO :: (Definition -> IO Definition) -> Dictionary -> IO Dictionary+mapIO =+ fmap .> io -{-| Path to parent, when there is one.+{-| One way to deal with multiple dictionaries. -> Just "../" or Nothing+> lsequence+> [ ( "pages", Shikensu.list rootDir ["src/pages/**/*.html"] )+> , ( "js", Shikensu.list rootDir ["src/javascript/**/*.js"] )+> ] +From multiple IO monads to a single IO monad. -}-compileParentPath :: FilePath -> Maybe FilePath-compileParentPath dirname =- case dirname of- "" -> Nothing- _ -> Just "../"+lsequence :: Monad m => [( String, m a )] -> m [( String, a )]+lsequence list =+ let+ unzippedList =+ List.unzip list + identifiers =+ Tuple.fst unzippedList -{-| Path to root.+ dictionaries =+ Tuple.snd unzippedList+ in+ dictionaries+ |> sequence+ |> fmap (List.zip identifiers) -Example, if `dirname` is 'example/subdir',-then this will be `../../`. -If the `dirname` is empty,-then this will be empty as well. --}-compilePathToRoot :: FilePath -> FilePath-compilePathToRoot dirname =- if dirname == "" then- ""- else- dirname- |> splitDirectories- |> fmap (\_ -> "..")- |> joinPath- |> addTrailingPathSeparator+-- PURE -{-| List contents of a directory using a glob pattern.-Returns a relative path, based on the given rootDirname.+{-| Get stuff out of the metadata.+ Return a `Maybe`. -}-globDir :: FilePath -> [Glob.Pattern] -> IO [[FilePath]]-globDir rootDir patterns =- Glob.globDir patterns rootDir- |> fmap (fst)- |> fmap (List.map . List.map . makeRelative $ rootDir)+(⚡) :: (FromJSON a, ToJSON a) => Metadata -> Text -> Maybe a+(⚡) obj key =+ HashMap.lookup key obj+ |> fmap fromJSON+ |> fmap fromJSONResult -{-| IO Sequence helpers+{-| Get stuff out of the metadata.+ Does NOT return a `Maybe`, but gives an error if it isn't found. -}-io :: ([Definition] -> [IO Definition]) -> Dictionary -> IO Dictionary-io fn = sequence . fn+(⚡⚡) :: (FromJSON a, ToJSON a) => Metadata -> Text -> a+(⚡⚡) obj key =+ case (obj ⚡ key) of+ Just x -> x+ Nothing -> error <|+ "Could not find the key `" ++ (Text.unpack key) ++ "` " +++ "on the metadata object `" ++ (aesonObjectToString obj) ++ "` using (⚡⚡)" -mapIO :: (Definition -> IO Definition) -> Dictionary -> IO Dictionary-mapIO = io . fmap --{-| If the path is a single dot, return an empty string.-Otherwise return the path.--}-replaceSingleDot :: String -> String-replaceSingleDot path = if path == "." then "" else path+-- Private -{-| Strip prefix.--}-stripPrefix :: String -> String -> String-stripPrefix prefix target = fromMaybe target (List.stripPrefix prefix target)+fromJSONResult :: ToJSON a => Json.Result a -> a+fromJSONResult result =+ case result of+ Json.Success x -> x+ Json.Error err -> error err -{-| Take dirname.--}-takeDirName :: FilePath -> FilePath-takeDirName = replaceSingleDot . takeDirectory+aesonObjectToString :: Json.Object -> String+aesonObjectToString =+ Json.encode .> Lazy.Text.decodeUtf8 .> Lazy.Text.unpack
tests/Test.hs view
@@ -6,16 +6,18 @@ import Test.Helpers (ioErrorHandler, rootPath) import Test.Shikensu import Test.Tasty+import Test.Utilities main :: IO () main =- rootPath- >>= \r -> catch- (removeDirectoryRecursive (combine r "tests/build"))- (ioErrorHandler)- >> defaultMain tests+ rootPath+ >>= \r -> catch+ (removeDirectoryRecursive (combine r "tests/build"))+ (ioErrorHandler)+ >> defaultMain tests tests :: TestTree-tests = testGroup "Tests" [shikensuTests, contribTests, exampleTests]+tests =+ testGroup "Tests" [shikensuTests, contribTests, exampleTests, utilityTests]
tests/Test/Contrib.hs view
@@ -23,18 +23,18 @@ contribTests :: TestTree contribTests = testGroup- "Contrib tests"- [ testClone- , testExclude- , testMetadata- , testPermalink- , testPrefixDirname- , testRead- , testRename- , testRenameExt- , testRenderContent- , testWrite- ]+ "Contrib tests"+ [ testClone+ , testExclude+ , testMetadata+ , testPermalink+ , testPrefixDirname+ , testRead+ , testRename+ , testRenameExt+ , testRenderContent+ , testWrite+ ] @@ -43,22 +43,24 @@ list :: Shikensu.Pattern -> IO Shikensu.Dictionary-list pattern = rootPath >>= Shikensu.list [pattern]+list pattern =+ rootPath >>= Shikensu.listF [pattern] example_md :: IO Shikensu.Dictionary-example_md = list "tests/fixtures/example.md"+example_md =+ list "tests/fixtures/example.md" renderer :: Shikensu.Definition -> Maybe ByteString renderer def =- let- openingTag = BS.pack "<html>"- closingTag = BS.pack "</html>"- in- def- |> Shikensu.content- |> fmap (\c -> BS.intercalate B.empty [openingTag, c, closingTag])+ let+ openingTag = BS.pack "<html>"+ closingTag = BS.pack "</html>"+ in+ def+ |> Shikensu.content+ |> fmap (\c -> BS.intercalate B.empty [openingTag, c, closingTag]) @@ -68,175 +70,175 @@ testClone :: TestTree testClone =- let- dictionary = fmap (Contrib.clone "example.md" "cloned.md") example_md- definition = fmap (List.head . List.reverse) dictionary- in- testCase "Should `clone`"- $ definition `rmap` Shikensu.localPath >>= assertEq "cloned.md"+ let+ dictionary = fmap (Contrib.clone "example.md" "cloned.md") example_md+ definition = fmap (List.head . List.reverse) dictionary+ in+ testCase "Should `clone`"+ $ definition `rmap` Shikensu.localPath >>= assertEq "cloned.md" testExclude :: TestTree testExclude =- let- dictionary = fmap (Contrib.exclude "example.md") example_md- length_ = fmap length dictionary- in- testCase "Should `exclude`"- $ length_ >>= assertEq 0+ let+ dictionary = fmap (Contrib.exclude "example.md") example_md+ length_ = fmap length dictionary+ in+ testCase "Should `exclude`"+ $ length_ >>= assertEq 0 testMetadata :: TestTree testMetadata =- let- keyA = Text.pack "title"- valueA = Aeson.String (Text.pack "Hello world!")+ let+ keyA = Text.pack "title"+ valueA = Aeson.String (Text.pack "Hello world!") - keyB = Text.pack "hello"- valueB = Aeson.String (Text.pack "Guardian.")+ keyB = Text.pack "hello"+ valueB = Aeson.String (Text.pack "Guardian.") - keyC = Text.pack "removed"- valueC = Aeson.String (Text.pack "Me.")+ keyC = Text.pack "removed"+ valueC = Aeson.String (Text.pack "Me.") - keyBase = Text.pack "basename"- valueBase = Aeson.String (Text.pack "example")+ keyBase = Text.pack "basename"+ valueBase = Aeson.String (Text.pack "example") - -- 1. Insert C- -- 2. Replace with A- -- 3. Insert B- dictionary = example_md- <&> ( Contrib.insertMetadata (HashMap.fromList [ (keyC, valueC) ])- .> Contrib.replaceMetadata (HashMap.fromList [ (keyA, valueA) ])- .> Contrib.copyPropsToMetadata- .> Contrib.insertMetadata (HashMap.fromList [ (keyB, valueB) ])- )+ -- 1. Insert C+ -- 2. Replace with A+ -- 3. Insert B+ dictionary = example_md+ <&> ( Contrib.insertMetadata (HashMap.fromList [ (keyC, valueC) ])+ .> Contrib.replaceMetadata (HashMap.fromList [ (keyA, valueA) ])+ .> Contrib.copyPropsToMetadata+ .> Contrib.insertMetadata (HashMap.fromList [ (keyB, valueB) ])+ ) - definition = fmap (List.head . List.reverse) dictionary+ definition = fmap (List.head . List.reverse) dictionary - lookupTitle = \def -> HashMap.lookup keyA (Shikensu.metadata def)- lookupHello = \def -> HashMap.lookup keyB (Shikensu.metadata def)- lookupRemoved = \def -> HashMap.lookup keyC (Shikensu.metadata def)- lookupBasename = \def -> HashMap.lookup keyBase (Shikensu.metadata def)- in- testGroup- "Metadata"- [ testCase "Should no longer have `removed` key"- $ definition `rmap` lookupRemoved >>= assertEq Nothing+ lookupTitle = \def -> HashMap.lookup keyA (Shikensu.metadata def)+ lookupHello = \def -> HashMap.lookup keyB (Shikensu.metadata def)+ lookupRemoved = \def -> HashMap.lookup keyC (Shikensu.metadata def)+ lookupBasename = \def -> HashMap.lookup keyBase (Shikensu.metadata def)+ in+ testGroup+ "Metadata"+ [ testCase "Should no longer have `removed` key"+ $ definition `rmap` lookupRemoved >>= assertEq Nothing - , testCase "Should have `hello` key"- $ definition `rmap` lookupHello >>= assertEq (Just valueB)+ , testCase "Should have `hello` key"+ $ definition `rmap` lookupHello >>= assertEq (Just valueB) - , testCase "Should have `title` key"- $ definition `rmap` lookupTitle >>= assertEq (Just valueA)+ , testCase "Should have `title` key"+ $ definition `rmap` lookupTitle >>= assertEq (Just valueA) - , testCase "Should have `basename` key"- $ definition `rmap` lookupBasename >>= assertEq (Just valueBase)- ]+ , testCase "Should have `basename` key"+ $ definition `rmap` lookupBasename >>= assertEq (Just valueBase)+ ] testPermalink :: TestTree testPermalink =- let- dictionary = fmap (Contrib.permalink "index") example_md- definition = fmap (List.head) dictionary- in- testGroup- "Permalink"- [ testCase "Should have the correct `localPath`"- $ definition `rmap` Shikensu.localPath >>= assertEq "example/index.md"+ let+ dictionary = fmap (Contrib.permalink "index") example_md+ definition = fmap (List.head) dictionary+ in+ testGroup+ "Permalink"+ [ testCase "Should have the correct `localPath`"+ $ definition `rmap` Shikensu.localPath >>= assertEq "example/index.md" - , testCase "Should have the correct `parentPath`"- $ definition `rmap` Shikensu.parentPath >>= assertEq (Just "../")+ , testCase "Should have the correct `parentPath`"+ $ definition `rmap` Shikensu.parentPath >>= assertEq (Just "../") - , testCase "Should have the correct `pathToRoot`"- $ definition `rmap` Shikensu.pathToRoot >>= assertEq "../"- ]+ , testCase "Should have the correct `pathToRoot`"+ $ definition `rmap` Shikensu.pathToRoot >>= assertEq "../"+ ] testPrefixDirname :: TestTree testPrefixDirname =- let- dictionary = fmap (Contrib.prefixDirname "prefix/") (list "tests/**/example.md")- definition = fmap List.head dictionary- in- testGroup- "PrefixDirname"- [ testCase "Should have the correct `dirname`"- $ definition `rmap` Shikensu.dirname >>= assertEq "prefix/fixtures"+ let+ dictionary = fmap (Contrib.prefixDirname "prefix/") (list "tests/**/example.md")+ definition = fmap List.head dictionary+ in+ testGroup+ "PrefixDirname"+ [ testCase "Should have the correct `dirname`"+ $ definition `rmap` Shikensu.dirname >>= assertEq "prefix/fixtures" - , testCase "Should have the correct `pathToRoot`"- $ definition `rmap` Shikensu.pathToRoot >>= assertEq "../../"+ , testCase "Should have the correct `pathToRoot`"+ $ definition `rmap` Shikensu.pathToRoot >>= assertEq "../../" - , testCase "Should have the correct `parentPath`"- $ definition `rmap` Shikensu.parentPath >>= assertEq (Just "../")- ]+ , testCase "Should have the correct `parentPath`"+ $ definition `rmap` Shikensu.parentPath >>= assertEq (Just "../")+ ] testRead :: TestTree testRead =- let- dictionary = example_md >>= Contrib.IO.read- definition = fmap List.head dictionary- in- testCase "Should `read`"- $ definition- <&> Shikensu.content- <&> fmap Text.decodeUtf8- >>= assertEq (Just (Text.pack "# Example\n"))+ let+ dictionary = example_md >>= Contrib.IO.read+ definition = fmap List.head dictionary+ in+ testCase "Should `read`"+ $ definition+ <&> Shikensu.content+ <&> fmap Text.decodeUtf8+ >>= assertEq (Just (Text.pack "# Example\n")) testRename :: TestTree testRename =- let- dictionary = fmap (Contrib.rename "example.md" "renamed.md") example_md- definition = fmap (List.head) dictionary- in- testCase "Should `rename`"- $ definition `rmap` Shikensu.localPath >>= assertEq "renamed.md"+ let+ dictionary = fmap (Contrib.rename "example.md" "renamed.md") example_md+ definition = fmap (List.head) dictionary+ in+ testCase "Should `rename`"+ $ definition `rmap` Shikensu.localPath >>= assertEq "renamed.md" testRenameExt :: TestTree testRenameExt =- let- dictionary = fmap (Contrib.renameExt ".md" ".html") example_md- definition = fmap (List.head) dictionary- in- testCase "Should `renameExt`"- $ definition `rmap` Shikensu.extname >>= assertEq ".html"+ let+ dictionary = fmap (Contrib.renameExt ".md" ".html") example_md+ definition = fmap (List.head) dictionary+ in+ testCase "Should `renameExt`"+ $ definition `rmap` Shikensu.extname >>= assertEq ".html" testRenderContent :: TestTree testRenderContent =- let- dictionary = fmap (Contrib.renderContent renderer) (example_md >>= Contrib.IO.read)- definition = fmap (List.head) dictionary- expectedResult = Just (Text.pack "<html># Example\n</html>")- in- testCase "Should `renderContent`"- $ definition- <&> Shikensu.content- <&> fmap Text.decodeUtf8- >>= assertEq expectedResult+ let+ dictionary = fmap (Contrib.renderContent renderer) (example_md >>= Contrib.IO.read)+ definition = fmap (List.head) dictionary+ expectedResult = Just (Text.pack "<html># Example\n</html>")+ in+ testCase "Should `renderContent`"+ $ definition+ <&> Shikensu.content+ <&> fmap Text.decodeUtf8+ >>= assertEq expectedResult testWrite :: TestTree testWrite =- let- destination = "tests/build/"- dictionary = list "tests/**/example.md" >>= Contrib.IO.read >>= Contrib.IO.write destination- definition = fmap List.head dictionary- in- testCase "Should `write`"- $ definition- <&> Shikensu.rootDirname- >>= \r -> Text.readFile (joinPath [r, destination, "fixtures/example.md"])- >>= \c -> assertEq "# Example\n" (Text.unpack c)+ let+ destination = "tests/build/"+ dictionary = list "tests/**/example.md" >>= Contrib.IO.read >>= Contrib.IO.write destination+ definition = fmap List.head dictionary+ in+ testCase "Should `write`"+ $ definition+ <&> Shikensu.rootDirname+ >>= \r -> Text.readFile (joinPath [r, destination, "fixtures/example.md"])+ >>= \c -> assertEq "# Example\n" (Text.unpack c)
tests/Test/Example.hs view
@@ -19,15 +19,15 @@ exampleTests :: TestTree exampleTests =- let- path = canonicalizePath "./tests"- dict = path >>= dictionary_io- test = path >>= \p ->- read [Shikensu.makeDefinition p "fixtures/*.md" "fixtures/example.md"]- >>= flow- in- testCase "Example test"- $ dict >>= \d -> test >>= assertEq d+ let+ path = canonicalizePath "./tests"+ dict = path >>= dictionary_io+ test = path >>= \p ->+ read [Shikensu.makeDefinition p "fixtures/*.md" "fixtures/example.md"]+ >>= flow+ in+ testCase "Example test"+ $ dict >>= \d -> test >>= assertEq d @@ -36,29 +36,30 @@ dictionary_io :: String -> IO Dictionary dictionary_io absolutePathToCwd =- Shikensu.list ["fixtures/*.md"] absolutePathToCwd- >>= read- >>= flow- >>= write "./build"+ Shikensu.list absolutePathToCwd ["fixtures/*.md"]+ >>= read+ >>= flow+ >>= write "./build" flow :: Dictionary -> IO Dictionary flow =- renameExt ".md" ".html"- .> permalink "index"- .> clone "index.html" "200.html"- .> copyPropsToMetadata- .> renderContent markdownRenderer- .> return+ renameExt ".md" ".html"+ .> permalink "index"+ .> clone "index.html" "200.html"+ .> copyPropsToMetadata+ .> renderContent markdownRenderer+ .> return markdownRenderer :: Definition -> Maybe ByteString markdownRenderer def =- content def- |> fmap Text.decodeUtf8- |> fmap renderMarkdown- |> fmap Text.encodeUtf8+ content def+ |> fmap Text.decodeUtf8+ |> fmap renderMarkdown+ |> fmap Text.encodeUtf8 renderMarkdown :: Text -> Text-renderMarkdown text = text+renderMarkdown text =+ text
tests/Test/Helpers.hs view
@@ -1,12 +1,12 @@ module Test.Helpers- ( (<&>)- , rmap- , assertEq- , ioErrorHandler- , rootPath- , sort- , testsPath- ) where+ ( (<&>)+ , rmap+ , assertEq+ , ioErrorHandler+ , rootPath+ , sort+ , testsPath+ ) where import Shikensu.Sorting (sortByAbsolutePath) import Shikensu.Types (Dictionary)@@ -18,28 +18,35 @@ (<&>) :: Functor f => f a -> (a -> b) -> f b-(<&>) = flip fmap+(<&>) =+ flip fmap rmap :: Functor f => f a -> (a -> b) -> f b-rmap = (<&>)+rmap =+ (<&>) assertEq :: (Eq a, Show a) => a -> a -> Assertion-assertEq = assertEqual ""+assertEq =+ assertEqual "" ioErrorHandler :: IOError -> IO ()-ioErrorHandler _ = putStrLn ""+ioErrorHandler _ =+ putStrLn "" rootPath :: IO FilePath-rootPath = canonicalizePath "./"+rootPath =+ canonicalizePath "./" sort :: Dictionary -> Dictionary-sort = List.sortBy sortByAbsolutePath+sort =+ List.sortBy sortByAbsolutePath testsPath :: IO FilePath-testsPath = fmap ((flip combine) "tests") rootPath+testsPath =+ fmap ((flip combine) "tests") rootPath
tests/Test/Shikensu.hs view
@@ -11,8 +11,8 @@ shikensuTests :: TestTree shikensuTests = testGroup- "Shikensu tests"- [testRegular, testDot, testWithoutWd, testRootFile]+ "Shikensu tests"+ [testRegular, testDot, testWithoutWd, testRootFile] @@ -22,119 +22,119 @@ testRegular :: TestTree testRegular =- let- pattern = "tests/**/*.md"- dictionary = fmap sort $ rootPath >>= Shikensu.list [pattern]- definition = fmap List.head dictionary- localPath = "fixtures/example.md"- in- testGroup "Test regular"- [ testCase "Should have the correct basename"- $ definition `rmap` Shikensu.basename >>= assertEq "example"+ let+ pattern = "tests/**/*.md"+ dictionary = fmap sort $ rootPath >>= Shikensu.listF [pattern]+ definition = fmap List.head dictionary+ localPath = "fixtures/example.md"+ in+ testGroup "Test regular"+ [ testCase "Should have the correct basename"+ $ definition `rmap` Shikensu.basename >>= assertEq "example" - , testCase "Should have the correct dirname"- $ definition `rmap` Shikensu.dirname >>= assertEq "fixtures"+ , testCase "Should have the correct dirname"+ $ definition `rmap` Shikensu.dirname >>= assertEq "fixtures" - , testCase "Should have the correct extname"- $ definition `rmap` Shikensu.extname >>= assertEq ".md"+ , testCase "Should have the correct extname"+ $ definition `rmap` Shikensu.extname >>= assertEq ".md" - , testCase "Should have the correct localPath"- $ definition `rmap` Shikensu.localPath >>= assertEq localPath+ , testCase "Should have the correct localPath"+ $ definition `rmap` Shikensu.localPath >>= assertEq localPath - , testCase "Should have the correct pattern"- $ definition `rmap` Shikensu.pattern >>= assertEq pattern+ , testCase "Should have the correct pattern"+ $ definition `rmap` Shikensu.pattern >>= assertEq pattern - , testCase "Should have the correct workingDirname"- $ definition `rmap` Shikensu.workingDirname >>= assertEq "tests"+ , testCase "Should have the correct workingDirname"+ $ definition `rmap` Shikensu.workingDirname >>= assertEq "tests" - ]+ ] testDot :: TestTree testDot =- let- pattern = "./tests/**/*.md"- dictionary = fmap sort $ rootPath >>= Shikensu.list [pattern]- definition = fmap List.head dictionary- localPath = "fixtures/example.md"- in- testGroup "Test dot"- [ testCase "Should have the correct basename"- $ definition `rmap` Shikensu.basename >>= assertEq "example"+ let+ pattern = "./tests/**/*.md"+ dictionary = fmap sort $ rootPath >>= Shikensu.listF [pattern]+ definition = fmap List.head dictionary+ localPath = "fixtures/example.md"+ in+ testGroup "Test dot"+ [ testCase "Should have the correct basename"+ $ definition `rmap` Shikensu.basename >>= assertEq "example" - , testCase "Should have the correct dirname"- $ definition `rmap` Shikensu.dirname >>= assertEq "fixtures"+ , testCase "Should have the correct dirname"+ $ definition `rmap` Shikensu.dirname >>= assertEq "fixtures" - , testCase "Should have the correct extname"- $ definition `rmap` Shikensu.extname >>= assertEq ".md"+ , testCase "Should have the correct extname"+ $ definition `rmap` Shikensu.extname >>= assertEq ".md" - , testCase "Should have the correct localPath"- $ definition `rmap` Shikensu.localPath >>= assertEq localPath+ , testCase "Should have the correct localPath"+ $ definition `rmap` Shikensu.localPath >>= assertEq localPath - , testCase "Should have the correct pattern"- $ definition `rmap` Shikensu.pattern >>= assertEq pattern+ , testCase "Should have the correct pattern"+ $ definition `rmap` Shikensu.pattern >>= assertEq pattern - , testCase "Should have the correct workingDirname"- $ definition `rmap` Shikensu.workingDirname >>= assertEq "tests"+ , testCase "Should have the correct workingDirname"+ $ definition `rmap` Shikensu.workingDirname >>= assertEq "tests" - ]+ ] testWithoutWd :: TestTree testWithoutWd =- let- pattern = "**/*.md"- dictionary = fmap sort $ testsPath >>= Shikensu.list [pattern]- definition = fmap List.head dictionary- localPath = "fixtures/example.md"- in- testGroup "Test without workingDirname"- [ testCase "Should have the correct basename"- $ definition `rmap` Shikensu.basename >>= assertEq "example"+ let+ pattern = "**/*.md"+ dictionary = fmap sort $ testsPath >>= Shikensu.listF [pattern]+ definition = fmap List.head dictionary+ localPath = "fixtures/example.md"+ in+ testGroup "Test without workingDirname"+ [ testCase "Should have the correct basename"+ $ definition `rmap` Shikensu.basename >>= assertEq "example" - , testCase "Should have the correct dirname"- $ definition `rmap` Shikensu.dirname >>= assertEq "fixtures"+ , testCase "Should have the correct dirname"+ $ definition `rmap` Shikensu.dirname >>= assertEq "fixtures" - , testCase "Should have the correct extname"- $ definition `rmap` Shikensu.extname >>= assertEq ".md"+ , testCase "Should have the correct extname"+ $ definition `rmap` Shikensu.extname >>= assertEq ".md" - , testCase "Should have the correct localPath"- $ definition `rmap` Shikensu.localPath >>= assertEq localPath+ , testCase "Should have the correct localPath"+ $ definition `rmap` Shikensu.localPath >>= assertEq localPath - , testCase "Should have the correct pattern"- $ definition `rmap` Shikensu.pattern >>= assertEq pattern+ , testCase "Should have the correct pattern"+ $ definition `rmap` Shikensu.pattern >>= assertEq pattern - , testCase "Should have the correct workingDirname"- $ definition `rmap` Shikensu.workingDirname >>= assertEq ""+ , testCase "Should have the correct workingDirname"+ $ definition `rmap` Shikensu.workingDirname >>= assertEq "" - ]+ ] testRootFile :: TestTree testRootFile =- let- pattern = "*.md"- dictionary = fmap sort $ rootPath >>= Shikensu.list [pattern]- definition = fmap List.head dictionary- localPath = "README.md"- in- testGroup "Test file in root path"- [ testCase "Should have the correct basename"- $ definition `rmap` Shikensu.basename >>= assertEq "README"+ let+ pattern = "*.md"+ dictionary = fmap sort $ rootPath >>= Shikensu.listF [pattern]+ definition = fmap List.head dictionary+ localPath = "CHANGELOG.md"+ in+ testGroup "Test file in root path"+ [ testCase "Should have the correct basename"+ $ definition `rmap` Shikensu.basename >>= assertEq "CHANGELOG" - , testCase "Should have the correct dirname"- $ definition `rmap` Shikensu.dirname >>= assertEq ""+ , testCase "Should have the correct dirname"+ $ definition `rmap` Shikensu.dirname >>= assertEq "" - , testCase "Should have the correct extname"- $ definition `rmap` Shikensu.extname >>= assertEq ".md"+ , testCase "Should have the correct extname"+ $ definition `rmap` Shikensu.extname >>= assertEq ".md" - , testCase "Should have the correct localPath"- $ definition `rmap` Shikensu.localPath >>= assertEq localPath+ , testCase "Should have the correct localPath"+ $ definition `rmap` Shikensu.localPath >>= assertEq localPath - , testCase "Should have the correct pattern"- $ definition `rmap` Shikensu.pattern >>= assertEq pattern+ , testCase "Should have the correct pattern"+ $ definition `rmap` Shikensu.pattern >>= assertEq pattern - , testCase "Should have the correct workingDirname"- $ definition `rmap` Shikensu.workingDirname >>= assertEq ""+ , testCase "Should have the correct workingDirname"+ $ definition `rmap` Shikensu.workingDirname >>= assertEq "" - ]+ ]
+ tests/Test/Utilities.hs view
@@ -0,0 +1,69 @@+module Test.Utilities (utilityTests) where++import Flow+import Shikensu.Types+import Shikensu.Utilities as Utils+import Test.Helpers+import Test.Tasty+import Test.Tasty.HUnit++import qualified Data.HashMap.Strict as HashMap (singleton)+import qualified Data.List as List (head)+import qualified Data.Tuple as Tuple (fst)+import qualified Shikensu+import qualified Shikensu.Contrib as Contrib+++utilityTests :: TestTree+utilityTests = testGroup+ "Utility tests"+ [testSequencing, testThunder]+++++-- Tests+++testSequencing :: TestTree+testSequencing =+ let+ result =+ Utils.lsequence+ [ ( "a", rootPath >>= Shikensu.listF ["tests/fixtures/example.md"] )+ , ( "b", rootPath >>= Shikensu.listF ["tests/fixtures/example.md"] )+ ]+ in+ testCase "Test lsequence"+ $ (List.head .> Tuple.fst) <$> result >>= assertEq "a"+++testThunder :: TestTree+testThunder =+ let+ flow =+ Contrib.insertMetadata (HashMap.singleton "a" "Hi!")+ .> return++ dictionary =+ rootPath+ >>= Shikensu.listF ["tests/fixtures/example.md"]+ >>= flow++ def =+ fmap List.head dictionary++ resultExisting =+ fmap (\d -> metadata d ⚡ "a" :: Maybe String) def++ resultNonExisting =+ fmap (\d -> metadata d ⚡ "b" :: Maybe String) def+ in+ testGroup+ "Test (⚡)"+ [ testCase "Existing"+ $ resultExisting >>= assertEq (Just "Hi!")++ , testCase "Non-existing"+ $ resultNonExisting >>= assertEq (Nothing)+ ]