shikensu 0.3.3 → 0.3.4
raw patch · 16 files changed
+370/−478 lines, 16 filesdep −shikensudep ~aesondep ~basedep ~bytestring
Dependencies removed: shikensu
Dependency ranges changed: aeson, base, bytestring, directory, filepath, flow, text, unordered-containers
Files
- shikensu.cabal +46/−89
- src/Shikensu.hs +37/−31
- src/Shikensu/Contrib.hs +27/−27
- src/Shikensu/Contrib/IO.hs +2/−3
- src/Shikensu/Internal/Types.hs +71/−0
- src/Shikensu/Internal/Utilities.hs +13/−40
- src/Shikensu/Metadata.hs +1/−2
- src/Shikensu/Sorting.hs +1/−1
- src/Shikensu/Types.hs +0/−70
- src/Shikensu/Utilities.hs +12/−11
- tests/Test.hs +15/−10
- tests/Test/Contrib.hs +50/−53
- tests/Test/Example.hs +25/−18
- tests/Test/Helpers.hs +20/−29
- tests/Test/Shikensu.hs +32/−69
- tests/Test/Utilities.hs +18/−25
shikensu.cabal view
@@ -1,98 +1,55 @@-name: shikensu-version: 0.3.3-category: File IO--synopsis:- A small toolset for building static websites--description:- Please see README.md--homepage:- https://github.com/icidasset/shikensu#README--license: MIT-license-file: LICENSE--author: Steven Vandevelde-maintainer: icid.asset@gmail.com--build-type: Simple-cabal-version: >= 1.10+-- This file has been generated from package.yaml by hpack version 0.17.0.+--+-- see: https://github.com/sol/hpack +name: shikensu+version: 0.3.4+synopsis: Run a sequence of functions on in-memory representations of files+description: See README at <https://github.com/icidasset/shikensu#readme>+category: Filesystem+homepage: https://github.com/icidasset/shikensu#readme+bug-reports: https://github.com/icidasset/shikensu/issues+maintainer: Steven Vandevelde <icid.asset@gmail.com>+license: MIT+license-file: LICENSE+build-type: Simple+cabal-version: >= 1.10 source-repository head type: git location: https://github.com/icidasset/shikensu --library- default-language:- Haskell2010-- default-extensions:- OverloadedStrings-+test-suite spec+ type: exitcode-stdio-1.0+ main-is: Test.hs hs-source-dirs:- src-- exposed-modules:- Shikensu,- Shikensu.Contrib,- Shikensu.Contrib.IO,- Shikensu.Internal.Utilities,- Shikensu.Metadata,- Shikensu.Sorting,- Shikensu.Types,- Shikensu.Utilities-+ tests+ src+ default-extensions: DisambiguateRecordFields DuplicateRecordFields OverloadedStrings build-depends:- aeson == 1.0.*,- base >= 4.8 && < 5,- bytestring == 0.10.*,- directory == 1.3.*,- filepath == 1.4.*,- flow == 1.0.*,- Glob == 0.7.*,- 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-- type:- exitcode-stdio-1.0-- hs-source-dirs:- tests-- main-is:- Test.hs-+ aeson == 1.0.*+ , base >= 4.9 && < 5+ , bytestring == 0.10.*+ , directory == 1.3.*+ , filepath == 1.4.*+ , flow == 1.0.*+ , Glob == 0.7.*+ , unordered-containers == 0.2.*+ , text == 1.2.*+ , tasty == 0.11.*+ , tasty-hunit == 0.9.* other-modules:- Test.Contrib,- Test.Example,- Test.Helpers,- Test.Shikensu,- Test.Utilities-- build-depends:- aeson,- base,- bytestring,- directory,- filepath,- flow,- shikensu,- tasty == 0.11.*,- tasty-hunit == 0.9.*,- text,- unordered-containers+ Test.Contrib+ Test.Example+ Test.Helpers+ Test.Shikensu+ Test.Utilities+ Shikensu+ Shikensu.Contrib+ Shikensu.Contrib.IO+ Shikensu.Internal.Types+ Shikensu.Internal.Utilities+ Shikensu.Metadata+ Shikensu.Sorting+ Shikensu.Utilities+ default-language: Haskell2010
src/Shikensu.hs view
@@ -4,25 +4,26 @@ -} module Shikensu- ( list+ ( forkDefinition+ , list , listF , listRelative , listRelativeF-- , forkDefinition , makeDefinition , makeDictionary+ , module Shikensu.Internal.Types ) where +import Data.Monoid ((<>)) import Flow+import Shikensu.Internal.Types import Shikensu.Internal.Utilities-import Shikensu.Types import System.FilePath import qualified Data.HashMap.Strict as HashMap (empty)-import qualified Data.List as List (concat, map, zip)+import qualified Data.List as List (concatMap, map, zip) import qualified System.Directory as Dir (canonicalizePath)-+import qualified System.FilePath.Glob as Glob (compile, globDir1) -- IO@@ -37,40 +38,42 @@ 4. We make a Dictionary out of each tuple (this also needs the path). 5. Merge the dictionaries into one dictionary. +> list ["*.md"] "/root/articles"+ -}-list :: [Pattern] -> FilePath -> IO Dictionary+list :: [String] -> FilePath -> IO Dictionary list patterns rootDir = patterns- |> compilePatterns- |> globDir rootDir+ |> List.map (Glob.compile)+ |> List.map (flip Glob.globDir1 $ rootDir)+ |> sequence |> fmap (List.zip patterns)- |> fmap (List.map (uncurry . makeDictionary $ rootDir))- |> fmap (List.concat)+ |> fmap (List.concatMap $ makeDictionary rootDir) {-| Flipped version of `list`. -}-listF :: FilePath -> [Pattern] -> IO Dictionary+listF :: FilePath -> [String] -> IO Dictionary listF = flip list {-| Same as `list`, but given a relative directory. > listRelative ["*.md"] "./articles"+ -}-listRelative :: [Pattern] -> FilePath -> IO Dictionary+listRelative :: [String] -> FilePath -> IO Dictionary listRelative patterns relativePath = Dir.canonicalizePath relativePath >>= list patterns {-| Flipped version `listRelative`. -}-listRelativeF :: FilePath -> [Pattern] -> IO Dictionary+listRelativeF :: FilePath -> [String] -> IO Dictionary listRelativeF = flip listRelative - -- PURE @@ -101,7 +104,7 @@ - the root path `/Users/icidasset/Projects/shikensu` - the pattern `example/**/*.md`-- the workspace path `example/test/hello.md`+- the absolute path `/Users/icidasset/Projects/shikensu/example/test/hello.md` > Definition > { basename = "hello"@@ -118,31 +121,34 @@ > } -}-makeDefinition :: FilePath -> Pattern -> FilePath -> Definition-makeDefinition _rootDirname _pattern _workspacePath =+makeDefinition :: FilePath -> String -> FilePath -> Definition+makeDefinition rootDirname pattern absolutePath = let- workingDir = cleanPath . (commonDirectory) $ _pattern- localPath = cleanPath . (stripPrefix workingDir) . cleanPath $ _workspacePath+ workingDirname = commonDirectory pattern+ rootWorkingDirname = combine rootDirname workingDirname++ theAbsolutePath = normalise absolutePath+ theLocalPath = dropDrive (stripPrefix rootWorkingDirname theAbsolutePath) in Definition- { basename = takeBaseName localPath- , dirname = takeDirName localPath- , extname = takeExtension localPath- , pattern = _pattern- , rootDirname = dropTrailingPathSeparator _rootDirname- , workingDirname = workingDir+ { basename = takeBaseName theLocalPath+ , dirname = takeDirName theLocalPath+ , extname = takeExtension theLocalPath+ , pattern = pattern+ , rootDirname = rootDirname+ , workingDirname = workingDirname -- Additional properties , content = Nothing , metadata = HashMap.empty- , parentPath = compileParentPath $ takeDirName localPath- , pathToRoot = compilePathToRoot $ takeDirName localPath+ , parentPath = compileParentPath $ takeDirName theLocalPath+ , pathToRoot = compilePathToRoot $ takeDirName theLocalPath } {-| Make a Dictionary. -}-makeDictionary :: FilePath -> Pattern -> [FilePath] -> Dictionary-makeDictionary _rootDirname _pattern =- List.map (makeDefinition _rootDirname _pattern)+makeDictionary :: FilePath -> (String, [FilePath]) -> Dictionary+makeDictionary rootDirname (pattern, filepaths) =+ List.map (makeDefinition rootDirname pattern) filepaths
src/Shikensu/Contrib.hs view
@@ -25,11 +25,11 @@ ) where import Data.ByteString (ByteString)-import Flow+import Data.Monoid ((<>)) import Shikensu (forkDefinition)-import Shikensu.Internal.Utilities (cleanPath, compileParentPath, compilePathToRoot)+import Shikensu.Internal.Types+import Shikensu.Internal.Utilities (compileParentPath, compilePathToRoot) import Shikensu.Metadata (transposeToMetadata)-import Shikensu.Types import System.FilePath (FilePath, combine) import qualified Data.HashMap.Strict as HashMap (empty, union)@@ -41,7 +41,7 @@ -} clearMetadata :: Dictionary -> Dictionary clearMetadata =- fmap (clearMetadataDef)+ fmap clearMetadataDef clearMetadataDef :: Definition -> Definition@@ -62,11 +62,11 @@ clone existingPath newPath dict = let makeNew = \def acc ->- if (localPath def) == existingPath- then acc ++ [forkDefinition newPath def]- else acc+ if localPath def == existingPath+ then acc <> [forkDefinition newPath def]+ else acc in- dict ++ (foldr makeNew [] dict)+ dict <> foldr makeNew [] dict @@ -77,7 +77,7 @@ -} copyPropsToMetadata :: Dictionary -> Dictionary copyPropsToMetadata =- fmap (copyPropsToMetadataDef)+ fmap copyPropsToMetadataDef copyPropsToMetadataDef :: Definition -> Definition@@ -93,7 +93,7 @@ -} exclude :: FilePath -> Dictionary -> Dictionary exclude path =- filter (\def -> (localPath def) /= path)+ filter (\def -> localPath def /= path) @@ -127,16 +127,16 @@ 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 = combine (dirname def) (basename def)+ in+ def+ { basename = newBasename+ , dirname = newDirname+ , parentPath = compileParentPath newDirname+ , pathToRoot = compilePathToRoot newDirname+ } else def @@ -153,12 +153,12 @@ prefixDirnameDef :: String -> Definition -> Definition prefixDirnameDef prefix def = let- newDirname = prefix ++ (dirname def)+ newDirname = prefix <> dirname def in def { dirname = newDirname- , parentPath = compileParentPath $ newDirname- , pathToRoot = compilePathToRoot $ newDirname+ , parentPath = compileParentPath newDirname+ , pathToRoot = compilePathToRoot newDirname } @@ -178,9 +178,9 @@ renameDef :: FilePath -> FilePath -> Definition -> Definition renameDef oldPath newPath def =- if (localPath def) == oldPath- then forkDefinition newPath def- else def+ if localPath def == oldPath+ then forkDefinition newPath def+ else def @@ -199,7 +199,7 @@ renameExtDef :: String -> String -> Definition -> Definition renameExtDef oldExtname newExtname def =- if (extname def) == oldExtname+ if extname def == oldExtname then def { extname = newExtname } else def
src/Shikensu/Contrib/IO.hs view
@@ -9,8 +9,7 @@ ) where import Data.Maybe (fromMaybe)-import Flow-import Shikensu.Types+import Shikensu.Internal.Types import System.Directory (createDirectoryIfMissing, doesFileExist) import System.FilePath (FilePath, joinPath, takeDirectory) @@ -25,7 +24,7 @@ -} read :: Dictionary -> IO Dictionary read =- Utilities.mapIO (readDef)+ Utilities.mapIO readDef readDef :: Definition -> IO Definition
+ src/Shikensu/Internal/Types.hs view
@@ -0,0 +1,71 @@+{-| Types and path helpers.+ This is re-exported in the main `Shikensu` module.++-}+module Shikensu.Internal.Types where++import Data.Aeson ((.=), toJSON)+import Data.ByteString (ByteString)+import Data.Monoid ((<>))+import System.FilePath (joinPath)++import qualified Data.Aeson as Aeson (Object, ToJSON, object)+++{-| A file definition, along with some additional properties.+-}+data Definition =+ Definition+ { basename :: String+ , dirname :: FilePath+ , extname :: String+ , pattern :: String+ , rootDirname :: FilePath+ , workingDirname :: FilePath++ -- Additional properties+ , content :: Maybe ByteString+ , metadata :: Metadata+ , parentPath :: Maybe FilePath+ , pathToRoot :: FilePath+ } deriving (Eq, Show)+++instance Aeson.ToJSON Definition where+ toJSON def =+ Aeson.object+ [ "basename" .= basename def+ , "dirname" .= dirname def+ , "extname" .= extname def+ , "pattern" .= pattern def+ , "workingDirname" .= workingDirname def+ , "parentPath" .= parentPath def+ , "pathToRoot" .= pathToRoot def+ ]++++-- Type aliases+++type Dictionary = [Definition]+type Metadata = Aeson.Object++++-- Path functions+++absolutePath :: Definition -> String+absolutePath def =+ joinPath [rootDirname def, workspacePath def]+++localPath :: Definition -> String+localPath def =+ joinPath [dirname def, basename def <> extname def]+++workspacePath :: Definition -> String+workspacePath def =+ joinPath [workingDirname def, localPath def]
src/Shikensu/Internal/Utilities.hs view
@@ -2,12 +2,9 @@ -} module Shikensu.Internal.Utilities- ( cleanPath- , commonDirectory- , compilePatterns+ ( commonDirectory , compileParentPath , compilePathToRoot- , globDir , replaceSingleDot , stripPrefix , takeDirName@@ -15,37 +12,23 @@ import Data.Maybe (fromMaybe) import Flow-import Shikensu.Types (Pattern) import System.FilePath import qualified Data.List as List (map, stripPrefix)+import qualified Data.Tuple as Tuple (fst) 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.+{-| Get the common directory from a pattern. -}-compilePatterns :: [Pattern] -> [Glob.Pattern]-compilePatterns =- List.map Glob.compile+commonDirectory :: String -> FilePath+commonDirectory =+ Glob.compile+ .> Glob.commonDirectory+ .> Tuple.fst+ .> normalise+ .> dropTrailingPathSeparator+ .> replaceSingleDot {-| Path to parent, when there is one.@@ -76,21 +59,11 @@ else dirname |> splitDirectories- |> fmap (\_ -> "..")+ |> fmap (const "..") |> 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. -}@@ -110,4 +83,4 @@ -} takeDirName :: FilePath -> FilePath takeDirName =- replaceSingleDot . takeDirectory+ takeDirectory .> replaceSingleDot
src/Shikensu/Metadata.hs view
@@ -7,11 +7,10 @@ ) where import Flow-import Shikensu.Types+import Shikensu.Internal.Types import qualified Data.Aeson as Aeson (FromJSON, Result(..), ToJSON, fromJSON, toJSON) import qualified Data.HashMap.Strict as HashMap (empty)- {-| Transpose metadata.
src/Shikensu/Sorting.hs view
@@ -5,7 +5,7 @@ ( sortByAbsolutePath ) where -import Shikensu.Types (Definition, absolutePath)+import Shikensu.Internal.Types (Definition, absolutePath) {-| Sort by absolutePath.
− src/Shikensu/Types.hs
@@ -1,70 +0,0 @@-{-| Types and path helpers.---}-module Shikensu.Types where--import Data.Aeson (ToJSON, Object, (.=), object, toJSON)-import Data.ByteString (ByteString)-import System.FilePath (joinPath)---{-| A file definition, along with some additional properties.--}-data Definition =- 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)---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- ]------- Type aliases---type Dictionary = [Definition]-type Metadata = Object-type Pattern = String------- Path functions---absolutePath :: Definition -> String-absolutePath def =- joinPath [rootDirname def, workspacePath def]---localPath :: Definition -> String-localPath def =- joinPath [dirname def, (basename def) ++ (extname def)]---workspacePath :: Definition -> String-workspacePath def =- joinPath [workingDirname def, localPath def]
src/Shikensu/Utilities.hs view
@@ -1,24 +1,25 @@ module Shikensu.Utilities- ( io- , mapIO- , lsequence-+ ( (!~>) , (~>)- , (!~>)+ , io+ , lsequence+ , mapIO ) where import Data.Aeson (FromJSON, ToJSON, fromJSON)+import Data.Maybe (fromMaybe)+import Data.Monoid ((<>)) import Data.Text (Text) import Flow-import Shikensu.Types+import Shikensu.Internal.Types 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 as Text (unpack) import qualified Data.Text.Lazy as Lazy.Text (unpack) import qualified Data.Text.Lazy.Encoding as Lazy.Text (decodeUtf8)+import qualified Data.Tuple as Tuple (fst, snd) -- IO@@ -45,7 +46,7 @@ From multiple IO monads to a single IO monad. -}-lsequence :: Monad m => [( String, m a )] -> m [( String, a )]+lsequence :: Monad m => [( id, m a )] -> m [( id, a )] lsequence list = let unzippedList =@@ -84,8 +85,8 @@ case (obj ~> key) of Just x -> x Nothing -> error <|- "Could not find the key `" ++ (Text.unpack key) ++ "` " ++- "on the metadata object `" ++ (aesonObjectToString obj) ++ "` using (!~>)"+ "Could not find the key `" <> Text.unpack key <> "` " <>+ "on the metadata object `" <> aesonObjectToString obj <> "` using (!~>)"
tests/Test.hs view
@@ -1,23 +1,28 @@-import Control.Exception (catch)-import System.Directory (removeDirectoryRecursive)+module Main where++import System.Directory (canonicalizePath, removePathForcibly) import System.FilePath (combine) import Test.Contrib import Test.Example-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+main = do+ root <- canonicalizePath "./"+ _ <- removePathForcibly (combine root "tests/build") + defaultMain tests + tests :: TestTree tests =- testGroup "Tests" [shikensuTests, contribTests, exampleTests, utilityTests]+ testGroup+ "Tests"+ [ shikensuTests+ , contribTests+ , exampleTests+ , utilityTests+ ]
tests/Test/Contrib.hs view
@@ -1,4 +1,6 @@-module Test.Contrib (contribTests) where+module Test.Contrib+ ( contribTests+ ) where import Data.ByteString (ByteString) import Flow@@ -13,12 +15,11 @@ import qualified Data.HashMap.Strict as HashMap (fromList, lookup) import qualified Data.List as List (head, reverse) import qualified Data.Text as Text (pack, unpack)-import qualified Data.Text.IO as Text (readFile) import qualified Data.Text.Encoding as Text (decodeUtf8)+import qualified Data.Text.IO as Text (readFile) import qualified Shikensu import qualified Shikensu.Contrib as Contrib import qualified Shikensu.Contrib.IO as Contrib.IO-import qualified Shikensu.Types as Shikensu contribTests :: TestTree@@ -38,13 +39,12 @@ - -- Test data -list :: Shikensu.Pattern -> IO Shikensu.Dictionary+list :: String -> IO Shikensu.Dictionary list pattern =- rootPath >>= Shikensu.list [pattern]+ Shikensu.listRelative [pattern] "." example_md :: IO Shikensu.Dictionary@@ -64,7 +64,6 @@ - -- Tests @@ -72,10 +71,10 @@ testClone = let dictionary = fmap (Contrib.clone "example.md" "cloned.md") example_md- definition = fmap (List.head . List.reverse) dictionary+ definition = fmap (List.reverse .> List.head) dictionary in testCase "Should `clone`"- $ definition `rmap` Shikensu.localPath >>= assertEq "cloned.md"+ $ assertDef definition Shikensu.localPath "cloned.md" @@ -83,10 +82,10 @@ testExclude = let dictionary = fmap (Contrib.exclude "example.md") example_md- length_ = fmap length dictionary+ dictLength = fmap length dictionary in testCase "Should `exclude`"- $ length_ >>= assertEq 0+ $ assertEqm dictLength 0 @@ -108,33 +107,35 @@ -- 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) ])+ dictionary = fmap+ ( id+ .> Contrib.insertMetadata (HashMap.fromList [ (keyC, valueC) ])+ .> Contrib.replaceMetadata (HashMap.fromList [ (keyA, valueA) ])+ .> Contrib.copyPropsToMetadata+ .> Contrib.insertMetadata (HashMap.fromList [ (keyB, valueB) ]) )+ example_md - definition = fmap (List.head . List.reverse) dictionary+ definition = fmap (List.reverse .> List.head) 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)+ 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+ $ assertDef definition lookupRemoved Nothing , testCase "Should have `hello` key"- $ definition `rmap` lookupHello >>= assertEq (Just valueB)+ $ assertDef definition lookupHello (Just valueB) , testCase "Should have `title` key"- $ definition `rmap` lookupTitle >>= assertEq (Just valueA)+ $ assertDef definition lookupTitle (Just valueA) , testCase "Should have `basename` key"- $ definition `rmap` lookupBasename >>= assertEq (Just valueBase)+ $ assertDef definition lookupBasename (Just valueBase) ] @@ -143,18 +144,18 @@ testPermalink = let dictionary = fmap (Contrib.permalink "index") example_md- definition = fmap (List.head) dictionary+ definition = fmap List.head dictionary in testGroup "Permalink" [ testCase "Should have the correct `localPath`"- $ definition `rmap` Shikensu.localPath >>= assertEq "example/index.md"+ $ assertDef definition Shikensu.localPath "example/index.md" , testCase "Should have the correct `parentPath`"- $ definition `rmap` Shikensu.parentPath >>= assertEq (Just "../")+ $ assertDef definition Shikensu.parentPath (Just "../") , testCase "Should have the correct `pathToRoot`"- $ definition `rmap` Shikensu.pathToRoot >>= assertEq "../"+ $ assertDef definition Shikensu.pathToRoot "../" ] @@ -168,13 +169,13 @@ testGroup "PrefixDirname" [ testCase "Should have the correct `dirname`"- $ definition `rmap` Shikensu.dirname >>= assertEq "prefix/fixtures"+ $ assertDef definition Shikensu.dirname "prefix/fixtures" , testCase "Should have the correct `pathToRoot`"- $ definition `rmap` Shikensu.pathToRoot >>= assertEq "../../"+ $ assertDef definition Shikensu.pathToRoot "../../" , testCase "Should have the correct `parentPath`"- $ definition `rmap` Shikensu.parentPath >>= assertEq (Just "../")+ $ assertDef definition Shikensu.parentPath (Just "../") ] @@ -182,14 +183,11 @@ testRead :: TestTree testRead = let- dictionary = example_md >>= Contrib.IO.read- definition = fmap List.head dictionary+ theResult = Just (Text.pack "# Example\n")+ definition = fmap List.head (example_md >>= Contrib.IO.read) in testCase "Should `read`"- $ definition- <&> Shikensu.content- <&> fmap Text.decodeUtf8- >>= assertEq (Just (Text.pack "# Example\n"))+ $ assertDef definition (Shikensu.content .> fmap Text.decodeUtf8) theResult @@ -197,10 +195,10 @@ testRename = let dictionary = fmap (Contrib.rename "example.md" "renamed.md") example_md- definition = fmap (List.head) dictionary+ definition = fmap List.head dictionary in testCase "Should `rename`"- $ definition `rmap` Shikensu.localPath >>= assertEq "renamed.md"+ $ assertDef definition Shikensu.localPath "renamed.md" @@ -208,25 +206,22 @@ testRenameExt = let dictionary = fmap (Contrib.renameExt ".md" ".html") example_md- definition = fmap (List.head) dictionary+ definition = fmap List.head dictionary in testCase "Should `renameExt`"- $ definition `rmap` Shikensu.extname >>= assertEq ".html"+ $ assertDef definition Shikensu.extname ".html" testRenderContent :: TestTree testRenderContent = let+ theResult = Just (Text.pack "<html># Example\n</html>") dictionary = fmap (Contrib.renderContent renderer) (example_md >>= Contrib.IO.read)- definition = fmap (List.head) dictionary- expectedResult = Just (Text.pack "<html># Example\n</html>")+ definition = fmap List.head dictionary in testCase "Should `renderContent`"- $ definition- <&> Shikensu.content- <&> fmap Text.decodeUtf8- >>= assertEq expectedResult+ $ assertDef definition (Shikensu.content .> fmap Text.decodeUtf8) theResult @@ -234,11 +229,13 @@ testWrite = let destination = "tests/build/"- dictionary = list "tests/**/example.md" >>= Contrib.IO.read >>= Contrib.IO.write destination+ 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)+ $ fmap Shikensu.rootDirname definition+ >>= \r -> readFile (joinPath [r, destination, "fixtures/example.md"])+ >>= \c -> assertEq "# Example\n" c
tests/Test/Example.hs view
@@ -1,33 +1,40 @@-module Test.Example (exampleTests) where+module Test.Example+ ( exampleTests+ ) where +import Data.ByteString (ByteString)+import Data.Monoid ((<>)) import Data.Text (Text)+import Flow+import Prelude hiding (read)+import Shikensu (Definition(..), Dictionary(..), list, makeDefinition)+import Shikensu.Contrib (clone, copyPropsToMetadata, permalink, renameExt, renderContent)+import Shikensu.Contrib.IO (read, write) import System.Directory (canonicalizePath) import Test.Helpers import Test.Tasty import Test.Tasty.HUnit import qualified Data.Text.Encoding as Text (decodeUtf8, encodeUtf8)-import qualified Shikensu -import Data.ByteString (ByteString)-import Flow-import Prelude hiding (read)-import Shikensu.Types-import Shikensu.Contrib-import Shikensu.Contrib.IO (read, write) - 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+ testCase "Example test" $ dictionaries >>= uncurry assertEq+++dictionaries :: IO (Dictionary, Dictionary)+dictionaries = do+ root <- canonicalizePath "./tests"+ dictA <- dictionary_io root++ let absolute = root <> "/fixtures/example.md"+ let dictB = [Shikensu.makeDefinition root "fixtures/*.md" absolute]++ dictB_Read <- read dictB+ dictB_Final <- flow dictB_Read++ return (dictA, dictB_Final)
tests/Test/Helpers.hs view
@@ -1,30 +1,24 @@ module Test.Helpers- ( (<&>)- , rmap+ ( assertDef , assertEq- , ioErrorHandler- , rootPath- , sort- , testsPath+ , assertEqm+ , define ) where +import Flow+import Shikensu import Shikensu.Sorting (sortByAbsolutePath)-import Shikensu.Types (Dictionary)-import System.Directory (canonicalizePath)-import System.FilePath (combine) import Test.Tasty.HUnit (Assertion, assertEqual) -import qualified Data.List as List+import qualified Data.List as List (head, sortBy) -(<&>) :: Functor f => f a -> (a -> b) -> f b-(<&>) =- flip fmap+-- Assertions -rmap :: Functor f => f a -> (a -> b) -> f b-rmap =- (<&>)+assertDef :: (Eq a, Show a) => IO Definition -> (Definition -> a) -> a -> Assertion+assertDef definition recordFn value =+ fmap recordFn definition >>= assertEq value assertEq :: (Eq a, Show a) => a -> a -> Assertion@@ -32,21 +26,18 @@ assertEqual "" -ioErrorHandler :: IOError -> IO ()-ioErrorHandler _ =- putStrLn ""+assertEqm :: (Eq a, Show a) => IO a -> a -> Assertion+assertEqm a b =+ a >>= assertEqual "" b -rootPath :: IO FilePath-rootPath =- canonicalizePath "./" --sort :: Dictionary -> Dictionary-sort =- List.sortBy sortByAbsolutePath+-- Shortcuts -testsPath :: IO FilePath-testsPath =- fmap ((flip combine) "tests") rootPath+define :: String -> String -> IO Definition+define pattern root =+ root+ |> Shikensu.listRelative [pattern]+ |> fmap (List.sortBy sortByAbsolutePath)+ |> fmap List.head
tests/Test/Shikensu.hs view
@@ -1,4 +1,6 @@-module Test.Shikensu (shikensuTests) where+module Test.Shikensu+ ( shikensuTests+ ) where import Test.Helpers import Test.Tasty@@ -6,14 +8,16 @@ import qualified Data.List as List (head) import qualified Shikensu-import qualified Shikensu.Types as Shikensu shikensuTests :: TestTree shikensuTests = testGroup "Shikensu tests"- [testRegular, testDot, testWithoutWd, testRootFile, testRelative]-+ [ testRegular+ , testDot+ , testWithoutWd+ , testRootFile+ ] @@ -23,29 +27,23 @@ testRegular :: TestTree testRegular = let- pattern = "tests/**/*.md"- dictionary = fmap sort $ rootPath >>= Shikensu.list [pattern]- definition = fmap List.head dictionary- localPath = "fixtures/example.md"+ definition = define "tests/**/*.md" "." in testGroup "Test regular" [ testCase "Should have the correct basename"- $ definition `rmap` Shikensu.basename >>= assertEq "example"+ $ assertDef definition Shikensu.basename "example" , testCase "Should have the correct dirname"- $ definition `rmap` Shikensu.dirname >>= assertEq "fixtures"+ $ assertDef definition Shikensu.dirname "fixtures" , testCase "Should have the correct extname"- $ definition `rmap` Shikensu.extname >>= assertEq ".md"-- , testCase "Should have the correct localPath"- $ definition `rmap` Shikensu.localPath >>= assertEq localPath+ $ assertDef definition Shikensu.extname ".md" , testCase "Should have the correct pattern"- $ definition `rmap` Shikensu.pattern >>= assertEq pattern+ $ assertDef definition Shikensu.pattern "tests/**/*.md" , testCase "Should have the correct workingDirname"- $ definition `rmap` Shikensu.workingDirname >>= assertEq "tests"+ $ assertDef definition Shikensu.workingDirname "tests" ] @@ -53,29 +51,23 @@ testDot :: TestTree testDot = let- pattern = "./tests/**/*.md"- dictionary = fmap sort $ rootPath >>= Shikensu.list [pattern]- definition = fmap List.head dictionary- localPath = "fixtures/example.md"+ definition = define "./tests/**/*.md" "." in testGroup "Test dot" [ testCase "Should have the correct basename"- $ definition `rmap` Shikensu.basename >>= assertEq "example"+ $ assertDef definition Shikensu.basename "example" , testCase "Should have the correct dirname"- $ definition `rmap` Shikensu.dirname >>= assertEq "fixtures"+ $ assertDef definition Shikensu.dirname "fixtures" , testCase "Should have the correct extname"- $ definition `rmap` Shikensu.extname >>= assertEq ".md"-- , testCase "Should have the correct localPath"- $ definition `rmap` Shikensu.localPath >>= assertEq localPath+ $ assertDef definition Shikensu.extname ".md" , testCase "Should have the correct pattern"- $ definition `rmap` Shikensu.pattern >>= assertEq pattern+ $ assertDef definition Shikensu.pattern "./tests/**/*.md" , testCase "Should have the correct workingDirname"- $ definition `rmap` Shikensu.workingDirname >>= assertEq "tests"+ $ assertDef definition Shikensu.workingDirname "tests" ] @@ -83,29 +75,23 @@ testWithoutWd :: TestTree testWithoutWd = let- pattern = "**/*.md"- dictionary = fmap sort $ testsPath >>= Shikensu.list [pattern]- definition = fmap List.head dictionary- localPath = "fixtures/example.md"+ definition = define "**/*.md" "./tests" in testGroup "Test without workingDirname" [ testCase "Should have the correct basename"- $ definition `rmap` Shikensu.basename >>= assertEq "example"+ $ assertDef definition Shikensu.basename "example" , testCase "Should have the correct dirname"- $ definition `rmap` Shikensu.dirname >>= assertEq "fixtures"+ $ assertDef definition Shikensu.dirname "fixtures" , testCase "Should have the correct extname"- $ definition `rmap` Shikensu.extname >>= assertEq ".md"-- , testCase "Should have the correct localPath"- $ definition `rmap` Shikensu.localPath >>= assertEq localPath+ $ assertDef definition Shikensu.extname ".md" , testCase "Should have the correct pattern"- $ definition `rmap` Shikensu.pattern >>= assertEq pattern+ $ assertDef definition Shikensu.pattern "**/*.md" , testCase "Should have the correct workingDirname"- $ definition `rmap` Shikensu.workingDirname >>= assertEq ""+ $ assertDef definition Shikensu.workingDirname "" ] @@ -113,45 +99,22 @@ testRootFile :: TestTree testRootFile = let- pattern = "*.md"- dictionary = fmap sort $ rootPath >>= Shikensu.list [pattern]- definition = fmap List.head dictionary- localPath = "CHANGELOG.md"+ definition = define "*.md" "." in testGroup "Test file in root path" [ testCase "Should have the correct basename"- $ definition `rmap` Shikensu.basename >>= assertEq "CHANGELOG"+ $ assertDef definition Shikensu.basename "CHANGELOG" , testCase "Should have the correct dirname"- $ definition `rmap` Shikensu.dirname >>= assertEq ""+ $ assertDef definition Shikensu.dirname "" , testCase "Should have the correct extname"- $ definition `rmap` Shikensu.extname >>= assertEq ".md"-- , testCase "Should have the correct localPath"- $ definition `rmap` Shikensu.localPath >>= assertEq localPath+ $ assertDef definition Shikensu.extname ".md" , testCase "Should have the correct pattern"- $ definition `rmap` Shikensu.pattern >>= assertEq pattern+ $ assertDef definition Shikensu.pattern "*.md" , testCase "Should have the correct workingDirname"- $ definition `rmap` Shikensu.workingDirname >>= assertEq ""-- ]---testRelative :: TestTree-testRelative =- let- pattern = "*.md"- dictionary = fmap sort $ Shikensu.listRelative [pattern] "./"- definition = fmap List.head dictionary- localPath = "CHANGELOG.md"- in- testGroup "Test relative"- [ testCase "Should have the correct rootDirname"- $ definition `rmap` Shikensu.rootDirname >>= (\x -> rootPath >>= assertEq x)+ $ assertDef definition Shikensu.workingDirname "" - , testCase "Should have the correct localPath"- $ definition `rmap` Shikensu.localPath >>= assertEq localPath ]
tests/Test/Utilities.hs view
@@ -1,7 +1,9 @@-module Test.Utilities (utilityTests) where+module Test.Utilities+ ( utilityTests+ ) where import Flow-import Shikensu.Types+import Shikensu import Shikensu.Utilities as Utils import Test.Helpers import Test.Tasty@@ -10,15 +12,13 @@ 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]-+ [ testSequencing, testMetadataAccessors ] @@ -30,40 +30,33 @@ let result = Utils.lsequence- [ ( "a", rootPath >>= Shikensu.list ["tests/fixtures/example.md"] )- , ( "b", rootPath >>= Shikensu.list ["tests/fixtures/example.md"] )+ [ ( "a", Shikensu.listRelative ["tests/fixtures/example.md"] "." )+ , ( "b", Shikensu.listRelative ["tests/fixtures/example.md"] "." ) ] in testCase "Test lsequence"- $ (List.head .> Tuple.fst) <$> result >>= assertEq "a"+ $ fmap (List.head .> Tuple.fst) result >>= assertEq "a" -testThunder :: TestTree-testThunder =+testMetadataAccessors :: TestTree+testMetadataAccessors = let- flow =- Contrib.insertMetadata (HashMap.singleton "a" "Hi!")- .> return-- dictionary =- rootPath- >>= Shikensu.list ["tests/fixtures/example.md"]- >>= flow-- def =- fmap List.head dictionary+ definition =+ "."+ |> define "tests/fixtures/example.md"+ |> fmap (Contrib.insertMetadataDef $ HashMap.singleton "a" "Hi!") resultExisting =- fmap (\d -> metadata d ~> "a" :: Maybe String) def+ fmap (\d -> metadata d ~> "a" :: Maybe String) definition resultNonExisting =- fmap (\d -> metadata d ~> "b" :: Maybe String) def+ fmap (\d -> metadata d ~> "b" :: Maybe String) definition in testGroup "Test (~>)" [ testCase "Existing"- $ resultExisting >>= assertEq (Just "Hi!")+ $ assertEqm resultExisting (Just "Hi!") , testCase "Non-existing"- $ resultNonExisting >>= assertEq (Nothing)+ $ assertEqm resultNonExisting Nothing ]