packages feed

snipcheck (empty) → 0.1.0.0

raw patch · 5 files changed

+147/−0 lines, 5 filesdep +basedep +pandocdep +processsetup-changed

Dependencies added: base, pandoc, process

Files

+ LICENSE view
@@ -0,0 +1,19 @@+Copyright (c) 2017 Nicolas Mattia++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
+ README.md view
@@ -0,0 +1,28 @@+# Snipcheck++Snipcheck makes sure that the code snippets in markdown files are up-to-date.++This is very much a work in progress. The only function currently available is++``` haskell+checkMarkdownFile :: FilePath -> IO ()+```++that will run shell snippets and errored out if the output doesn't match the+snippet. You can skip some of the output with `...`.++## Example:++    # Some title++    some markdown content++    ``` shell+    $ echo foo; echo bar; echo baz; echo qux+    foo+    ...+    qux+    ```++    some more content+
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ snipcheck.cabal view
@@ -0,0 +1,28 @@+name: snipcheck+version: 0.1.0.0+cabal-version: >=1.10+build-type: Simple+license: MIT+license-file: LICENSE+copyright: 2017 Nicolas Mattia+maintainer: nicolas@nmattia.com+homepage: https://github.com/nmattia/snipcheck#readme+synopsis: Markdown tester+description:+    Markdown snippet runner and checker+category: Development+author: Nicolas Mattia+extra-source-files:+    README.md++library+    exposed-modules:+        Snipcheck+    build-depends:+        base >=4.7 && <5,+        pandoc >=1.19.2.1 && <1.20,+        process >=1.4.3.0 && <1.5+    default-language: Haskell2010+    hs-source-dirs: src+    ghc-options: -Wall+
+ src/Snipcheck.hs view
@@ -0,0 +1,70 @@+{-# LANGUAGE DeriveFunctor #-}++module Snipcheck where++import Control.Monad+import Data.Maybe+import Data.Monoid+import System.Process(readCreateProcess, shell)+import Text.Pandoc (Block(..))++import qualified Text.Pandoc as Pandoc++data Sloppy a = Skip | Must a deriving (Show, Functor)++sloppyString :: String -> Sloppy String+sloppyString "..." = Skip+sloppyString str = Must str++checkSloppy :: Eq a => [a] -> [Sloppy a] -> Bool+checkSloppy (a:as) ((Must a'):as')+  | a == a' = checkSloppy as as'+  | otherwise = False+checkSloppy (a:as) as'@(Skip:(Must a'):as'')+  | a == a' = checkSloppy as as''+  | otherwise = checkSloppy as as'+checkSloppy as (Skip:Skip:as') = checkSloppy as (Skip:as')+checkSloppy [] ((Must _):_) = False+checkSloppy [] (Skip:as') = checkSloppy [] as'+checkSloppy [] [] = True+checkSloppy (_:_) [] = False+checkSloppy _ [Skip] = True++checkMarkdownFile :: FilePath -> IO ()+checkMarkdownFile fp = do+  content <- readFile fp+  let (Right (Pandoc.Pandoc _meta blocks)) = Pandoc.readMarkdown Pandoc.def content+  forM_ blocks check++check :: Pandoc.Block -> IO ()+check (CodeBlock (typ, classes, kvs) content)+  | "shell" `elem` classes = do+      let Right cmds = extractCommands content+      forM_ cmds $ \(cmd, expected) -> do+        actual <- lines <$> readCreateProcess (shell cmd) ""+        let expected' = sloppyString <$> expected+        unless (checkSloppy actual expected') $ error $ mconcat+          [ "Couldnt match expected ", show expected'+          , " with " <> show actual+          ]+  | otherwise = print (typ, classes, kvs)+check _ = return ()++extractCommands :: String -> Either String [(String, [String])]+extractCommands str = go (lines str)+  where+    go :: [String] -> Either String [(String, [String])]+    go (l:ls) | Just cmd <- toCommand l =+      let (output, rest) = span (not . isCommand) ls+      in ((cmd,output):) <$> (go rest)+              | otherwise = Left $ "Expected a command, got " <> l+    go [] = Right []+    toCommand :: String -> Maybe String+    toCommand ('$':cmd) = Just cmd+    toCommand _ = Nothing+    isCommand :: String -> Bool+    isCommand = isJust . toCommand+++someFunc :: IO ()+someFunc = putStrLn "someFunc"