markdown-unlit 0.2.0.1 → 0.3.0
raw patch · 4 files changed
+283/−31 lines, 4 filesdep +base-compatdep +temporarydep ~basedep ~hspecPVP ok
version bump matches the API change (PVP)
Dependencies added: base-compat, temporary
Dependency ranges changed: base, hspec
API changes (from Hackage documentation)
- Text.Markdown.Unlit: codeBlockClasses :: CodeBlock -> [String]
- Text.Markdown.Unlit: codeBlockContent :: CodeBlock -> [String]
- Text.Markdown.Unlit: codeBlockStartLine :: CodeBlock -> Int
- Text.Markdown.Unlit: instance Eq CodeBlock
- Text.Markdown.Unlit: instance Eq Selector
- Text.Markdown.Unlit: instance IsString Selector
- Text.Markdown.Unlit: instance Show CodeBlock
- Text.Markdown.Unlit: instance Show Selector
+ Text.Markdown.Unlit: [codeBlockClasses] :: CodeBlock -> [String]
+ Text.Markdown.Unlit: [codeBlockContent] :: CodeBlock -> [String]
+ Text.Markdown.Unlit: [codeBlockStartLine] :: CodeBlock -> Int
+ Text.Markdown.Unlit: instance Data.String.IsString Text.Markdown.Unlit.Selector
+ Text.Markdown.Unlit: instance GHC.Classes.Eq Text.Markdown.Unlit.CodeBlock
+ Text.Markdown.Unlit: instance GHC.Classes.Eq Text.Markdown.Unlit.Selector
+ Text.Markdown.Unlit: instance GHC.Show.Show Text.Markdown.Unlit.CodeBlock
+ Text.Markdown.Unlit: instance GHC.Show.Show Text.Markdown.Unlit.Selector
Files
- LICENSE +1/−1
- markdown-unlit.cabal +35/−25
- src/Text/Markdown/Unlit.hs +8/−5
- test/Text/Markdown/UnlitSpec.hs +239/−0
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2012 Simon Hengel <sol@typeful.net>+Copyright (c) 2012-2013 Simon Hengel <sol@typeful.net> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal
markdown-unlit.cabal view
@@ -1,14 +1,20 @@+-- This file has been generated from package.yaml by hpack version 0.8.0.+--+-- see: https://github.com/sol/hpack+ name: markdown-unlit-version: 0.2.0.1+version: 0.3.0 synopsis: Literate Haskell support for Markdown category: Development+homepage: https://github.com/sol/markdown-unlit#readme+bug-reports: https://github.com/sol/markdown-unlit/issues license: MIT license-file: LICENSE-copyright: (c) 2012 Simon Hengel+copyright: (c) 2012-2013 Simon Hengel author: Simon Hengel <sol@typeful.net> maintainer: Simon Hengel <sol@typeful.net> build-type: Simple-cabal-version: >= 1.8+cabal-version: >= 1.10 description: Documentation is here: <https://github.com/sol/markdown-unlit#readme> source-repository head@@ -16,41 +22,45 @@ location: https://github.com/sol/markdown-unlit library- ghc-options:- -Wall hs-source-dirs: src+ ghc-options: -Wall+ build-depends:+ base == 4.*+ , base-compat exposed-modules: Text.Markdown.Unlit- build-depends:- base < 5+ default-language: Haskell2010 executable markdown-unlit- ghc-options:- -Wall+ main-is: Main.hs hs-source-dirs: driver- main-is:- Main.hs+ ghc-options: -Wall build-depends:- base+ base == 4.*+ , base-compat , markdown-unlit+ default-language: Haskell2010 test-suite spec- type:- exitcode-stdio-1.0- ghc-options:- -Wall -Werror- cpp-options:- -DTEST+ type: exitcode-stdio-1.0+ main-is: Spec.hs hs-source-dirs:- src, test- main-is:- Spec.hs+ src+ , test+ ghc-options: -Wall+ cpp-options: -DTEST build-depends:- base- , stringbuilder+ base == 4.*+ , base-compat , directory- , silently- , hspec >= 1.3+ , hspec == 2.* , QuickCheck+ , silently+ , stringbuilder+ , temporary+ other-modules:+ Text.Markdown.Unlit+ Text.Markdown.UnlitSpec+ default-language: Haskell2010
src/Text/Markdown/Unlit.hs view
@@ -11,7 +11,8 @@ #endif ) where -import Control.Applicative+import Prelude ()+import Prelude.Compat import Data.Maybe import Data.List import Data.Char@@ -108,14 +109,16 @@ (cb, rest) -> cb : go rest takeCB :: Line -> [Line] -> (CodeBlock, [Line])- takeCB (n, fence) xs = case break isFence xs of- (cb, rest) -> (CodeBlock (parseClasses fence) (map snd cb) n, drop 1 rest)+ takeCB (n, fence) xs =+ let indent = length . takeWhile isSpace $ fence+ in case break isFence xs of+ (cb, rest) -> (CodeBlock (parseClasses fence) (map (drop indent . snd) cb) n, drop 1 rest) isFence :: Line -> Bool- isFence = isPrefixOf "~~~" . snd+ isFence = isPrefixOf "~~~" . dropWhile isSpace . snd parseClasses :: String -> [String]-parseClasses xs = case dropWhile isSpace . dropWhile (== '~') $ xs of+parseClasses xs = case dropWhile isSpace . dropWhile (== '~') . dropWhile isSpace $ xs of '{':ys -> words . replace '.' ' ' . takeWhile (/= '}') $ ys _ -> []
+ test/Text/Markdown/UnlitSpec.hs view
@@ -0,0 +1,239 @@+{-# LANGUAGE OverloadedStrings #-}+module Text.Markdown.UnlitSpec (main, spec) where++import Test.Hspec+import Test.QuickCheck+import Data.String.Builder+import System.Environment+import Control.Exception+import System.Exit+import System.IO.Silently+import System.IO+import System.IO.Temp (withSystemTempFile)+import System.Directory+import qualified Control.Exception as E++import Text.Markdown.Unlit++main :: IO ()+main = hspec spec++withTempFile :: (FilePath -> IO ()) -> IO ()+withTempFile action = withSystemTempFile "hspec" $ \f h -> do+ hClose h+ action f `E.finally` removeFile f++spec :: Spec+spec = do+ describe "run" $ do+ it "prints a usage message" $ do+ withProgName "foo" $ do+ (r, Left (ExitFailure 1)) <- hCapture [stderr] (try $ run [])+ r `shouldBe` "usage: foo [selector] -h label infile outfile\n"++ it "unlits code marked with .haskell by default (unless it is marked with .ignore as well)" $ do+ withTempFile $ \infile -> withTempFile $ \outfile -> do+ writeFile infile . build $ do+ "~~~ {.haskell}"+ "some code"++ "~~~"+ "~~~ {.haskell .ignore}"+ "some other code"++ "~~~"+ run ["-h", "Foo.lhs", infile, outfile]+ readFile outfile `shouldReturn` (build $ do+ "#line 2 \"Foo.lhs\""+ "some code"+ )++ it "can be customized" $ do+ withTempFile $ \infile -> withTempFile $ \outfile -> do+ writeFile infile . build $ do+ "~~~ {.foo}"+ "some code"+ ""+ "~~~"+ "~~~ {.bar}"+ "some other code"+ "~~~"+ run ["bar", "-h", "Foo.lhs", infile, outfile]+ readFile outfile `shouldReturn` (build $ do+ "#line 6 \"Foo.lhs\""+ "some other code"+ )++ describe "parseSelector" $ do+ it "parses + as :&:" $ do+ parseSelector "foo+bar+baz" `shouldBe` Just ("foo" :&: "bar" :&: "baz")++ it "parses whitespace as :|:" $ do+ parseSelector "foo bar baz" `shouldBe` Just ("foo" :|: "bar" :|: "baz")++ it "parses ! as Not" $ do+ parseSelector "foo+!bar+baz" `shouldBe` Just ("foo" :&: Not "bar" :&: "baz")++ it "can handle a combination of :&: and :|:" $ do+ parseSelector "foo+bar baz+bar" `shouldBe` Just ("foo" :&: "bar" :|: "baz" :&: "bar")++ it "is total" $ do+ property $ \xs -> parseSelector xs `seq` True++ describe "unlit" $ do+ it "can be used to unlit everything with a specified class" $ do+ unlit "Foo.lhs" "foo" . build $ do+ "~~~ {.foo}"+ "foo"+ "~~~"+ "~~~ {.bar}"+ "bar"+ "~~~"+ `shouldBe` (build $ do+ "#line 2 \"Foo.lhs\""+ "foo"+ )++ it "can handle Not" $ do+ unlit "Foo.lhs" (Not "foo") . build $ do+ "~~~ {.foo}"+ "1"+ "~~~"+ "~~~ {.bar}"+ "2"+ "~~~"+ `shouldBe` (build $ do+ "#line 5 \"Foo.lhs\""+ "2"+ )++ it "can handle :&:" $ do+ unlit "Foo.lhs" ("foo" :&: "bar") . build $ do+ "~~~ {.foo}"+ "some code"+ "~~~"+ "~~~ {.foo .bar}"+ "some other code"+ "~~~"+ `shouldBe` (build $ do+ "#line 5 \"Foo.lhs\""+ "some other code"+ )++ it "can handle :|:" $ do+ unlit "Foo.lhs" ("foo" :|: "bar") . build $ do+ "~~~ {.foo}"+ "foo"+ "~~~"+ "~~~ {.bar}"+ "bar"+ "~~~"+ `shouldBe` (build $ do+ "#line 2 \"Foo.lhs\""+ "foo"+ "#line 5 \"Foo.lhs\""+ "bar"+ )++ it "can handle a combination of :&: and :|:" $ do+ unlit "Foo.lhs" ("foo" :&: "bar" :|: "foo" :&: "baz") . build $ do+ "~~~ {.foo .bar}"+ "one"+ "~~~"+ "~~~ {.foo .baz}"+ "two"+ "~~~"+ "~~~ {.bar .baz}"+ "two"+ "~~~"+ `shouldBe` (build $ do+ "#line 2 \"Foo.lhs\""+ "one"+ "#line 5 \"Foo.lhs\""+ "two"+ )++ it "can handle a combination of :&: and Not" $ do+ unlit "Foo.lhs" ("foo" :&: Not "bar" :&: "baz") . build $ do+ "~~~ {.foo}"+ "1"+ "~~~"+ "~~~ {.foo .bar}"+ "2"+ "~~~"+ "~~~ {.foo .baz}"+ "3"+ "~~~"+ "~~~ {.foo .bar .baz}"+ "4"+ "~~~"+ `shouldBe` (build $ do+ "#line 8 \"Foo.lhs\""+ "3"+ )++ describe "parse" $ do+ it "yields an empty list on empty input" $ do+ parse "" `shouldBe` []++ it "parses a code block" $ do+ map codeBlockContent . parse . build $ do+ "some text"+ "~~~"+ "some"+ "code"+ "~~~"+ "some other text"+ `shouldBe` [["some", "code"]]++ it "parses an indented code block" $ do+ map codeBlockContent . parse . build $ do+ "1. some text"+ " ~~~"+ " some"+ " code"+ " ~~~"+ "2. some other text"+ `shouldBe` [["some", " code"]]++ it "parses an empty code block" $ do+ map codeBlockContent . parse . build $ do+ "some text"+ "~~~"+ "~~~"+ "some other text"+ `shouldBe` [[]]++ it "attaches classes to code blocks" $ do+ map codeBlockClasses . parse . build $ do+ "~~~ {.haskell .literate}"+ "some code"+ "~~~"+ `shouldBe` [["haskell", "literate"]]++ it "attaches classes to indented code blocks" $ do+ map codeBlockClasses . parse . build $ do+ "1. some text"+ " ~~~ {.haskell .literate}"+ " some code"+ " ~~~"+ "2. some other text"+ `shouldBe` [["haskell", "literate"]]++ it "attaches source locations to code blocks" $ do+ map codeBlockStartLine . parse . build $ do+ "some text"+ ""+ "~~~"+ "some"+ "code"+ "~~~"+ "some other text"+ `shouldBe` [4]++ describe "parseClasses" $ do+ it "drops a leading dot" $ do+ parseClasses "~~~ {.foo .bar}" `shouldBe` ["foo", "bar"]++ it "treats dots as whitespace" $ do+ parseClasses "~~~ {foo.bar. ..}" `shouldBe` ["foo", "bar"]