heredoc 0.1.0.1 → 0.2.0.0
raw patch · 3 files changed
+122/−38 lines, 3 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Text.Here: here :: QuasiQuoter
- Text.Here: there :: QuasiQuoter
+ Text.Heredoc: here :: QuasiQuoter
+ Text.Heredoc: str :: QuasiQuoter
+ Text.Heredoc: there :: QuasiQuoter
Files
- heredoc.cabal +2/−2
- src/Text/Here.hs +0/−36
- src/Text/Heredoc.hs +120/−0
heredoc.cabal view
@@ -1,5 +1,5 @@ name: heredoc-version: 0.1.0.1+version: 0.2.0.0 synopsis: multi-line string / here document using QuasiQuotes description: multi-line string / here document using QuasiQuotes @@ -16,7 +16,7 @@ cabal-version: >=1.8 library- exposed-modules: Text.Here+ exposed-modules: Text.Heredoc build-depends: base >= 4 && < 5, template-haskell >= 2.5
− src/Text/Here.hs
@@ -1,36 +0,0 @@-module Text.Here (here, there) where--import Language.Haskell.TH- ( litE- , stringL- )--import Language.Haskell.TH.Quote- ( QuasiQuoter- ( QuasiQuoter- , quoteExp- , quotePat- , quoteType- , quoteDec- )- , quoteFile- )--err :: String -> String-err ctx =- "You have used the `here` QuasiQuoter in a " ++ ctx ++ " context; " ++- "you must only use it as a string literal expression"---- | Create a string-literal expression from the string being quoted.-here :: QuasiQuoter-here = QuasiQuoter- { quoteExp = litE . stringL- , quotePat = const $ error $ err "pattern"- , quoteType = const $ error $ err "type"- , quoteDec = const $ error $ err "declaration"- }---- | Create a string-literal expression from--- the contents of the file at the filepath being quoted.-there :: QuasiQuoter-there = quoteFile here
+ src/Text/Heredoc.hs view
@@ -0,0 +1,120 @@+module Text.Heredoc (here, there, str) where++import Data.Maybe (fromMaybe)+import Data.List (intercalate)+import Language.Haskell.TH+ ( litE+ , stringL+ )++import Language.Haskell.TH.Quote+ ( QuasiQuoter+ ( QuasiQuoter+ , quoteExp+ , quotePat+ , quoteType+ , quoteDec+ )+ , quoteFile+ )++data Ctx = Exp | Pat | Type | Dec++qq :: String -> Ctx -> QuasiQuoter+qq qqName correctCtx = QuasiQuoter+ { quoteExp = const $ error $ errorString Exp+ , quotePat = const $ error $ errorString Pat+ , quoteType = const $ error $ errorString Type+ , quoteDec = const $ error $ errorString Dec+ }+ where+ errorString ctx =+ "You have used the `" ++ qqName ++ "` QuasiQuoter " +++ "in " ++ ctxName ctx ++ " context; " +++ "you must only use it in " ++ ctxName correctCtx ++ " context"++ ctxName c = case c of+ Exp -> "an expression"+ Pat -> "a pattern"+ Type -> "a type"+ Dec -> "a declaration"+++toUnix :: String -> String+toUnix cs = case cs of+ '\r':'\n' : cs -> '\n' : toUnix cs+ '\r' : cs -> '\n' : toUnix cs+ c : cs -> c : toUnix cs+ [] -> []++{-| Create a string-literal expression from the string being quoted.++ Newline literals are normalized to UNIX newlines (one '\n' character).+-}+here :: QuasiQuoter+here = (qq "here" Exp) { quoteExp = litE . stringL . toUnix }++{-| Create a string-literal expression from+ the contents of the file at the filepath being quoted.++ Newline literals are normalized to UNIX newlines (one '\n' character).+-}+there :: QuasiQuoter+there = quoteFile here++{-| Create a multi-line string literal whose left edge is demarcated by the+ "pipe" character ('|'). For example,++ >famousQuote = [str|Any dictator would admire the+ > |uniformity and obedience of the U.S. media.+ > |+ > | -- Noam Chomsky+ > |]++ is functionally equivalent to++ >famousQuote = "Any dictator would admire the\n" +++ > "uniformity and obedience of the U.S. media.\n" +++ > "\n" +++ > " -- Noam Chomsky\n"++ If desired, you can have a ragged left-edge, so++ >myHtml = [str|<html>+ > |<body>+ > |<h1>My home page</h1>+ > |</body>+ > |</html>+ > |]++ is functionally equivalent to++ >myHtml = "<html>\n" +++ > "<body>\n" +++ > "<h1>My home page</h1>\n" +++ > "</body>\n" +++ > "</html>\n"+-}+str :: QuasiQuoter+str = (qq "str" Exp)+ { quoteExp = litE . stringL . intercalate "\n" . unPipe . lines . toUnix }+ where+ unPipe ls = case ls of+ [] -> []+ l : ls -> l : case splitLast ls of+ Nothing -> []+ Just (middles, last) ->+ map removePipe middles ++ [fromMaybe "" (tryRemovePipe last)]+ where+ removePipe cs = case tryRemovePipe cs of+ Nothing -> error "no pipe character found in line '" ++ cs ++ "'"+ Just cs -> cs++ tryRemovePipe cs = case dropWhile (/='|') cs of+ [] -> Nothing+ c:cs -> Just cs++ splitLast :: [a] -> Maybe ([a], a)+ splitLast xs = case reverse xs of+ [] -> Nothing+ l:i -> Just (reverse i, l)