qm-interpolated-string 0.1.1.0 → 0.2.0.0
raw patch · 22 files changed
+2657/−307 lines, 22 filesdep ~haskell-src-meta
Dependency ranges changed: haskell-src-meta
Files
- CHANGELOG.md +24/−4
- README.md +179/−28
- qm-interpolated-string.cabal +38/−16
- src/Text/InterpolatedString/QM.hs +80/−156
- src/Text/InterpolatedString/QM/Internal/Parsers.hs +89/−0
- src/Text/InterpolatedString/QM/Internal/Parsers/Helpers.hs +120/−0
- src/Text/InterpolatedString/QM/Internal/Parsers/TH.hs +184/−0
- src/Text/InterpolatedString/QM/Internal/Parsers/Types.hs +19/−0
- src/Text/InterpolatedString/QM/ShowQ/Class.hs +42/−0
- test/LineBreaks/CRLF/QM/Spec.hs +161/−0
- test/LineBreaks/CRLF/QMB/Spec.hs +156/−0
- test/LineBreaks/CRLF/QMS/Spec.hs +162/−0
- test/LineBreaks/CRLF/QN/Spec.hs +134/−0
- test/LineBreaks/CRLF/QNB/Spec.hs +158/−0
- test/LineBreaks/CRLF/QNS/Spec.hs +158/−0
- test/QM/Spec.hs +160/−0
- test/QMB/Spec.hs +155/−0
- test/QMS/Spec.hs +161/−0
- test/QN/Spec.hs +133/−0
- test/QNB/Spec.hs +157/−0
- test/QNS/Spec.hs +157/−0
- test/Spec.hs +30/−103
CHANGELOG.md view
@@ -1,5 +1,25 @@-## 0.1.1.0+## <a name="v0.2.0.0"></a>0.2.0.0 -- Added `qn` QuasiQuoter as alternative to `qm` but without interpolation-- Some code refactoring-- More docs and tests+* Added tab (`\t`) symbol escaping+ (breaks backward compatibility with [v0.1.1.0](#v0.1.1.0))+* Support new [LTS Haskell 9.0 (ghc-8.0.2)](https://www.stackage.org/lts-9.0)+ (updated upper version of **haskell-src-meta** from 0.7.x to 0.8.x)+* Added `qmb` QuasiQuoter,+ it's `qm` + `b` (line-<b>B</b>reaks),+ it works just as `qm` but keeps line breaks (still ignores indendation)+* Added `qnb` QuasiQuoter (`qmb` without interpolation),+ it's `qn` + `b` (line-<b>B</b>reaks),+ it works just as `qn` but keeps line breaks (still ignores indendation)+* Added `qms` QuasiQuoter,+ it's `qm` + `s` (<b>S</b>paces),+ it works just as `qmb` but kept line breaks replaced with spaces+* Added `qns` QuasiQuoter (`qms` without interpolation),+ it's `qn` + `s` (<b>S</b>paces),+ it works just as `qnb` but kept line breaks replaced with spaces+* More docs and tests++## <a name="v0.1.1.0"></a>0.1.1.0++* Added `qn` QuasiQuoter as alternative to `qm` but without interpolation+* Some code refactoring+* More docs and tests
README.md view
@@ -9,65 +9,216 @@ Actually it's modification of [interpolatedstring-perl6](https://github.com/audreyt/interpolatedstring-perl6)-package. I used it to implemenent my own strings I really like.+package. I've forked it to implemenent my own strings I really like. -This implementation looks just like `qc`-from **interpolatedstring-perl6** package but ignores any indentation,-line breaks (except explicitly written using `\n` char)+This implementation based on `qc` from **interpolatedstring-perl6** package+but ignores any indentation, line breaks+(except explicitly written using `\n` char) and trailing whitespaces. -'m' in 'qm' means 'multiline'.+* 'm' in `qm` means '**M**ultiline'.+* 'n' in `qn` means '**N**o interpolation'.+* 'b' in `qmb`/`qnb` means 'line **B**reaks'.+* 's' in `qms`/`qns` means '**S**paces'. -You could write a decoratively formatted string and your-decorative indentation and line breaks wont go to the string,+Write a decoratively formatted string and your+decorative indentation and line breaks wont go to result string, but when you really need it, you could just escape it using backslash. -## Simple usage example+## Usage example ```haskell {-# LANGUAGE QuasiQuotes #-} -import Text.InterpolatedString.QM (qm)+import Text.InterpolatedString.QM main :: IO ()-main = putStrLn [qm| hello- \ world |]+main = do+ -- Hello, world! Pi is 3.14…+ putStrLn [qms| Hello,+ world!+ Pi is {floor pi}.{floor $ (pi - 3) * 100}… |]++ -- Some examples with HTML below to demonstrate the difference+ -- between all of the quasi-quoters.++ let title = "Testing"+ text = "Some testing text"++ -- <article><h1>Testing</h1><p>Some testing text</p></article>+ putStrLn [qm|+ <article>+ <h1>{title}</h1>+ <p>{text}</p>+ </article>+ |]++ -- <article><h1>{title}</h1><p>{text}</p></article>+ putStrLn [qn|+ <article>+ <h1>{title}</h1>+ <p>{text}</p>+ </article>+ |]++ -- <article> <h1>Testing</h1> <p>Some testing text</p> </article>+ putStrLn [qms|+ <article>+ <h1>{title}</h1>+ <p>{text}</p>+ </article>+ |]++ -- <article> <h1>{title}</h1> <p>{text}</p> </article>+ putStrLn [qns|+ <article>+ <h1>{title}</h1>+ <p>{text}</p>+ </article>+ |]++ -- <article>+ -- <h1>Testing</h1>+ -- <p>Some testing text</p>+ -- </article>+ putStrLn [qmb|+ <article>+ <h1>{title}</h1>+ <p>{text}</p>+ </article>+ |]++ -- <article>+ -- <h1>{title}</h1>+ -- <p>{text}</p>+ -- </article>+ putStrLn [qnb|+ <article>+ <h1>{title}</h1>+ <p>{text}</p>+ </article>+ |] ``` +## Tables++### All QuasiQuoters++```+| QuasiQuoter | Interpolation | Indentation | Line breaks | Trailing whitespaces |+|-------------|---------------|-------------|----------------------|----------------------|+| qm | ✓ | Removed | Removed | Removed |+| qn | ✗ | Removed | Removed | Removed |+| qmb | ✓ | Removed | Kept | Removed |+| qnb | ✗ | Removed | Kept | Removed |+| qms | ✓ | Removed | Replaced with spaces | Removed |+| qns | ✗ | Removed | Replaced with spaces | Removed |+```++### About naming logic++```+| Contains in its name | What means | QuasiQuoters |+|----------------------|----------------------------------|--------------|+| m | Resolves interpolation blocks | qm, qmb, qms |+| n | Without interpolation | qn, qnb, qns |+| b | Keeps line breaks | qmb, qnb |+| s | Replaces line breaks with spaces | qms, qns |+```++## About escaping++### Symbols that can be escaped++Backslash is used for escaping these:++ 1. `\n` - line break+ 2. `\ ` - space (space is supposed to be escaped when you're going to keep+ some part of indentation)+ 3. `\↵` - backslash just before end of line cuts off line break+ (makes sense for `qmb`, `qnb`, `qms` and `qns`)+ 4. `\{` - opening bracket of interpolation block+ (only for `qm`, `qmb` and `qms`, to prevent interpolation+ and interpret this block as plain text)+ 5. `\t` or `\‣` (where `‣` is real tab symbol) - tab (escaping it to keep some+ part of indentation, or if you need tab symbol for some reason,+ escaping real tabs makes sense only for keeping some part of indentation)+ 6. `\\` - backslash itself (for situations when you don't want to escape+ other symbols but just want backslash symbol, `\\t`, `\\n`, `\\↵`,+ `\\{`, etc., if backslash doesn't come with any of symbols from+ this list it is interpreted just as backslash symbol, keep in mind+ that `\\\` (without any of symbols from this list after)+ and `\\\\` are producing same result - `\\`)++### Escaping examples++```haskell+[qm| foo\nbar |] -- "foo\nbar"+[qm| foo\\nbar |] -- "foo\\nbar"+[qm| foo\tbar |] -- "foo\tbar"+[qm| foo\\tbar |] -- "foo\\tbar"+[qm| foo\‣bar |] -- "foo\tbar" (`‣` is real tab symbol)+[qm| foo\\‣bar |] -- "foo\\\tbar" (`‣` is real tab symbol)+[qm| foo\ bar |] -- "foo bar"+[qm| foo\\ bar |] -- "foo\\ bar"++[qm| foo\+ bar |] -- "foobar"+[qm| foo\\+ bar |] -- "foo\\bar"++[qmb| foo\+ bar |] -- "foobar"+[qmb| foo\\+ bar |] -- "foo\\\nbar"++[qm| foo\bar |] -- "foo\\bar"+[qm| foo\\bar |] -- "foo\\bar"+[qm| foo\\\bar |] -- "foo\\\\bar"+[qm| foo\\\\bar |] -- "foo\\\\bar"+```+ ## More examples ```haskell-[qm| hello world,- \ what's going on here? |]--- Result: "hello world, what's going on here?"+[qm| you can escape spaces+ \ when you need them |]+-- Result: "you can escape spaces when you need them" ``` ```haskell [qm|- it's actual- ly ignored- |]--- Result: "it's actually ignored"+ indentation and li+ ne bre+ aks are i+ gno+ red+|]+-- Result: "indentation and line breaks are ignored" ``` ```haskell-[qm| \ You could explicitly escape indentation or\n- line-breaks when you really need it! \- |]--- Result: " You could explicitly escape indentation or\nline-breaks when you really need it! "+[qm| \ You can escape indentation or\n+ line breaks when you need them! \ |]+-- Result: " You can escape indentation or\nline breaks when you need them! " ``` ```haskell-[qm| {1+2} \{3+4} |]--- Result: "3 {3+4}"+[qm| Interpolation blocks can be escaped too: {1+2} \{3+4} |]+-- Result: "Interpolation blocks can be escaped too: 3 {3+4}" ``` -There is also very similar to `qm` QuasiQuoter-named as `qn` that do the same except interpolation:+If you don't need interpolation - just replace `m` to `n` in quasi-quoter name: ```haskell-[qn| foo {1+2} |]--- Result: "foo {1+2}"+[qm| foo {1+2} |] -- Result: "foo 3"+[qn| foo {1+2} |] -- Result: "foo {1+2}"++[qms| foo {1+2} |] -- Result: "foo 3"+[qns| foo {1+2} |] -- Result: "foo {1+2}"++[qmb| foo {1+2} |] -- Result: "foo 3"+[qnb| foo {1+2} |] -- Result: "foo {1+2}" ``` ## Author
qm-interpolated-string.cabal view
@@ -1,5 +1,5 @@ name: qm-interpolated-string-version: 0.1.1.0+version: 0.2.0.0 synopsis: Implementation of interpolated multiline strings description: Implementation of interpolated multiline strings that ignores indentation and trailing whitespaces@@ -24,20 +24,42 @@ location: git://github.com/unclechu/haskell-qm-interpolated-string.git library- ghc-options: -Wall- hs-source-dirs: src- exposed-modules: Text.InterpolatedString.QM- build-depends: base ==4.*- , template-haskell >=2.5 && <3- , haskell-src-meta >=0.3 && <0.8- , bytestring ==0.10.*- , text ==1.*+ ghc-options: -Wall+ hs-source-dirs: src+ exposed-modules: Text.InterpolatedString.QM+ , Text.InterpolatedString.QM.Internal.Parsers+ , Text.InterpolatedString.QM.Internal.Parsers.TH+ , Text.InterpolatedString.QM.Internal.Parsers.Types+ , Text.InterpolatedString.QM.Internal.Parsers.Helpers+ , Text.InterpolatedString.QM.ShowQ.Class+ build-depends: base ==4.*+ , template-haskell >=2.5 && <3+ , haskell-src-meta >=0.3 && <0.9+ , bytestring ==0.10.*+ , text ==1.* test-suite tests- type: exitcode-stdio-1.0- ghc-options: -Wall -fno-warn-type-defaults- hs-source-dirs: test- main-is: Spec.hs- build-depends: base ==4.*- , hspec ==2.*- , qm-interpolated-string+ type: exitcode-stdio-1.0++ if impl(ghc >= 8.0)+ ghc-options: -Wall -fno-warn-type-defaults -Wno-tabs+ else+ ghc-options: -Wall -fno-warn-type-defaults++ hs-source-dirs: test+ main-is: Spec.hs+ other-modules: QM.Spec+ , QN.Spec+ , QMB.Spec+ , QNB.Spec+ , QMS.Spec+ , QNS.Spec+ , LineBreaks.CRLF.QM.Spec+ , LineBreaks.CRLF.QN.Spec+ , LineBreaks.CRLF.QMB.Spec+ , LineBreaks.CRLF.QNB.Spec+ , LineBreaks.CRLF.QMS.Spec+ , LineBreaks.CRLF.QNS.Spec+ build-depends: base ==4.*+ , hspec ==2.*+ , qm-interpolated-string
src/Text/InterpolatedString/QM.hs view
@@ -1,196 +1,120 @@ -- Fork of: https://github.com/audreyt/interpolatedstring-perl6/blob/63d91a83eb5e48740c87570a8c7fd4668afe6832/src/Text/InterpolatedString/Perl6.hs -- Author of the 'interpolatedstring-perl6' package: Audrey Tang -{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeSynonymInstances #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE IncoherentInstances #-}- {-# LANGUAGE PackageImports #-}-{-# LANGUAGE ViewPatterns #-} -{-# LANGUAGE CPP #-}--module Text.InterpolatedString.QM (qm, qn, ShowQ(..)) where+module Text.InterpolatedString.QM (qm, qn, qmb, qnb, qms, qns, ShowQ (..)) where -import "base" GHC.Exts (IsString (fromString))-import qualified "template-haskell" Language.Haskell.TH as TH import "template-haskell" Language.Haskell.TH.Quote (QuasiQuoter (QuasiQuoter))-import "haskell-src-meta" Language.Haskell.Meta.Parse (parseExp)-import "bytestring" Data.ByteString.Char8 as Strict (ByteString, unpack)-import "bytestring" Data.ByteString.Lazy.Char8 as Lazy (ByteString, unpack)-import "text" Data.Text as T (Text, unpack)-import "text" Data.Text.Lazy as LazyT (Text, unpack) -#if MIN_VERSION_base(4,8,0)-#else-import "base" Data.Monoid (mempty, mappend)-#endif---class ShowQ a where- showQ :: a -> String--instance ShowQ Char where- showQ = (:[])--instance ShowQ String where- showQ = id--instance ShowQ Strict.ByteString where- showQ = Strict.unpack--instance ShowQ Lazy.ByteString where- showQ = Lazy.unpack--instance ShowQ T.Text where- showQ = T.unpack--instance ShowQ LazyT.Text where- showQ = LazyT.unpack--instance Show a => ShowQ a where- showQ = show--class QQ a string where- toQQ :: a -> string--instance IsString s => QQ s s where- toQQ = id--instance (ShowQ a, IsString s) => QQ a s where- toQQ = fromString . showQ--data StringPart = Literal String | AntiQuote String deriving Show---unQM :: String -> String -> [StringPart]-unQM a "" = [Literal (reverse a)]-unQM a ('\\':x:xs) = unQM (x:a) xs-unQM a ("\\") = unQM ('\\':a) ""-unQM a ('}':xs) = AntiQuote (reverse a) : parseQM "" xs-unQM a (x:xs) = unQM (x:a) xs---parseQM :: String -> String -> [StringPart]-parseQM a "" = [Literal (reverse a)]-parseQM a ('\\':'\\':xs) = parseQM ('\\':a) xs-parseQM a ('\\':'{':xs) = parseQM ('{':a) xs-parseQM a ('\\':' ':xs) = parseQM (' ':a) xs-parseQM a ('\\':'\n':xs) = parseQM a ('\n':xs)-parseQM a ('\\':'n':xs) = parseQM ('\n':a) xs-parseQM a ("\\") = parseQM ('\\':a) ""-parseQM a ('{':xs) = Literal (reverse a) : unQM "" xs-parseQM a (clearIndentAtSOF -> Just clean) = parseQM a clean-parseQM a (clearIndentTillEOF -> Just clean) = parseQM a clean-parseQM a ('\n':xs) = parseQM a xs -- cut off line breaks-parseQM a (x:xs) = parseQM (x:a) xs---parseQN :: String -> String -> [StringPart]-parseQN a "" = [Literal (reverse a)]-parseQN a ('\\':'\\':xs) = parseQN ('\\':a) xs-parseQN a ('\\':' ':xs) = parseQN (' ':a) xs-parseQN a ('\\':'\n':xs) = parseQN a ('\n':xs)-parseQN a ('\\':'n':xs) = parseQN ('\n':a) xs-parseQN a ("\\") = parseQN ('\\':a) ""-parseQN a (clearIndentAtSOF -> Just clean) = parseQN a clean-parseQN a (clearIndentTillEOF -> Just clean) = parseQN a clean-parseQN a ('\n':xs) = parseQN a xs -- cut off line breaks-parseQN a (x:xs) = parseQN (x:a) xs---clearIndentTillEOF :: String -> Maybe String-clearIndentTillEOF s | s == "" = Nothing- | head s `elem` "\t " = cutOff s- | otherwise = Nothing-- where cutOff x | x == "" = Just ""- | head x == '\n' = Just x- | head x `elem` "\t " = cutOff $ tail x- | otherwise = Nothing---clearIndentAtSOF :: String -> Maybe String-clearIndentAtSOF s | s == "" = Nothing- | head s == '\n' && hasChanges = Just processed- | otherwise = Nothing-- where processed = '\n' : cutOff (tail s)- hasChanges = processed /= s-- cutOff x | x == "" = ""- | head x `elem` "\t " = cutOff $ tail x- | otherwise = x---clearIndentAtStart :: String -> String-clearIndentAtStart s | s == "" = ""- | head s `elem` "\t " = clearIndentAtStart $ tail s- | otherwise = s---makeExpr :: [StringPart] -> TH.ExpQ-makeExpr [] = [| mempty |]-makeExpr (Literal a : xs) =- TH.appE [| mappend (fromString a) |] $ makeExpr xs-makeExpr (AntiQuote a : xs) =- TH.appE [| mappend (toQQ $(reify a)) |] $ makeExpr xs---reify :: String -> TH.Q TH.Exp-reify s = case parseExp s of- Left e -> TH.reportError e >> [| mempty |]- Right e -> return e+-- local imports+import Text.InterpolatedString.QM.ShowQ.Class (ShowQ (..))+import qualified Text.InterpolatedString.QM.Internal.Parsers as Parsers -- | QuasiQuoter for multiline interpolated string. -- -- @--- [qm| foo {'b':'a':'r':""}+-- ['qm'| foo {'b':'a':'r':""} -- \\ baz |] -- "foo bar baz" -- @ -- -- Symbols that could be escaped: -- -- * @\\@ - backslash itself (two backslashes one by one: @\\\\@)--- @[qm| foo\\\\bar |] -- "foo\\\\bar"@+-- @['qm'| foo\\\\bar |] -- "foo\\\\bar"@ -- -- * Space symbol at the edge -- (to put it to the output instead of just ignoring it)--- @[qm| foo\\ |] -- "foo "@ or @[qm|\\ foo |] -- " foo"@+-- @['qm'| foo\\ |] -- "foo "@ or @['qm'|\\ foo |] -- " foo"@ -- -- * Line break @\\n@ (actual line breaks are ignored) -- -- * Opening bracket of interpolation block @\\{@--- to prevent interpolatin and put it as it is--- @[qm| {1+2} \\{3+4} |] -- "3 {3+4}"@+-- to prevent interpolation and put it as it is+-- @['qm'| {1+2} \\{3+4} |] -- "3 {3+4}"@ -- qm :: QuasiQuoter-qm = QuasiQuoter f- (error "Cannot use qm as a pattern")- (error "Cannot use qm as a type")- (error "Cannot use qm as a dec")- where f = makeExpr . parseQM "" . clearIndentAtStart . filter (/= '\r')+qm = QuasiQuoter Parsers.qm+ (error "Cannot use 'qm' as a pattern")+ (error "Cannot use 'qm' as a type")+ (error "Cannot use 'qm' as a dec") --- | Works just like `qm` but without interpolation+-- | Works just like 'qm' but without interpolation -- (just multiline string with decorative indentation). -- -- @--- [qn| foo {'b':'a':'r':""}+-- ['qn'| foo {'b':'a':'r':""} -- \\ baz |] -- "foo {'b':'a':'r':\\"\\"} baz" -- @ -- -- Interpolation blocks goes just as text: ----- @[qn| {1+2} \\{3+4} |] -- "{1+2} \\\\{3+4}"@+-- @['qn'| {1+2} \\{3+4} |] -- "{1+2} \\\\{3+4}"@ -- qn :: QuasiQuoter-qn = QuasiQuoter f- (error "Cannot use qn as a pattern")- (error "Cannot use qn as a type")- (error "Cannot use qn as a dec")- where f = makeExpr . parseQN "" . clearIndentAtStart . filter (/= '\r')+qn = QuasiQuoter Parsers.qn+ (error "Cannot use 'qn' as a pattern")+ (error "Cannot use 'qn' as a type")+ (error "Cannot use 'qn' as a dec")+++-- | 'qm' + `b` (line-/B/reaks)+--+-- @+-- ['qmb'| foo+-- {'b':'a':'r':""}+-- baz |] -- "foo\\nbar\\nbaz"+-- @+--+qmb :: QuasiQuoter+qmb = QuasiQuoter Parsers.qmb+ (error "Cannot use 'qmb' as a pattern")+ (error "Cannot use 'qmb' as a type")+ (error "Cannot use 'qmb' as a dec")+++-- | 'qn' + `b` (line-/B/reaks)+-- Works just like 'qmb' but without interpolation.+--+-- @+-- ['qnb'| foo+-- {'b':'a':'r':""}+-- baz |] -- "foo\\n{'b':'a':'r':\\"\\"}\\nbaz"+-- @+qnb :: QuasiQuoter+qnb = QuasiQuoter Parsers.qnb+ (error "Cannot use 'qnb' as a pattern")+ (error "Cannot use 'qnb' as a type")+ (error "Cannot use 'qnb' as a dec")+++-- | 'qm' + `s` (/S/paces)+--+-- @+-- ['qms'| foo+-- {'b':'a':'r':""}+-- baz |] -- "foo bar baz"+-- @+qms :: QuasiQuoter+qms = QuasiQuoter Parsers.qms+ (error "Cannot use 'qms' as a pattern")+ (error "Cannot use 'qms' as a type")+ (error "Cannot use 'qms' as a dec")+++-- | 'qn' + `s` (/S/paces)+--+-- Works just like 'qms' but without interpolation.+--+-- @+-- ['qns'| foo+-- {'b':'a':'r':""}+-- baz |] -- "foo {'b':'a':'r':\\"\\"} baz"+-- @+qns :: QuasiQuoter+qns = QuasiQuoter Parsers.qns+ (error "Cannot use 'qns' as a pattern")+ (error "Cannot use 'qns' as a type")+ (error "Cannot use 'qns' as a dec")
+ src/Text/InterpolatedString/QM/Internal/Parsers.hs view
@@ -0,0 +1,89 @@+-- Fork of: https://github.com/audreyt/interpolatedstring-perl6/blob/63d91a83eb5e48740c87570a8c7fd4668afe6832/src/Text/InterpolatedString/Perl6.hs+-- Author of the 'interpolatedstring-perl6' package: Audrey Tang++{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE PackageImports #-}+{-# LANGUAGE ViewPatterns #-}++module Text.InterpolatedString.QM.Internal.Parsers+ ( qm, qn+ , qmb, qnb+ , qms, qns+ ) where++import qualified "template-haskell" Language.Haskell.TH as TH++-- local imports++import Text.InterpolatedString.QM.Internal.Parsers.TH (parserTpl)++import Text.InterpolatedString.QM.Internal.Parsers.Types ( Parser+ , StringPart (..)+ , LineBreaks (..)+ )++import Text.InterpolatedString.QM.Internal.Parsers.Helpers+ ( unQX+ , clearIndentAtStart+ , clearIndentAtSOF+ , clearIndentTillEOF+ , clearFirstQXXLineBreak+ , clearLastQXXLineBreak+ , makeExpr+ )+++$(parserTpl "parseQM" True IgnoreLineBreaks)+$(parserTpl "parseQN" False IgnoreLineBreaks)+$(parserTpl "parseQMB" True KeepLineBreaks)+$(parserTpl "parseQNB" False KeepLineBreaks)+$(parserTpl "parseQMS" True ReplaceLineBreaksWithSpaces)+$(parserTpl "parseQNS" False ReplaceLineBreaksWithSpaces)+++-- With interpolation blocks (line breaks and indentation are ignored)+qm :: String -> TH.ExpQ+qm = makeExpr . parseQM "" . clearIndentAtStart . filter (/= '\r')+++-- No interpolation block (line breaks and indentation are ignored)+qn :: String -> TH.ExpQ+qn = makeExpr . parseQN "" . clearIndentAtStart . filter (/= '\r')+++-- With interpolation blocks (line breaks are kept, indentation is ignored)+qmb :: String -> TH.ExpQ+qmb = makeExpr+ . parseQMB ""+ . clearFirstQXXLineBreak+ . clearIndentAtStart+ . filter (/= '\r')+++-- No interpolation block (line breaks are kept, indentation is ignored)+qnb :: String -> TH.ExpQ+qnb = makeExpr+ . parseQNB ""+ . clearFirstQXXLineBreak+ . clearIndentAtStart+ . filter (/= '\r')+++-- With interpolation blocks+-- (line breaks are replaced with spaces, indentation is ignored).+qms :: String -> TH.ExpQ+qms = makeExpr+ . parseQMS ""+ . clearFirstQXXLineBreak+ . clearIndentAtStart+ . filter (/= '\r')+++-- No interpolation block+-- (line breaks are replaced with spaces, indentation is ignored).+qns :: String -> TH.ExpQ+qns = makeExpr+ . parseQNS ""+ . clearFirstQXXLineBreak+ . clearIndentAtStart+ . filter (/= '\r')
+ src/Text/InterpolatedString/QM/Internal/Parsers/Helpers.hs view
@@ -0,0 +1,120 @@+-- Fork of: https://github.com/audreyt/interpolatedstring-perl6/blob/63d91a83eb5e48740c87570a8c7fd4668afe6832/src/Text/InterpolatedString/Perl6.hs+-- Author of the 'interpolatedstring-perl6' package: Audrey Tang++{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE PackageImports #-}+{-# LANGUAGE CPP #-}++{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE IncoherentInstances #-}+{-# LANGUAGE FlexibleInstances #-}++module Text.InterpolatedString.QM.Internal.Parsers.Helpers+ ( unQX+ , clearIndentAtStart+ , clearIndentAtSOF+ , clearIndentTillEOF+ , clearFirstQXXLineBreak+ , clearLastQXXLineBreak+ , makeExpr+ ) where++import "base" GHC.Exts (IsString (fromString))+import "haskell-src-meta" Language.Haskell.Meta.Parse (parseExp)+import qualified "template-haskell" Language.Haskell.TH as TH++#if MIN_VERSION_base(4,8,0)+#else+import "base" Data.Monoid (mempty, mappend)+#endif++-- local imports++import Text.InterpolatedString.QM.ShowQ.Class (ShowQ (..))++import Text.InterpolatedString.QM.Internal.Parsers.Types ( Parser+ , StringPart (..)+ )+++class QQ a string where+ toQQ :: a -> string++instance IsString s => QQ s s where+ toQQ = id++instance (ShowQ a, IsString s) => QQ a s where+ toQQ = fromString . showQ+++-- Parser for interpolation block+unQX :: Parser -> Parser+unQX _ a "" = [Literal (reverse a)]+unQX f a ('\\':x:xs) = unQX f (x:a) xs+unQX f a ("\\") = unQX f ('\\':a) ""+unQX f a ('}':xs) = AntiQuote (reverse a) : f "" xs+unQX f a (x:xs) = unQX f (x:a) xs+++clearIndentAtSOF :: String -> Maybe String+clearIndentAtSOF "" = Nothing+clearIndentAtSOF s@(x:xs) | x == '\n' && hasChanges = Just processed+ | otherwise = Nothing++ where processed = '\n' : cutOff xs+ hasChanges = processed /= s++ cutOff "" = ""+ cutOff z@(y:ys) | y `elem` "\t " = cutOff ys+ | otherwise = z+++clearIndentTillEOF :: String -> Maybe String+clearIndentTillEOF "" = Nothing+clearIndentTillEOF s@(x:_) | x `elem` "\t " = cutOff s+ | otherwise = Nothing++ where cutOff "" = Just ""+ cutOff z@('\n':_) = Just z+ cutOff (y:ys) | y `elem` "\t " = cutOff ys+ | otherwise = Nothing+++clearLastQXXLineBreak :: String -> Bool+-- Cannot really be empty (matched in `parseQMB`)+clearLastQXXLineBreak "" = False+clearLastQXXLineBreak (x:xs) | x `elem` "\t\n " = f xs+ | otherwise = False++ where f "" = True+ f (y:ys) | y `elem` "\t\n " = f ys+ | otherwise = False+++clearFirstQXXLineBreak :: String -> String+clearFirstQXXLineBreak "" = ""+clearFirstQXXLineBreak s@(x:xs) | x `elem` "\t\n " = cutOff xs+ | otherwise = s+ where cutOff "" = ""+ cutOff c@(y:ys) | y `elem` "\t\n " = cutOff ys+ | otherwise = c+++clearIndentAtStart :: String -> String+clearIndentAtStart "" = ""+clearIndentAtStart s@(x:xs) | x `elem` "\t " = clearIndentAtStart xs+ | otherwise = s+++makeExpr :: [StringPart] -> TH.ExpQ+makeExpr [] = [| mempty |]+makeExpr (Literal a : xs) =+ TH.appE [| mappend (fromString a) |] $ makeExpr xs+makeExpr (AntiQuote a : xs) =+ TH.appE [| mappend (toQQ $(reify a)) |] $ makeExpr xs+ where reify :: String -> TH.Q TH.Exp+ reify s = case parseExp s of+ Left e -> TH.reportError e >> [| mempty |]+ Right e -> return e
+ src/Text/InterpolatedString/QM/Internal/Parsers/TH.hs view
@@ -0,0 +1,184 @@+-- Fork of: https://github.com/audreyt/interpolatedstring-perl6/blob/63d91a83eb5e48740c87570a8c7fd4668afE6832/src/Text/InterpolatedString/Perl6.hs+-- Author of the 'interpolatedstring-perl6' package: Audrey Tang++{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE PackageImports #-}+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE LambdaCase #-}++module Text.InterpolatedString.QM.Internal.Parsers.TH (parserTpl) where++import "base" Control.Arrow ((&&&))+import qualified "template-haskell" Language.Haskell.TH as TH+import "template-haskell" Language.Haskell.TH ( Pat (ListP, ViewP)+ , Exp (ListE)+ )++-- local imports+import Text.InterpolatedString.QM.Internal.Parsers.Types (LineBreaks (..))+++data Decl++ = C (Bool, TH.Pat, TH.Exp)+ -- ^ 'C' means 'Conditional'.+ -- First value of tuple is condition to add pattern or not.++ | D (TH.Pat, TH.Exp)+ -- ^ 'D' means 'Declarative'.+ -- A pattern always will be added.++ deriving (Show, Eq)+++parserTpl :: String+ -- ^ Parser name+ -> Bool+ -- ^ Enable interpolation+ -> LineBreaks+ -> TH.DecsQ+parserTpl (TH.mkName &&& varE -> (n, fE)) withInterpolation lineBreaks = return++ [ TH.SigD n (TH.ConT $ TH.mkName "Parser") -- Type annotation for parser+ , TH.FunD n decls -- All patterns to match+ ]++ -- About naming variables:+ -- Suffixes (where `foo` is a variable name):+ -- * `fooP` means Pattern+ -- * `fooE` means Expression+ -- Variables:+ -- * `fE` - Quoter-parser's name (like `parseQM`), for recursive calls+ -- * `aE` - Result accumulator, defined for each pattern, like:+ -- `parseQM a …` where `…` is pattern and body+ -- For each from `decls` this prefix shown above+ -- is aproduced by `f` helper.+ -- For instance first pattern would be:+ -- `parseQM a [] = [Literal (reverse a)]`+ -- * `f` - Helper to prefix each pattern with `parseQM a`+ -- where `parseQM` is a name of parser from first argument.+ -- `apps` produces Expression,+ -- multiple function application with variate arity.+ where++ decls =++ map (uncurry f) $+ map (\case C (_, x, y) -> (x, y) ; D x -> x ) $+ filter (\case C (x, _, _) -> x ; D _ -> True)++ [ D ( ListP []+ , ListE [apps [conE "Literal", apps [varE "reverse", aE]]]+ )++ , C ( lineBreaks `elem` [KeepLineBreaks, ReplaceLineBreaksWithSpaces]+ , ViewP (varE "clearLastQXXLineBreak") $ conP "True" []+ , apps [fE, aE, strE ""]+ )++ , D ( consP [chrP '\\', chrP '\\', varP "xs"]+ , apps [fE, consE [chrE '\\', aE], varE "xs"]+ )++ , C ( withInterpolation+ , consP [chrP '\\', chrP '{', varP "xs"]+ , apps [fE, consE [chrE '{', aE], varE "xs"]+ )++ , D ( consP [chrP '\\', chrP ' ', varP "xs"]+ , apps [fE, consE [chrE ' ', aE], varE "xs"]+ )++ , C ( lineBreaks == IgnoreLineBreaks+ , consP [chrP '\\', chrP '\n', varP "xs"]+ , apps [fE, aE, consE [chrE '\n', varE "xs"]]+ )++ -- Explicitly cutting off line breaks+ , C ( lineBreaks `elem` [KeepLineBreaks, ReplaceLineBreaksWithSpaces]+ , consP [chrP '\\', chrP '\n', varP "xs"]++ , let cutOffFakeLnOrUseXS maybeVal =+ apps [varE "maybe", varE "xs", varE "tail", maybeVal]++ clearNextLineIndentFromXS =+ -- Fake '\n' here to make `clearIndentAtSOF` works for this+ apps [varE "clearIndentAtSOF", consE [chrE '\n', varE "xs"]]++ in -- Recursively do stuff+ apps [fE, aE, cutOffFakeLnOrUseXS clearNextLineIndentFromXS]+ )++ , D ( consP [chrP '\\', chrP 'n', varP "xs"]+ , apps [fE, consE [chrE '\n', aE], varE "xs"]+ )++ , D ( consP [chrP '\\', chrP '\t', varP "xs"]+ , apps [fE, consE [chrE '\t', aE], varE "xs"]+ )++ , D ( consP [chrP '\\', chrP 't', varP "xs"]+ , apps [fE, consE [chrE '\t', aE], varE "xs"]+ )++ , D ( strP "\\"+ , apps [fE, consE [chrE '\\', aE], strE ""]+ )++ , C ( withInterpolation+ , consP [chrP '{', varP "xs"]+ , consE [ apps [conE "Literal", apps [varE "reverse", aE]]+ , apps [varE "unQX", fE, strE "", varE "xs"]+ ]+ )++ , D ( ViewP (varE "clearIndentAtSOF") $ conP "Just" [varP "clean"]+ , apps [fE, aE, varE "clean"]+ )++ , D ( ViewP (varE "clearIndentTillEOF") $ conP "Just" [varP "clean"]+ , apps [fE, aE, varE "clean"]+ )++ -- Cutting off line breaks+ , C ( lineBreaks == IgnoreLineBreaks+ , consP [chrP '\n', varP "xs"]+ , apps [fE, aE, varE "xs"]+ )++ -- Replacing line breaks with spaces+ , C ( lineBreaks == ReplaceLineBreaksWithSpaces+ , consP [chrP '\n', varP "xs"]+ , apps [fE, consE [chrE ' ', aE], varE "xs"]+ )++ , D ( consP [varP "x", varP "xs"]+ , apps [fE, consE [varE "x", aE], varE "xs"]+ )+ ]++ aE = varE "a"+ f pat body = TH.Clause [varP "a", pat] (TH.NormalB body) []++ apps [x] = x+ apps (x:y:zs) = apps $ TH.AppE x y : zs+ apps [] = error "apps []"++ consP [x] = x+ consP (x:y:zs) = consP $ TH.UInfixP x (TH.mkName ":") y : zs+ consP [] = error "consP []"++ consE [x] = x+ consE (x:y:zs) = consE $ TH.UInfixE x (conE ":") y : zs+ consE [] = error "consE []"+++varP :: String -> TH.Pat ; varP = TH.VarP . TH.mkName+varE :: String -> TH.Exp ; varE = TH.VarE . TH.mkName+conP :: String -> [TH.Pat] -> TH.Pat ; conP = TH.ConP . TH.mkName+conE :: String -> TH.Exp ; conE = TH.ConE . TH.mkName++chrP :: Char -> TH.Pat ; chrP = TH.LitP . TH.CharL+chrE :: Char -> TH.Exp ; chrE = TH.LitE . TH.CharL+strP :: String -> TH.Pat ; strP = TH.LitP . TH.StringL+strE :: String -> TH.Exp ; strE = TH.LitE . TH.StringL
+ src/Text/InterpolatedString/QM/Internal/Parsers/Types.hs view
@@ -0,0 +1,19 @@+-- Fork of: https://github.com/audreyt/interpolatedstring-perl6/blob/63d91a83eb5e48740c87570a8c7fd4668afe6832/src/Text/InterpolatedString/Perl6.hs+-- Author of the 'interpolatedstring-perl6' package: Audrey Tang++module Text.InterpolatedString.QM.Internal.Parsers.Types+ ( Parser+ , StringPart (..)+ , LineBreaks (..)+ ) where+++type Parser = String -> String -> [StringPart]++data LineBreaks+ = IgnoreLineBreaks+ | KeepLineBreaks+ | ReplaceLineBreaksWithSpaces+ deriving (Show, Eq)++data StringPart = Literal String | AntiQuote String deriving Show
+ src/Text/InterpolatedString/QM/ShowQ/Class.hs view
@@ -0,0 +1,42 @@+-- Fork of: https://github.com/audreyt/interpolatedstring-perl6/blob/63d91a83eb5e48740c87570a8c7fd4668afe6832/src/Text/InterpolatedString/Perl6.hs+-- Author of the 'interpolatedstring-perl6' package: Audrey Tang++{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE IncoherentInstances #-}+{-# LANGUAGE FlexibleInstances #-}++{-# LANGUAGE PackageImports #-}++module Text.InterpolatedString.QM.ShowQ.Class (ShowQ (..)) where++import "bytestring" Data.ByteString.Char8 as Strict (ByteString, unpack)+import "bytestring" Data.ByteString.Lazy.Char8 as Lazy (ByteString, unpack)+import "text" Data.Text as T (Text, unpack)+import "text" Data.Text.Lazy as LazyT (Text, unpack)+++class ShowQ a where+ showQ :: a -> String++instance ShowQ Char where+ showQ = (:[])++instance ShowQ String where+ showQ = id++instance ShowQ Strict.ByteString where+ showQ = Strict.unpack++instance ShowQ Lazy.ByteString where+ showQ = Lazy.unpack++instance ShowQ T.Text where+ showQ = T.unpack++instance ShowQ LazyT.Text where+ showQ = LazyT.unpack++instance Show a => ShowQ a where+ showQ = show
+ test/LineBreaks/CRLF/QM/Spec.hs view
@@ -0,0 +1,161 @@+-- This file automatically generated by generate-cr-and-crlf-tests.sh (do not modify!) +{-# LANGUAGE PackageImports #-} +{-# LANGUAGE QuasiQuotes #-} + +module LineBreaks.CRLF.QM.Spec (spec) where + +import "hspec" Test.Hspec (Spec, describe, it, shouldBe) + +-- local imports +import "qm-interpolated-string" Text.InterpolatedString.QM (qm) + + +spec :: Spec +spec = do + + describe "Examples from README" $ do + + it "First (decorative spacing and escaping space symbol)" $ + [qm| hello world, + \ what's going on here? |] + `shouldBe` "hello world, what's going on here?" + + it "Second (merging lines without spaces)" $ + [qm| + it's actual + ly ignored + |] + `shouldBe` "it's actually ignored" + + it "Third (explicit line breaks symbols)" $ + [qm| \ You could explicitly escape indentation or\n + line breaks when you really need it! \ + |] `shouldBe` " You could explicitly escape indentation or\n\ + \line breaks when you really need it! " + + it "Fourth (escaping interpolation blocks to show them as text)" $ + [qm| {1+2} \{3+4} |] `shouldBe` "3 {3+4}" + + it "Type annotation in interpolation block" $ + [qm|{10 :: Float}|] `shouldBe` "10.0" + + it "Escaping interpolation symbols inside interpolation block" $ do + [qm|foo {"b{a{r"} baz|] `shouldBe` "foo b{a{r baz" + [qm|foo {"b\}a\}r"} baz|] `shouldBe` "foo b}a}r baz" + + it "Example from generated docs" $ [qm| foo {'b':'a':'r':""} + \ baz |] `shouldBe` "foo bar baz" + + it "Escaping backslashes" $ do [qm| foo\bar |] `shouldBe` "foo\\bar" + [qm| foo\\bar |] `shouldBe` "foo\\bar" + [qm| foo\\\bar |] `shouldBe` "foo\\\\bar" + [qm| foo\\\\bar |] `shouldBe` "foo\\\\bar" + + it "Empty string" $ [qm| |] `shouldBe` "" + + it "Escaping space by slash at EOL after space" $ + [qm| foo \ + bar |] `shouldBe` "foo bar" + + it "Escaped spaces at the edges" $ do [qm| foo\ |] `shouldBe` "foo " + [qm|\ foo |] `shouldBe` " foo" + + describe "Tabs as indentation" $ do + + it "Tabs is only indentation at left side" $ do + [qm| + foo bar baz + |] `shouldBe` "foo bar baz" + + [qm| foo bar baz|] `shouldBe` "foo bar baz" + + it "Tabs also at EOL" $ do + [qm| + foo bar baz + |] `shouldBe` "foo bar baz" + + [qm| foo bar baz |] `shouldBe` "foo bar baz" + + it "Escaped tabs" $ do + [qm| \tfoo|] `shouldBe` "\tfoo" + [qm| \ foo |] `shouldBe` "\tfoo" + [qm| foo \ |] `shouldBe` "foo\t\t\t" + [qm| foo \ |] `shouldBe` "foo\t\t" + [qm| foo\ |] `shouldBe` "foo\t" + + it "Tails" $ do + [qm| + foo + |] `shouldBe` "foo" + [qm| + + foo + + + |] `shouldBe` "foo" + [qm| + foo + + |] `shouldBe` "foo" + + describe "New README examples" $ do + + it "Simple usage example" $ do + let title = "Testing" + text = "Some testing text" + [qm| + <article> + <h1>{title}</h1> + <p>{text}</p> + </article> + |] + `shouldBe` + "<article><h1>Testing</h1><p>Some testing text</p></article>" + + it "Can escape spaces" $ + [qm| you can escape spaces + \ when you need them |] + `shouldBe` + "you can escape spaces when you need them" + + it "Indentation and line breaks are ignored" $ + [qm| + indentation and li + ne bre + aks are i + gno + red + |] + `shouldBe` "indentation and line breaks are ignored" + + it "Escaping indentation or line breaks" $ + [qm| \ You can escape indentation or\n + line breaks when you need them! \ |] + `shouldBe` + " You can escape indentation or\nline breaks when you need them! " + + it "Interpolation blocks can be escaped too" $ + [qm| Interpolation blocks can be escaped too: {1+2} \{3+4} |] + `shouldBe` + "Interpolation blocks can be escaped too: 3 {3+4}" + + it "Interpolation" $ [qm| foo {1+2} |] `shouldBe` "foo 3" + + it "Haddock example" $ + [qm| foo {'b':'a':'r':""} + \ baz |] `shouldBe` "foo bar baz" + + it "Escaping backslash itself when it makes sense" $ do + [qm| foo\nbar |] `shouldBe` "foo\nbar" + [qm| foo\\nbar |] `shouldBe` "foo\\nbar" + [qm| foo\tbar |] `shouldBe` "foo\tbar" + [qm| foo\\tbar |] `shouldBe` "foo\\tbar" + [qm| foo\ bar |] `shouldBe` "foo\tbar" + [qm| foo\\ bar |] `shouldBe` "foo\\\tbar" + [qm| foo\ bar |] `shouldBe` "foo bar" + [qm| foo\\ bar |] `shouldBe` "foo\\ bar" + + [qm| foo\ + bar |] `shouldBe` "foobar" + [qm| foo\\ + bar |] `shouldBe` "foo\\bar"
+ test/LineBreaks/CRLF/QMB/Spec.hs view
@@ -0,0 +1,156 @@+-- This file automatically generated by generate-cr-and-crlf-tests.sh (do not modify!) +{-# LANGUAGE PackageImports #-} +{-# LANGUAGE QuasiQuotes #-} + +module LineBreaks.CRLF.QMB.Spec (spec) where + +import "hspec" Test.Hspec (Spec, describe, it, shouldBe) + +-- local imports +import "qm-interpolated-string" Text.InterpolatedString.QM (qmb) + + +spec :: Spec +spec = do + + it "Works as expected" $ + [qmb| + foo + {1+2} + bar + |] `shouldBe` "foo\n3\nbar" + + it "Explicitly cutting off line breaks" $ do + [qmb| + foo\ + {1+2}\ + bar\ + baz + |] `shouldBe` "foo3barbaz" + [qmb| + foo\ + {1+2}\ + bar\ + baz\ + |] `shouldBe` "foo3barbaz" + + describe "Examples from README" $ do + + it "First (decorative spacing and escaping space symbol)" $ + [qmb| hello world, + \ what's going on here? |] + `shouldBe` "hello world,\n what's going on here?" + + it "Second (breaking lines)" $ + [qmb| + it's actual + ly NOT ignored + |] + `shouldBe` "it's actual\nly NOT ignored" + + it "Third (explicit line breaks symbols)" $ + [qmb| \ You could explicitly escape indentation or\n + line breaks when you really need it! \ + |] `shouldBe` " You could explicitly escape indentation or\n\n\ + \line breaks when you really need it! " + + it "Fourth (escaping interpolation blocks to show them as text)" $ + [qmb| {1+2} \{3+4} |] `shouldBe` "3 {3+4}" + + it "Type annotation in interpolation block" $ + [qmb|{10 :: Float}|] `shouldBe` "10.0" + + it "Escaping interpolation symbols inside interpolation block" $ do + [qmb|foo {"b{a{r"} baz|] `shouldBe` "foo b{a{r baz" + [qmb|foo {"b\}a\}r"} baz|] `shouldBe` "foo b}a}r baz" + + it "Example from generated docs" $ [qmb| foo {'b':'a':'r':""} + \ baz |] `shouldBe` "foo bar\n baz" + + it "Escaping backslashes" $ do [qmb| foo\bar |] `shouldBe` "foo\\bar" + [qmb| foo\\bar |] `shouldBe` "foo\\bar" + [qmb| foo\\\bar |] `shouldBe` "foo\\\\bar" + [qmb| foo\\\\bar |] `shouldBe` "foo\\\\bar" + + it "Empty string" $ [qmb| |] `shouldBe` "" + + it "Escaping space by backslash at EOL after space (line break is cutted off)" $ + [qmb| foo \ + bar |] `shouldBe` "foo bar" + + it "Escaped spaces at the edges" $ do [qmb| foo\ |] `shouldBe` "foo " + [qmb|\ foo |] `shouldBe` " foo" + + describe "Tabs as indentation" $ do + + it "Tabs is only indentation at left side" $ do + [qmb| + foo bar baz + |] `shouldBe` "foo bar baz" + + [qmb| foo bar baz|] `shouldBe` "foo bar baz" + + it "Tabs also at EOL" $ do + [qmb| + foo bar baz + |] `shouldBe` "foo bar baz" + + [qmb| foo bar baz |] `shouldBe` "foo bar baz" + + it "Escaped tabs" $ do + [qmb| \tfoo|] `shouldBe` "\tfoo" + [qmb| \ foo |] `shouldBe` "\tfoo" + [qmb| foo \ |] `shouldBe` "foo\t\t\t" + [qmb| foo \ |] `shouldBe` "foo\t\t" + [qmb| foo\ |] `shouldBe` "foo\t" + + it "Tails" $ do + [qmb| + foo + |] `shouldBe` "foo" + [qmb| + + foo + + + |] `shouldBe` "foo" + [qmb| + foo + + |] `shouldBe` "foo" + + describe "New README examples" $ do + + it "Simple usage example" $ do + let title = "Testing" + text = "Some testing text" + [qmb| + <article> + <h1>{title}</h1> + <p>{text}</p> + </article> + |] + `shouldBe` + "<article>\n<h1>Testing</h1>\n<p>Some testing text</p>\n</article>" + + it "Interpolation" $ [qmb| foo {1+2} |] `shouldBe` "foo 3" + + it "Haddock example" $ + [qmb| foo + {'b':'a':'r':""} + baz |] `shouldBe` "foo\nbar\nbaz" + + it "Escaping backslash itself when it makes sense" $ do + [qmb| foo\nbar |] `shouldBe` "foo\nbar" + [qmb| foo\\nbar |] `shouldBe` "foo\\nbar" + [qmb| foo\tbar |] `shouldBe` "foo\tbar" + [qmb| foo\\tbar |] `shouldBe` "foo\\tbar" + [qmb| foo\ bar |] `shouldBe` "foo\tbar" + [qmb| foo\\ bar |] `shouldBe` "foo\\\tbar" + [qmb| foo\ bar |] `shouldBe` "foo bar" + [qmb| foo\\ bar |] `shouldBe` "foo\\ bar" + + [qmb| foo\ + bar |] `shouldBe` "foobar" + [qmb| foo\\ + bar |] `shouldBe` "foo\\\nbar"
+ test/LineBreaks/CRLF/QMS/Spec.hs view
@@ -0,0 +1,162 @@+-- This file automatically generated by generate-cr-and-crlf-tests.sh (do not modify!) +{-# LANGUAGE PackageImports #-} +{-# LANGUAGE QuasiQuotes #-} + +module LineBreaks.CRLF.QMS.Spec (spec) where + +import "hspec" Test.Hspec (Spec, describe, it, shouldBe) + +-- local imports +import "qm-interpolated-string" Text.InterpolatedString.QM (qms) + + +spec :: Spec +spec = do + + it "Works as expected" $ + [qms| + foo + {1+2} + bar + |] `shouldBe` "foo 3 bar" + + it "Explicitly cutting off line breaks" $ do + [qms| + foo\ + {1+2}\ + bar\ + baz + |] `shouldBe` "foo3barbaz" + [qms| + foo\ + {1+2}\ + bar\ + baz\ + |] `shouldBe` "foo3barbaz" + + describe "Examples from README" $ do + + it "First (decorative spacing and escaping space symbol)" $ + [qms| hello world, + \ what's going on here? |] + `shouldBe` "hello world, what's going on here?" + + it "Second (breaking lines)" $ + [qms| + it's actual + ly NOT ignored + |] + `shouldBe` "it's actual ly NOT ignored" + + it "Third (explicit line breaks symbols)" $ + [qms| \ You could explicitly escape indentation or\n + line breaks when you really need it! \ + |] `shouldBe` " You could explicitly escape indentation or\n \ + \line breaks when you really need it! " + + it "Fourth (escaping interpolation blocks to show them as text)" $ + [qms| {1+2} \{3+4} |] `shouldBe` "3 {3+4}" + + it "Type annotation in interpolation block" $ + [qms|{10 :: Float}|] `shouldBe` "10.0" + + it "Escaping interpolation symbols inside interpolation block" $ do + [qms|foo {"b{a{r"} baz|] `shouldBe` "foo b{a{r baz" + [qms|foo {"b\}a\}r"} baz|] `shouldBe` "foo b}a}r baz" + + it "Example from generated docs" $ [qms| foo {'b':'a':'r':""} + \ baz |] `shouldBe` "foo bar baz" + + it "Escaping backslashes" $ do [qms| foo\bar |] `shouldBe` "foo\\bar" + [qms| foo\\bar |] `shouldBe` "foo\\bar" + [qms| foo\\\bar |] `shouldBe` "foo\\\\bar" + [qms| foo\\\\bar |] `shouldBe` "foo\\\\bar" + + it "Empty string" $ [qms| |] `shouldBe` "" + + it "Escaping space by backslash at EOL after space (line break is cutted off)" $ + [qms| foo \ + bar |] `shouldBe` "foo bar" + + it "Escaped spaces at the edges" $ do [qms| foo\ |] `shouldBe` "foo " + [qms|\ foo |] `shouldBe` " foo" + + describe "Tabs as indentation" $ do + + it "Tabs is only indentation at left side" $ do + [qms| + foo bar baz + |] `shouldBe` "foo bar baz" + + [qms| foo bar baz|] `shouldBe` "foo bar baz" + + it "Tabs also at EOL" $ do + [qms| + foo bar baz + |] `shouldBe` "foo bar baz" + + [qms| foo bar baz |] `shouldBe` "foo bar baz" + + it "Escaped tabs" $ do + [qms| \tfoo|] `shouldBe` "\tfoo" + [qms| \ foo |] `shouldBe` "\tfoo" + [qms| foo \ |] `shouldBe` "foo\t\t\t" + [qms| foo \ |] `shouldBe` "foo\t\t" + [qms| foo\ |] `shouldBe` "foo\t" + + it "Tails" $ do + [qms| + foo + |] `shouldBe` "foo" + [qms| + + foo + + + |] `shouldBe` "foo" + [qms| + foo + + |] `shouldBe` "foo" + + describe "New README examples" $ do + + it "First example" $ + [qms| Hello, + world! + Pi is {floor pi}.{floor $ (pi - 3) * 100}… |] + `shouldBe` "Hello, world! Pi is 3.14…" + + it "Simple usage example" $ do + let title = "Testing" + text = "Some testing text" + [qms| + <article> + <h1>{title}</h1> + <p>{text}</p> + </article> + |] + `shouldBe` + "<article> <h1>Testing</h1> <p>Some testing text</p> </article>" + + it "Interpolation" $ [qms| foo {1+2} |] `shouldBe` "foo 3" + + it "Haddock example" $ + [qms| foo + {'b':'a':'r':""} + baz |] `shouldBe` "foo bar baz" + + it "Escaping backslash itself when it makes sense" $ do + [qms| foo\nbar |] `shouldBe` "foo\nbar" + [qms| foo\\nbar |] `shouldBe` "foo\\nbar" + [qms| foo\tbar |] `shouldBe` "foo\tbar" + [qms| foo\\tbar |] `shouldBe` "foo\\tbar" + [qms| foo\ bar |] `shouldBe` "foo\tbar" + [qms| foo\\ bar |] `shouldBe` "foo\\\tbar" + [qms| foo\ bar |] `shouldBe` "foo bar" + [qms| foo\\ bar |] `shouldBe` "foo\\ bar" + + [qms| foo\ + bar |] `shouldBe` "foobar" + [qms| foo\\ + bar |] `shouldBe` "foo\\ bar"
+ test/LineBreaks/CRLF/QN/Spec.hs view
@@ -0,0 +1,134 @@+-- This file automatically generated by generate-cr-and-crlf-tests.sh (do not modify!) +{-# LANGUAGE PackageImports #-} +{-# LANGUAGE QuasiQuotes #-} + +module LineBreaks.CRLF.QN.Spec (spec) where + +import "hspec" Test.Hspec (Spec, describe, it, shouldBe) + +-- local imports +import "qm-interpolated-string" Text.InterpolatedString.QM (qn) + + +spec :: Spec +spec = do + + describe "Examples from README" $ do + + it "First (decorative spacing and escaping space symbol)" $ + [qn| hello world, + \ what's going on here? |] + `shouldBe` "hello world, what's going on here?" + + it "Second (merging lines without spaces)" $ + [qn| + it's actual + ly ignored + |] + `shouldBe` "it's actually ignored" + + it "Third (explicit line breaks symbols)" $ + [qn| \ You could explicitly escape indentation or\n + line breaks when you really need it! \ + |] `shouldBe` " You could explicitly escape indentation or\n\ + \line breaks when you really need it! " + + it "Fourth (escaping interpolation blocks to show them as text)" $ + [qn| {1+2} \{3+4} |] `shouldBe` "{1+2} \\{3+4}" + + it "Example of `qn` QuasiQuoter" $ + [qn| foo {1+2} |] `shouldBe` "foo {1+2}" + + it "Type annotation in interpolation block" $ + [qn|{10 :: Float}|] `shouldBe` "{10 :: Float}" + + it "Escaping interpolation symbols inside interpolation block" $ do + [qn|foo {"b{a{r"} baz|] `shouldBe` "foo {\"b{a{r\"} baz" + [qn|foo {"b\}a\}r"} baz|] `shouldBe` "foo {\"b\\}a\\}r\"} baz" + + it "Example from generated docs" $ + [qn| foo {'b':'a':'r':""} + \ baz |] `shouldBe` "foo {'b':'a':'r':\"\"} baz" + + it "Escaping backslashes" $ do [qn| foo\bar |] `shouldBe` "foo\\bar" + [qn| foo\\bar |] `shouldBe` "foo\\bar" + [qn| foo\\\bar |] `shouldBe` "foo\\\\bar" + [qn| foo\\\\bar |] `shouldBe` "foo\\\\bar" + + it "Empty string" $ [qn| |] `shouldBe` "" + + it "Escaping space by slash at EOL after space" $ + [qn| foo \ + bar |] `shouldBe` "foo bar" + + it "Escaped spaces at the edges" $ do [qn| foo\ |] `shouldBe` "foo " + [qn|\ foo |] `shouldBe` " foo" + + describe "Tabs as indentation" $ do + + it "Tabs is only indentation at left side" $ do + [qn| + foo bar baz + |] `shouldBe` "foo bar baz" + + [qn| foo bar baz|] `shouldBe` "foo bar baz" + + it "Tabs also at EOL" $ do + [qn| + foo bar baz + |] `shouldBe` "foo bar baz" + + [qn| foo bar baz |] `shouldBe` "foo bar baz" + + it "Escaped tabs" $ do + [qn| \tfoo|] `shouldBe` "\tfoo" + [qn| \ foo |] `shouldBe` "\tfoo" + [qn| foo \ |] `shouldBe` "foo\t\t\t" + [qn| foo \ |] `shouldBe` "foo\t\t" + [qn| foo\ |] `shouldBe` "foo\t" + + it "Tails" $ do + [qn| + foo + |] `shouldBe` "foo" + [qn| + + foo + + + |] `shouldBe` "foo" + [qn| + foo + + |] `shouldBe` "foo" + + describe "New README examples" $ do + + it "Simple usage example" $ do + [qn| + <article> + <h1>{title}</h1> + <p>{text}</p> + </article> + |] `shouldBe` "<article><h1>{title}</h1><p>{text}</p></article>" + + it "Interpolation" $ [qn| foo {1+2} |] `shouldBe` "foo {1+2}" + + it "Haddock example" $ + [qn| foo {'b':'a':'r':""} + \ baz |] `shouldBe` "foo {'b':'a':'r':\"\"} baz" + + it "Escaping backslash itself when it makes sense" $ do + [qn| foo\nbar |] `shouldBe` "foo\nbar" + [qn| foo\\nbar |] `shouldBe` "foo\\nbar" + [qn| foo\tbar |] `shouldBe` "foo\tbar" + [qn| foo\\tbar |] `shouldBe` "foo\\tbar" + [qn| foo\ bar |] `shouldBe` "foo\tbar" + [qn| foo\\ bar |] `shouldBe` "foo\\\tbar" + [qn| foo\ bar |] `shouldBe` "foo bar" + [qn| foo\\ bar |] `shouldBe` "foo\\ bar" + + [qn| foo\ + bar |] `shouldBe` "foobar" + [qn| foo\\ + bar |] `shouldBe` "foo\\bar"
+ test/LineBreaks/CRLF/QNB/Spec.hs view
@@ -0,0 +1,158 @@+-- This file automatically generated by generate-cr-and-crlf-tests.sh (do not modify!) +{-# LANGUAGE PackageImports #-} +{-# LANGUAGE QuasiQuotes #-} + +module LineBreaks.CRLF.QNB.Spec (spec) where + +import "hspec" Test.Hspec (Spec, describe, it, shouldBe) + +-- local imports +import "qm-interpolated-string" Text.InterpolatedString.QM (qnb) + + +spec :: Spec +spec = do + + it "Works as expected" $ + [qnb| + foo + {1+2} + bar + |] `shouldBe` "foo\n{1+2}\nbar" + + it "Explicitly cutting off line breaks" $ do + [qnb| + foo\ + {1+2}\ + bar\ + baz + |] `shouldBe` "foo{1+2}barbaz" + [qnb| + foo\ + {1+2}\ + bar\ + baz\ + |] `shouldBe` "foo{1+2}barbaz" + + describe "Examples from README" $ do + + it "First (decorative spacing and escaping space symbol)" $ + [qnb| hello world, + \ what's going on here? |] + `shouldBe` "hello world,\n what's going on here?" + + it "Second (breaking lines)" $ + [qnb| + it's actual + ly NOT ignored + |] + `shouldBe` "it's actual\nly NOT ignored" + + it "Third (explicit line breaks symbols, line break plus space)" $ + [qnb| \ You could explicitly escape indentation or\n + line breaks when you really need it! \ + |] `shouldBe` " You could explicitly escape indentation or\n\n\ + \line breaks when you really need it! " + + it "Fourth (escaping interpolation blocks to show them as text)" $ + [qnb| {1+2} \{3+4} |] `shouldBe` "{1+2} \\{3+4}" + + it "Example of `qnb` QuasiQuoter" $ + [qnb| foo {1+2} |] `shouldBe` "foo {1+2}" + + it "Type annotation in interpolation block" $ + [qnb|{10 :: Float}|] `shouldBe` "{10 :: Float}" + + it "Escaping interpolation symbols inside interpolation block" $ do + [qnb|foo {"b{a{r"} baz|] `shouldBe` "foo {\"b{a{r\"} baz" + [qnb|foo {"b\}a\}r"} baz|] `shouldBe` "foo {\"b\\}a\\}r\"} baz" + + it "Example from generated docs (double-space)" $ + [qnb| foo {'b':'a':'r':""} + \ baz |] `shouldBe` "foo {'b':'a':'r':\"\"}\n baz" + + it "Escaping backslashes" $ do [qnb| foo\bar |] `shouldBe` "foo\\bar" + [qnb| foo\\bar |] `shouldBe` "foo\\bar" + [qnb| foo\\\bar |] `shouldBe` "foo\\\\bar" + [qnb| foo\\\\bar |] `shouldBe` "foo\\\\bar" + + it "Empty string" $ [qnb| |] `shouldBe` "" + + it "Escaping space by backslash at EOL after space (line break is cutted off)" $ + [qnb| foo \ + bar |] `shouldBe` "foo bar" + + it "Escaped spaces at the edges" $ do [qnb| foo\ |] `shouldBe` "foo " + [qnb|\ foo |] `shouldBe` " foo" + + describe "Tabs as indentation" $ do + + it "Tabs is only indentation at left side" $ do + [qnb| + foo bar baz + |] `shouldBe` "foo bar baz" + + [qnb| foo bar baz|] `shouldBe` "foo bar baz" + + it "Tabs also at EOL" $ do + [qnb| + foo bar baz + |] `shouldBe` "foo bar baz" + + [qnb| foo bar baz |] `shouldBe` "foo bar baz" + + it "Escaped tabs" $ do + [qnb| \tfoo|] `shouldBe` "\tfoo" + [qnb| \ foo |] `shouldBe` "\tfoo" + [qnb| foo \ |] `shouldBe` "foo\t\t\t" + [qnb| foo \ |] `shouldBe` "foo\t\t" + [qnb| foo\ |] `shouldBe` "foo\t" + + it "Tails" $ do + [qnb| + foo + |] `shouldBe` "foo" + [qnb| + + foo + + + |] `shouldBe` "foo" + [qnb| + foo + + |] `shouldBe` "foo" + + describe "New README examples" $ do + + it "Simple usage example" $ do + [qnb| + <article> + <h1>{title}</h1> + <p>{text}</p> + </article> + |] + `shouldBe` + "<article>\n<h1>{title}</h1>\n<p>{text}</p>\n</article>" + + it "Interpolation" $ [qnb| foo {1+2} |] `shouldBe` "foo {1+2}" + + it "Haddock example" $ + [qnb| foo + {'b':'a':'r':""} + baz |] `shouldBe` "foo\n{'b':'a':'r':\"\"}\nbaz" + + it "Escaping backslash itself when it makes sense" $ do + [qnb| foo\nbar |] `shouldBe` "foo\nbar" + [qnb| foo\\nbar |] `shouldBe` "foo\\nbar" + [qnb| foo\tbar |] `shouldBe` "foo\tbar" + [qnb| foo\\tbar |] `shouldBe` "foo\\tbar" + [qnb| foo\ bar |] `shouldBe` "foo\tbar" + [qnb| foo\\ bar |] `shouldBe` "foo\\\tbar" + [qnb| foo\ bar |] `shouldBe` "foo bar" + [qnb| foo\\ bar |] `shouldBe` "foo\\ bar" + + [qnb| foo\ + bar |] `shouldBe` "foobar" + [qnb| foo\\ + bar |] `shouldBe` "foo\\\nbar"
+ test/LineBreaks/CRLF/QNS/Spec.hs view
@@ -0,0 +1,158 @@+-- This file automatically generated by generate-cr-and-crlf-tests.sh (do not modify!) +{-# LANGUAGE PackageImports #-} +{-# LANGUAGE QuasiQuotes #-} + +module LineBreaks.CRLF.QNS.Spec (spec) where + +import "hspec" Test.Hspec (Spec, describe, it, shouldBe) + +-- local imports +import "qm-interpolated-string" Text.InterpolatedString.QM (qns) + + +spec :: Spec +spec = do + + it "Works as expected" $ + [qns| + foo + {1+2} + bar + |] `shouldBe` "foo {1+2} bar" + + it "Explicitly cutting off line breaks" $ do + [qns| + foo\ + {1+2}\ + bar\ + baz + |] `shouldBe` "foo{1+2}barbaz" + [qns| + foo\ + {1+2}\ + bar\ + baz\ + |] `shouldBe` "foo{1+2}barbaz" + + describe "Examples from README" $ do + + it "First (decorative spacing and escaping space symbol)" $ + [qns| hello world, + \ what's going on here? |] + `shouldBe` "hello world, what's going on here?" + + it "Second (breaking lines)" $ + [qns| + it's actual + ly NOT ignored + |] + `shouldBe` "it's actual ly NOT ignored" + + it "Third (explicit line breaks symbols, line break plus space)" $ + [qns| \ You could explicitly escape indentation or\n + line breaks when you really need it! \ + |] `shouldBe` " You could explicitly escape indentation or\n \ + \line breaks when you really need it! " + + it "Fourth (escaping interpolation blocks to show them as text)" $ + [qns| {1+2} \{3+4} |] `shouldBe` "{1+2} \\{3+4}" + + it "Example of `qns` QuasiQuoter" $ + [qns| foo {1+2} |] `shouldBe` "foo {1+2}" + + it "Type annotation in interpolation block" $ + [qns|{10 :: Float}|] `shouldBe` "{10 :: Float}" + + it "Escaping interpolation symbols inside interpolation block" $ do + [qns|foo {"b{a{r"} baz|] `shouldBe` "foo {\"b{a{r\"} baz" + [qns|foo {"b\}a\}r"} baz|] `shouldBe` "foo {\"b\\}a\\}r\"} baz" + + it "Example from generated docs (double-space)" $ + [qns| foo {'b':'a':'r':""} + \ baz |] `shouldBe` "foo {'b':'a':'r':\"\"} baz" + + it "Escaping backslashes" $ do [qns| foo\bar |] `shouldBe` "foo\\bar" + [qns| foo\\bar |] `shouldBe` "foo\\bar" + [qns| foo\\\bar |] `shouldBe` "foo\\\\bar" + [qns| foo\\\\bar |] `shouldBe` "foo\\\\bar" + + it "Empty string" $ [qns| |] `shouldBe` "" + + it "Escaping space by backslash at EOL after space (line break is cutted off)" $ + [qns| foo \ + bar |] `shouldBe` "foo bar" + + it "Escaped spaces at the edges" $ do [qns| foo\ |] `shouldBe` "foo " + [qns|\ foo |] `shouldBe` " foo" + + describe "Tabs as indentation" $ do + + it "Tabs is only indentation at left side" $ do + [qns| + foo bar baz + |] `shouldBe` "foo bar baz" + + [qns| foo bar baz|] `shouldBe` "foo bar baz" + + it "Tabs also at EOL" $ do + [qns| + foo bar baz + |] `shouldBe` "foo bar baz" + + [qns| foo bar baz |] `shouldBe` "foo bar baz" + + it "Escaped tabs" $ do + [qns| \tfoo|] `shouldBe` "\tfoo" + [qns| \ foo |] `shouldBe` "\tfoo" + [qns| foo \ |] `shouldBe` "foo\t\t\t" + [qns| foo \ |] `shouldBe` "foo\t\t" + [qns| foo\ |] `shouldBe` "foo\t" + + it "Tails" $ do + [qns| + foo + |] `shouldBe` "foo" + [qns| + + foo + + + |] `shouldBe` "foo" + [qns| + foo + + |] `shouldBe` "foo" + + describe "New README examples" $ do + + it "Simple usage example" $ do + [qns| + <article> + <h1>{title}</h1> + <p>{text}</p> + </article> + |] + `shouldBe` + "<article> <h1>{title}</h1> <p>{text}</p> </article>" + + it "Interpolation" $ [qns| foo {1+2} |] `shouldBe` "foo {1+2}" + + it "Haddock example" $ + [qns| foo + {'b':'a':'r':""} + baz |] `shouldBe` "foo {'b':'a':'r':\"\"} baz" + + it "Escaping backslash itself when it makes sense" $ do + [qns| foo\nbar |] `shouldBe` "foo\nbar" + [qns| foo\\nbar |] `shouldBe` "foo\\nbar" + [qns| foo\tbar |] `shouldBe` "foo\tbar" + [qns| foo\\tbar |] `shouldBe` "foo\\tbar" + [qns| foo\ bar |] `shouldBe` "foo\tbar" + [qns| foo\\ bar |] `shouldBe` "foo\\\tbar" + [qns| foo\ bar |] `shouldBe` "foo bar" + [qns| foo\\ bar |] `shouldBe` "foo\\ bar" + + [qns| foo\ + bar |] `shouldBe` "foobar" + [qns| foo\\ + bar |] `shouldBe` "foo\\ bar"
+ test/QM/Spec.hs view
@@ -0,0 +1,160 @@+{-# LANGUAGE PackageImports #-}+{-# LANGUAGE QuasiQuotes #-}++module QM.Spec (spec) where++import "hspec" Test.Hspec (Spec, describe, it, shouldBe)++-- local imports+import "qm-interpolated-string" Text.InterpolatedString.QM (qm)+++spec :: Spec+spec = do++ describe "Examples from README" $ do++ it "First (decorative spacing and escaping space symbol)" $+ [qm| hello world,+ \ what's going on here? |]+ `shouldBe` "hello world, what's going on here?"++ it "Second (merging lines without spaces)" $+ [qm|+ it's actual+ ly ignored+ |]+ `shouldBe` "it's actually ignored"++ it "Third (explicit line breaks symbols)" $+ [qm| \ You could explicitly escape indentation or\n+ line breaks when you really need it! \+ |] `shouldBe` " You could explicitly escape indentation or\n\+ \line breaks when you really need it! "++ it "Fourth (escaping interpolation blocks to show them as text)" $+ [qm| {1+2} \{3+4} |] `shouldBe` "3 {3+4}"++ it "Type annotation in interpolation block" $+ [qm|{10 :: Float}|] `shouldBe` "10.0"++ it "Escaping interpolation symbols inside interpolation block" $ do+ [qm|foo {"b{a{r"} baz|] `shouldBe` "foo b{a{r baz"+ [qm|foo {"b\}a\}r"} baz|] `shouldBe` "foo b}a}r baz"++ it "Example from generated docs" $ [qm| foo {'b':'a':'r':""}+ \ baz |] `shouldBe` "foo bar baz"++ it "Escaping backslashes" $ do [qm| foo\bar |] `shouldBe` "foo\\bar"+ [qm| foo\\bar |] `shouldBe` "foo\\bar"+ [qm| foo\\\bar |] `shouldBe` "foo\\\\bar"+ [qm| foo\\\\bar |] `shouldBe` "foo\\\\bar"++ it "Empty string" $ [qm| |] `shouldBe` ""++ it "Escaping space by slash at EOL after space" $+ [qm| foo \+ bar |] `shouldBe` "foo bar"++ it "Escaped spaces at the edges" $ do [qm| foo\ |] `shouldBe` "foo "+ [qm|\ foo |] `shouldBe` " foo"++ describe "Tabs as indentation" $ do++ it "Tabs is only indentation at left side" $ do+ [qm|+ foo bar baz+ |] `shouldBe` "foo bar baz"++ [qm| foo bar baz|] `shouldBe` "foo bar baz"++ it "Tabs also at EOL" $ do+ [qm|+ foo bar baz + |] `shouldBe` "foo bar baz"++ [qm| foo bar baz |] `shouldBe` "foo bar baz"++ it "Escaped tabs" $ do+ [qm| \tfoo|] `shouldBe` "\tfoo"+ [qm| \ foo |] `shouldBe` "\tfoo"+ [qm| foo \ |] `shouldBe` "foo\t\t\t"+ [qm| foo \ |] `shouldBe` "foo\t\t"+ [qm| foo\ |] `shouldBe` "foo\t"++ it "Tails" $ do+ [qm| + foo + |] `shouldBe` "foo"+ [qm| + + foo + + + |] `shouldBe` "foo"+ [qm| + foo + + |] `shouldBe` "foo"++ describe "New README examples" $ do++ it "Simple usage example" $ do+ let title = "Testing"+ text = "Some testing text"+ [qm|+ <article>+ <h1>{title}</h1>+ <p>{text}</p>+ </article>+ |]+ `shouldBe`+ "<article><h1>Testing</h1><p>Some testing text</p></article>"++ it "Can escape spaces" $+ [qm| you can escape spaces+ \ when you need them |]+ `shouldBe`+ "you can escape spaces when you need them"++ it "Indentation and line breaks are ignored" $ + [qm|+ indentation and li+ ne bre+ aks are i+ gno+ red+ |]+ `shouldBe` "indentation and line breaks are ignored"++ it "Escaping indentation or line breaks" $+ [qm| \ You can escape indentation or\n+ line breaks when you need them! \ |]+ `shouldBe`+ " You can escape indentation or\nline breaks when you need them! "++ it "Interpolation blocks can be escaped too" $+ [qm| Interpolation blocks can be escaped too: {1+2} \{3+4} |]+ `shouldBe`+ "Interpolation blocks can be escaped too: 3 {3+4}"++ it "Interpolation" $ [qm| foo {1+2} |] `shouldBe` "foo 3"++ it "Haddock example" $+ [qm| foo {'b':'a':'r':""}+ \ baz |] `shouldBe` "foo bar baz"++ it "Escaping backslash itself when it makes sense" $ do+ [qm| foo\nbar |] `shouldBe` "foo\nbar"+ [qm| foo\\nbar |] `shouldBe` "foo\\nbar"+ [qm| foo\tbar |] `shouldBe` "foo\tbar"+ [qm| foo\\tbar |] `shouldBe` "foo\\tbar"+ [qm| foo\ bar |] `shouldBe` "foo\tbar"+ [qm| foo\\ bar |] `shouldBe` "foo\\\tbar"+ [qm| foo\ bar |] `shouldBe` "foo bar"+ [qm| foo\\ bar |] `shouldBe` "foo\\ bar"++ [qm| foo\+ bar |] `shouldBe` "foobar"+ [qm| foo\\+ bar |] `shouldBe` "foo\\bar"
+ test/QMB/Spec.hs view
@@ -0,0 +1,155 @@+{-# LANGUAGE PackageImports #-}+{-# LANGUAGE QuasiQuotes #-}++module QMB.Spec (spec) where++import "hspec" Test.Hspec (Spec, describe, it, shouldBe)++-- local imports+import "qm-interpolated-string" Text.InterpolatedString.QM (qmb)+++spec :: Spec+spec = do++ it "Works as expected" $+ [qmb|+ foo+ {1+2}+ bar+ |] `shouldBe` "foo\n3\nbar"++ it "Explicitly cutting off line breaks" $ do+ [qmb|+ foo\+ {1+2}\+ bar\+ baz+ |] `shouldBe` "foo3barbaz"+ [qmb|+ foo\+ {1+2}\+ bar\+ baz\+ |] `shouldBe` "foo3barbaz"++ describe "Examples from README" $ do++ it "First (decorative spacing and escaping space symbol)" $+ [qmb| hello world,+ \ what's going on here? |]+ `shouldBe` "hello world,\n what's going on here?"++ it "Second (breaking lines)" $+ [qmb|+ it's actual+ ly NOT ignored+ |]+ `shouldBe` "it's actual\nly NOT ignored"++ it "Third (explicit line breaks symbols)" $+ [qmb| \ You could explicitly escape indentation or\n+ line breaks when you really need it! \+ |] `shouldBe` " You could explicitly escape indentation or\n\n\+ \line breaks when you really need it! "++ it "Fourth (escaping interpolation blocks to show them as text)" $+ [qmb| {1+2} \{3+4} |] `shouldBe` "3 {3+4}"++ it "Type annotation in interpolation block" $+ [qmb|{10 :: Float}|] `shouldBe` "10.0"++ it "Escaping interpolation symbols inside interpolation block" $ do+ [qmb|foo {"b{a{r"} baz|] `shouldBe` "foo b{a{r baz"+ [qmb|foo {"b\}a\}r"} baz|] `shouldBe` "foo b}a}r baz"++ it "Example from generated docs" $ [qmb| foo {'b':'a':'r':""}+ \ baz |] `shouldBe` "foo bar\n baz"++ it "Escaping backslashes" $ do [qmb| foo\bar |] `shouldBe` "foo\\bar"+ [qmb| foo\\bar |] `shouldBe` "foo\\bar"+ [qmb| foo\\\bar |] `shouldBe` "foo\\\\bar"+ [qmb| foo\\\\bar |] `shouldBe` "foo\\\\bar"++ it "Empty string" $ [qmb| |] `shouldBe` ""++ it "Escaping space by backslash at EOL after space (line break is cutted off)" $+ [qmb| foo \+ bar |] `shouldBe` "foo bar"++ it "Escaped spaces at the edges" $ do [qmb| foo\ |] `shouldBe` "foo "+ [qmb|\ foo |] `shouldBe` " foo"++ describe "Tabs as indentation" $ do++ it "Tabs is only indentation at left side" $ do+ [qmb|+ foo bar baz+ |] `shouldBe` "foo bar baz"++ [qmb| foo bar baz|] `shouldBe` "foo bar baz"++ it "Tabs also at EOL" $ do+ [qmb|+ foo bar baz + |] `shouldBe` "foo bar baz"++ [qmb| foo bar baz |] `shouldBe` "foo bar baz"++ it "Escaped tabs" $ do+ [qmb| \tfoo|] `shouldBe` "\tfoo"+ [qmb| \ foo |] `shouldBe` "\tfoo"+ [qmb| foo \ |] `shouldBe` "foo\t\t\t"+ [qmb| foo \ |] `shouldBe` "foo\t\t"+ [qmb| foo\ |] `shouldBe` "foo\t"++ it "Tails" $ do+ [qmb| + foo + |] `shouldBe` "foo"+ [qmb| + + foo + + + |] `shouldBe` "foo"+ [qmb| + foo + + |] `shouldBe` "foo"++ describe "New README examples" $ do++ it "Simple usage example" $ do+ let title = "Testing"+ text = "Some testing text"+ [qmb|+ <article>+ <h1>{title}</h1>+ <p>{text}</p>+ </article>+ |]+ `shouldBe`+ "<article>\n<h1>Testing</h1>\n<p>Some testing text</p>\n</article>"++ it "Interpolation" $ [qmb| foo {1+2} |] `shouldBe` "foo 3"++ it "Haddock example" $+ [qmb| foo+ {'b':'a':'r':""}+ baz |] `shouldBe` "foo\nbar\nbaz"++ it "Escaping backslash itself when it makes sense" $ do+ [qmb| foo\nbar |] `shouldBe` "foo\nbar"+ [qmb| foo\\nbar |] `shouldBe` "foo\\nbar"+ [qmb| foo\tbar |] `shouldBe` "foo\tbar"+ [qmb| foo\\tbar |] `shouldBe` "foo\\tbar"+ [qmb| foo\ bar |] `shouldBe` "foo\tbar"+ [qmb| foo\\ bar |] `shouldBe` "foo\\\tbar"+ [qmb| foo\ bar |] `shouldBe` "foo bar"+ [qmb| foo\\ bar |] `shouldBe` "foo\\ bar"++ [qmb| foo\+ bar |] `shouldBe` "foobar"+ [qmb| foo\\+ bar |] `shouldBe` "foo\\\nbar"
+ test/QMS/Spec.hs view
@@ -0,0 +1,161 @@+{-# LANGUAGE PackageImports #-}+{-# LANGUAGE QuasiQuotes #-}++module QMS.Spec (spec) where++import "hspec" Test.Hspec (Spec, describe, it, shouldBe)++-- local imports+import "qm-interpolated-string" Text.InterpolatedString.QM (qms)+++spec :: Spec+spec = do++ it "Works as expected" $+ [qms|+ foo+ {1+2}+ bar+ |] `shouldBe` "foo 3 bar"++ it "Explicitly cutting off line breaks" $ do+ [qms|+ foo\+ {1+2}\+ bar\+ baz+ |] `shouldBe` "foo3barbaz"+ [qms|+ foo\+ {1+2}\+ bar\+ baz\+ |] `shouldBe` "foo3barbaz"++ describe "Examples from README" $ do++ it "First (decorative spacing and escaping space symbol)" $+ [qms| hello world,+ \ what's going on here? |]+ `shouldBe` "hello world, what's going on here?"++ it "Second (breaking lines)" $+ [qms|+ it's actual+ ly NOT ignored+ |]+ `shouldBe` "it's actual ly NOT ignored"++ it "Third (explicit line breaks symbols)" $+ [qms| \ You could explicitly escape indentation or\n+ line breaks when you really need it! \+ |] `shouldBe` " You could explicitly escape indentation or\n \+ \line breaks when you really need it! "++ it "Fourth (escaping interpolation blocks to show them as text)" $+ [qms| {1+2} \{3+4} |] `shouldBe` "3 {3+4}"++ it "Type annotation in interpolation block" $+ [qms|{10 :: Float}|] `shouldBe` "10.0"++ it "Escaping interpolation symbols inside interpolation block" $ do+ [qms|foo {"b{a{r"} baz|] `shouldBe` "foo b{a{r baz"+ [qms|foo {"b\}a\}r"} baz|] `shouldBe` "foo b}a}r baz"++ it "Example from generated docs" $ [qms| foo {'b':'a':'r':""}+ \ baz |] `shouldBe` "foo bar baz"++ it "Escaping backslashes" $ do [qms| foo\bar |] `shouldBe` "foo\\bar"+ [qms| foo\\bar |] `shouldBe` "foo\\bar"+ [qms| foo\\\bar |] `shouldBe` "foo\\\\bar"+ [qms| foo\\\\bar |] `shouldBe` "foo\\\\bar"++ it "Empty string" $ [qms| |] `shouldBe` ""++ it "Escaping space by backslash at EOL after space (line break is cutted off)" $+ [qms| foo \+ bar |] `shouldBe` "foo bar"++ it "Escaped spaces at the edges" $ do [qms| foo\ |] `shouldBe` "foo "+ [qms|\ foo |] `shouldBe` " foo"++ describe "Tabs as indentation" $ do++ it "Tabs is only indentation at left side" $ do+ [qms|+ foo bar baz+ |] `shouldBe` "foo bar baz"++ [qms| foo bar baz|] `shouldBe` "foo bar baz"++ it "Tabs also at EOL" $ do+ [qms|+ foo bar baz + |] `shouldBe` "foo bar baz"++ [qms| foo bar baz |] `shouldBe` "foo bar baz"++ it "Escaped tabs" $ do+ [qms| \tfoo|] `shouldBe` "\tfoo"+ [qms| \ foo |] `shouldBe` "\tfoo"+ [qms| foo \ |] `shouldBe` "foo\t\t\t"+ [qms| foo \ |] `shouldBe` "foo\t\t"+ [qms| foo\ |] `shouldBe` "foo\t"++ it "Tails" $ do+ [qms| + foo + |] `shouldBe` "foo"+ [qms| + + foo + + + |] `shouldBe` "foo"+ [qms| + foo + + |] `shouldBe` "foo"++ describe "New README examples" $ do++ it "First example" $+ [qms| Hello,+ world!+ Pi is {floor pi}.{floor $ (pi - 3) * 100}… |]+ `shouldBe` "Hello, world! Pi is 3.14…"++ it "Simple usage example" $ do+ let title = "Testing"+ text = "Some testing text"+ [qms|+ <article>+ <h1>{title}</h1>+ <p>{text}</p>+ </article>+ |]+ `shouldBe`+ "<article> <h1>Testing</h1> <p>Some testing text</p> </article>"++ it "Interpolation" $ [qms| foo {1+2} |] `shouldBe` "foo 3"++ it "Haddock example" $+ [qms| foo+ {'b':'a':'r':""}+ baz |] `shouldBe` "foo bar baz"++ it "Escaping backslash itself when it makes sense" $ do+ [qms| foo\nbar |] `shouldBe` "foo\nbar"+ [qms| foo\\nbar |] `shouldBe` "foo\\nbar"+ [qms| foo\tbar |] `shouldBe` "foo\tbar"+ [qms| foo\\tbar |] `shouldBe` "foo\\tbar"+ [qms| foo\ bar |] `shouldBe` "foo\tbar"+ [qms| foo\\ bar |] `shouldBe` "foo\\\tbar"+ [qms| foo\ bar |] `shouldBe` "foo bar"+ [qms| foo\\ bar |] `shouldBe` "foo\\ bar"++ [qms| foo\+ bar |] `shouldBe` "foobar"+ [qms| foo\\+ bar |] `shouldBe` "foo\\ bar"
+ test/QN/Spec.hs view
@@ -0,0 +1,133 @@+{-# LANGUAGE PackageImports #-}+{-# LANGUAGE QuasiQuotes #-}++module QN.Spec (spec) where++import "hspec" Test.Hspec (Spec, describe, it, shouldBe)++-- local imports+import "qm-interpolated-string" Text.InterpolatedString.QM (qn)+++spec :: Spec+spec = do++ describe "Examples from README" $ do++ it "First (decorative spacing and escaping space symbol)" $+ [qn| hello world,+ \ what's going on here? |]+ `shouldBe` "hello world, what's going on here?"++ it "Second (merging lines without spaces)" $+ [qn|+ it's actual+ ly ignored+ |]+ `shouldBe` "it's actually ignored"++ it "Third (explicit line breaks symbols)" $+ [qn| \ You could explicitly escape indentation or\n+ line breaks when you really need it! \+ |] `shouldBe` " You could explicitly escape indentation or\n\+ \line breaks when you really need it! "++ it "Fourth (escaping interpolation blocks to show them as text)" $+ [qn| {1+2} \{3+4} |] `shouldBe` "{1+2} \\{3+4}"++ it "Example of `qn` QuasiQuoter" $+ [qn| foo {1+2} |] `shouldBe` "foo {1+2}"++ it "Type annotation in interpolation block" $+ [qn|{10 :: Float}|] `shouldBe` "{10 :: Float}"++ it "Escaping interpolation symbols inside interpolation block" $ do+ [qn|foo {"b{a{r"} baz|] `shouldBe` "foo {\"b{a{r\"} baz"+ [qn|foo {"b\}a\}r"} baz|] `shouldBe` "foo {\"b\\}a\\}r\"} baz"++ it "Example from generated docs" $+ [qn| foo {'b':'a':'r':""}+ \ baz |] `shouldBe` "foo {'b':'a':'r':\"\"} baz"++ it "Escaping backslashes" $ do [qn| foo\bar |] `shouldBe` "foo\\bar"+ [qn| foo\\bar |] `shouldBe` "foo\\bar"+ [qn| foo\\\bar |] `shouldBe` "foo\\\\bar"+ [qn| foo\\\\bar |] `shouldBe` "foo\\\\bar"++ it "Empty string" $ [qn| |] `shouldBe` ""++ it "Escaping space by slash at EOL after space" $+ [qn| foo \+ bar |] `shouldBe` "foo bar"++ it "Escaped spaces at the edges" $ do [qn| foo\ |] `shouldBe` "foo "+ [qn|\ foo |] `shouldBe` " foo"++ describe "Tabs as indentation" $ do++ it "Tabs is only indentation at left side" $ do+ [qn|+ foo bar baz+ |] `shouldBe` "foo bar baz"++ [qn| foo bar baz|] `shouldBe` "foo bar baz"++ it "Tabs also at EOL" $ do+ [qn|+ foo bar baz + |] `shouldBe` "foo bar baz"++ [qn| foo bar baz |] `shouldBe` "foo bar baz"++ it "Escaped tabs" $ do+ [qn| \tfoo|] `shouldBe` "\tfoo"+ [qn| \ foo |] `shouldBe` "\tfoo"+ [qn| foo \ |] `shouldBe` "foo\t\t\t"+ [qn| foo \ |] `shouldBe` "foo\t\t"+ [qn| foo\ |] `shouldBe` "foo\t"++ it "Tails" $ do+ [qn| + foo + |] `shouldBe` "foo"+ [qn| + + foo + + + |] `shouldBe` "foo"+ [qn| + foo + + |] `shouldBe` "foo"++ describe "New README examples" $ do++ it "Simple usage example" $ do+ [qn|+ <article>+ <h1>{title}</h1>+ <p>{text}</p>+ </article>+ |] `shouldBe` "<article><h1>{title}</h1><p>{text}</p></article>"++ it "Interpolation" $ [qn| foo {1+2} |] `shouldBe` "foo {1+2}"++ it "Haddock example" $+ [qn| foo {'b':'a':'r':""}+ \ baz |] `shouldBe` "foo {'b':'a':'r':\"\"} baz"++ it "Escaping backslash itself when it makes sense" $ do+ [qn| foo\nbar |] `shouldBe` "foo\nbar"+ [qn| foo\\nbar |] `shouldBe` "foo\\nbar"+ [qn| foo\tbar |] `shouldBe` "foo\tbar"+ [qn| foo\\tbar |] `shouldBe` "foo\\tbar"+ [qn| foo\ bar |] `shouldBe` "foo\tbar"+ [qn| foo\\ bar |] `shouldBe` "foo\\\tbar"+ [qn| foo\ bar |] `shouldBe` "foo bar"+ [qn| foo\\ bar |] `shouldBe` "foo\\ bar"++ [qn| foo\+ bar |] `shouldBe` "foobar"+ [qn| foo\\+ bar |] `shouldBe` "foo\\bar"
+ test/QNB/Spec.hs view
@@ -0,0 +1,157 @@+{-# LANGUAGE PackageImports #-}+{-# LANGUAGE QuasiQuotes #-}++module QNB.Spec (spec) where++import "hspec" Test.Hspec (Spec, describe, it, shouldBe)++-- local imports+import "qm-interpolated-string" Text.InterpolatedString.QM (qnb)+++spec :: Spec+spec = do++ it "Works as expected" $+ [qnb|+ foo+ {1+2}+ bar+ |] `shouldBe` "foo\n{1+2}\nbar"++ it "Explicitly cutting off line breaks" $ do+ [qnb|+ foo\+ {1+2}\+ bar\+ baz+ |] `shouldBe` "foo{1+2}barbaz"+ [qnb|+ foo\+ {1+2}\+ bar\+ baz\+ |] `shouldBe` "foo{1+2}barbaz"++ describe "Examples from README" $ do++ it "First (decorative spacing and escaping space symbol)" $+ [qnb| hello world,+ \ what's going on here? |]+ `shouldBe` "hello world,\n what's going on here?"++ it "Second (breaking lines)" $+ [qnb|+ it's actual+ ly NOT ignored+ |]+ `shouldBe` "it's actual\nly NOT ignored"++ it "Third (explicit line breaks symbols, line break plus space)" $+ [qnb| \ You could explicitly escape indentation or\n+ line breaks when you really need it! \+ |] `shouldBe` " You could explicitly escape indentation or\n\n\+ \line breaks when you really need it! "++ it "Fourth (escaping interpolation blocks to show them as text)" $+ [qnb| {1+2} \{3+4} |] `shouldBe` "{1+2} \\{3+4}"++ it "Example of `qnb` QuasiQuoter" $+ [qnb| foo {1+2} |] `shouldBe` "foo {1+2}"++ it "Type annotation in interpolation block" $+ [qnb|{10 :: Float}|] `shouldBe` "{10 :: Float}"++ it "Escaping interpolation symbols inside interpolation block" $ do+ [qnb|foo {"b{a{r"} baz|] `shouldBe` "foo {\"b{a{r\"} baz"+ [qnb|foo {"b\}a\}r"} baz|] `shouldBe` "foo {\"b\\}a\\}r\"} baz"++ it "Example from generated docs (double-space)" $+ [qnb| foo {'b':'a':'r':""}+ \ baz |] `shouldBe` "foo {'b':'a':'r':\"\"}\n baz"++ it "Escaping backslashes" $ do [qnb| foo\bar |] `shouldBe` "foo\\bar"+ [qnb| foo\\bar |] `shouldBe` "foo\\bar"+ [qnb| foo\\\bar |] `shouldBe` "foo\\\\bar"+ [qnb| foo\\\\bar |] `shouldBe` "foo\\\\bar"++ it "Empty string" $ [qnb| |] `shouldBe` ""++ it "Escaping space by backslash at EOL after space (line break is cutted off)" $+ [qnb| foo \+ bar |] `shouldBe` "foo bar"++ it "Escaped spaces at the edges" $ do [qnb| foo\ |] `shouldBe` "foo "+ [qnb|\ foo |] `shouldBe` " foo"++ describe "Tabs as indentation" $ do++ it "Tabs is only indentation at left side" $ do+ [qnb|+ foo bar baz+ |] `shouldBe` "foo bar baz"++ [qnb| foo bar baz|] `shouldBe` "foo bar baz"++ it "Tabs also at EOL" $ do+ [qnb|+ foo bar baz + |] `shouldBe` "foo bar baz"++ [qnb| foo bar baz |] `shouldBe` "foo bar baz"++ it "Escaped tabs" $ do+ [qnb| \tfoo|] `shouldBe` "\tfoo"+ [qnb| \ foo |] `shouldBe` "\tfoo"+ [qnb| foo \ |] `shouldBe` "foo\t\t\t"+ [qnb| foo \ |] `shouldBe` "foo\t\t"+ [qnb| foo\ |] `shouldBe` "foo\t"++ it "Tails" $ do+ [qnb| + foo + |] `shouldBe` "foo"+ [qnb| + + foo + + + |] `shouldBe` "foo"+ [qnb| + foo + + |] `shouldBe` "foo"++ describe "New README examples" $ do++ it "Simple usage example" $ do+ [qnb|+ <article>+ <h1>{title}</h1>+ <p>{text}</p>+ </article>+ |]+ `shouldBe`+ "<article>\n<h1>{title}</h1>\n<p>{text}</p>\n</article>"++ it "Interpolation" $ [qnb| foo {1+2} |] `shouldBe` "foo {1+2}"++ it "Haddock example" $+ [qnb| foo+ {'b':'a':'r':""}+ baz |] `shouldBe` "foo\n{'b':'a':'r':\"\"}\nbaz"++ it "Escaping backslash itself when it makes sense" $ do+ [qnb| foo\nbar |] `shouldBe` "foo\nbar"+ [qnb| foo\\nbar |] `shouldBe` "foo\\nbar"+ [qnb| foo\tbar |] `shouldBe` "foo\tbar"+ [qnb| foo\\tbar |] `shouldBe` "foo\\tbar"+ [qnb| foo\ bar |] `shouldBe` "foo\tbar"+ [qnb| foo\\ bar |] `shouldBe` "foo\\\tbar"+ [qnb| foo\ bar |] `shouldBe` "foo bar"+ [qnb| foo\\ bar |] `shouldBe` "foo\\ bar"++ [qnb| foo\+ bar |] `shouldBe` "foobar"+ [qnb| foo\\+ bar |] `shouldBe` "foo\\\nbar"
+ test/QNS/Spec.hs view
@@ -0,0 +1,157 @@+{-# LANGUAGE PackageImports #-}+{-# LANGUAGE QuasiQuotes #-}++module QNS.Spec (spec) where++import "hspec" Test.Hspec (Spec, describe, it, shouldBe)++-- local imports+import "qm-interpolated-string" Text.InterpolatedString.QM (qns)+++spec :: Spec+spec = do++ it "Works as expected" $+ [qns|+ foo+ {1+2}+ bar+ |] `shouldBe` "foo {1+2} bar"++ it "Explicitly cutting off line breaks" $ do+ [qns|+ foo\+ {1+2}\+ bar\+ baz+ |] `shouldBe` "foo{1+2}barbaz"+ [qns|+ foo\+ {1+2}\+ bar\+ baz\+ |] `shouldBe` "foo{1+2}barbaz"++ describe "Examples from README" $ do++ it "First (decorative spacing and escaping space symbol)" $+ [qns| hello world,+ \ what's going on here? |]+ `shouldBe` "hello world, what's going on here?"++ it "Second (breaking lines)" $+ [qns|+ it's actual+ ly NOT ignored+ |]+ `shouldBe` "it's actual ly NOT ignored"++ it "Third (explicit line breaks symbols, line break plus space)" $+ [qns| \ You could explicitly escape indentation or\n+ line breaks when you really need it! \+ |] `shouldBe` " You could explicitly escape indentation or\n \+ \line breaks when you really need it! "++ it "Fourth (escaping interpolation blocks to show them as text)" $+ [qns| {1+2} \{3+4} |] `shouldBe` "{1+2} \\{3+4}"++ it "Example of `qns` QuasiQuoter" $+ [qns| foo {1+2} |] `shouldBe` "foo {1+2}"++ it "Type annotation in interpolation block" $+ [qns|{10 :: Float}|] `shouldBe` "{10 :: Float}"++ it "Escaping interpolation symbols inside interpolation block" $ do+ [qns|foo {"b{a{r"} baz|] `shouldBe` "foo {\"b{a{r\"} baz"+ [qns|foo {"b\}a\}r"} baz|] `shouldBe` "foo {\"b\\}a\\}r\"} baz"++ it "Example from generated docs (double-space)" $+ [qns| foo {'b':'a':'r':""}+ \ baz |] `shouldBe` "foo {'b':'a':'r':\"\"} baz"++ it "Escaping backslashes" $ do [qns| foo\bar |] `shouldBe` "foo\\bar"+ [qns| foo\\bar |] `shouldBe` "foo\\bar"+ [qns| foo\\\bar |] `shouldBe` "foo\\\\bar"+ [qns| foo\\\\bar |] `shouldBe` "foo\\\\bar"++ it "Empty string" $ [qns| |] `shouldBe` ""++ it "Escaping space by backslash at EOL after space (line break is cutted off)" $+ [qns| foo \+ bar |] `shouldBe` "foo bar"++ it "Escaped spaces at the edges" $ do [qns| foo\ |] `shouldBe` "foo "+ [qns|\ foo |] `shouldBe` " foo"++ describe "Tabs as indentation" $ do++ it "Tabs is only indentation at left side" $ do+ [qns|+ foo bar baz+ |] `shouldBe` "foo bar baz"++ [qns| foo bar baz|] `shouldBe` "foo bar baz"++ it "Tabs also at EOL" $ do+ [qns|+ foo bar baz + |] `shouldBe` "foo bar baz"++ [qns| foo bar baz |] `shouldBe` "foo bar baz"++ it "Escaped tabs" $ do+ [qns| \tfoo|] `shouldBe` "\tfoo"+ [qns| \ foo |] `shouldBe` "\tfoo"+ [qns| foo \ |] `shouldBe` "foo\t\t\t"+ [qns| foo \ |] `shouldBe` "foo\t\t"+ [qns| foo\ |] `shouldBe` "foo\t"++ it "Tails" $ do+ [qns| + foo + |] `shouldBe` "foo"+ [qns| + + foo + + + |] `shouldBe` "foo"+ [qns| + foo + + |] `shouldBe` "foo"++ describe "New README examples" $ do++ it "Simple usage example" $ do+ [qns|+ <article>+ <h1>{title}</h1>+ <p>{text}</p>+ </article>+ |]+ `shouldBe`+ "<article> <h1>{title}</h1> <p>{text}</p> </article>"++ it "Interpolation" $ [qns| foo {1+2} |] `shouldBe` "foo {1+2}"++ it "Haddock example" $+ [qns| foo+ {'b':'a':'r':""}+ baz |] `shouldBe` "foo {'b':'a':'r':\"\"} baz"++ it "Escaping backslash itself when it makes sense" $ do+ [qns| foo\nbar |] `shouldBe` "foo\nbar"+ [qns| foo\\nbar |] `shouldBe` "foo\\nbar"+ [qns| foo\tbar |] `shouldBe` "foo\tbar"+ [qns| foo\\tbar |] `shouldBe` "foo\\tbar"+ [qns| foo\ bar |] `shouldBe` "foo\tbar"+ [qns| foo\\ bar |] `shouldBe` "foo\\\tbar"+ [qns| foo\ bar |] `shouldBe` "foo bar"+ [qns| foo\\ bar |] `shouldBe` "foo\\ bar"++ [qns| foo\+ bar |] `shouldBe` "foobar"+ [qns| foo\\+ bar |] `shouldBe` "foo\\ bar"
test/Spec.hs view
@@ -3,111 +3,38 @@ module Main (main) where -import "hspec" Test.Hspec (hspec, describe, it, shouldBe)-import "qm-interpolated-string" Text.InterpolatedString.QM (qm, qn)+import "hspec" Test.Hspec (hspec, describe) +-- local imports+import qualified QM.Spec+import qualified QN.Spec+import qualified QMB.Spec+import qualified QNB.Spec+import qualified QMS.Spec+import qualified QNS.Spec -main :: IO ()-main = hspec $ do+-- Generated tests for CRLF line breaks+import qualified LineBreaks.CRLF.QM.Spec+import qualified LineBreaks.CRLF.QN.Spec+import qualified LineBreaks.CRLF.QMB.Spec+import qualified LineBreaks.CRLF.QNB.Spec+import qualified LineBreaks.CRLF.QMS.Spec+import qualified LineBreaks.CRLF.QNS.Spec - describe "QM" $ do - describe "Examples from README" $ do-- it "First (decorative spacing and escaping space symbol)" $- [qm| hello world,- \ what's going on here? |]- `shouldBe` "hello world, what's going on here?"-- it "Second (merging lines without spaces)" $- [qm|- it's actual- ly ignored- |]- `shouldBe` "it's actually ignored"-- it "Third (explicit line-breaks symbols)" $- [qm| \ You could explicitly escape indentation or\n- line-breaks when you really need it! \- |] `shouldBe` " You could explicitly escape indentation or\n\- \line-breaks when you really need it! "-- it "Fourth (escaping interpolation blocks to show them as text)" $- [qm| {1+2} \{3+4} |] `shouldBe` "3 {3+4}"-- it "Type annotation in interpolation block" $- [qm|{10 :: Float}|] `shouldBe` "10.0"-- it "Escaping interpolation symbols inside interpolation block" $ do- [qm|foo {"b{a{r"} baz|] `shouldBe` "foo b{a{r baz"- [qm|foo {"b\}a\}r"} baz|] `shouldBe` "foo b}a}r baz"-- it "Example from generated docs" $ [qm| foo {'b':'a':'r':""}- \ baz |] `shouldBe` "foo bar baz"-- it "Escaping backslashes" $ do [qm| foo\bar |] `shouldBe` "foo\\bar"- [qm| foo\\bar |] `shouldBe` "foo\\bar"- [qm| foo\\\bar |] `shouldBe` "foo\\\\bar"- [qm| foo\\\\bar |] `shouldBe` "foo\\\\bar"-- it "Empty string" $ [qm| |] `shouldBe` ""-- it "Escaping space by slash at EOL after space" $- [qm| foo \- bar |] `shouldBe` "foo bar"-- it "Escaped spaces at the edges" $ do [qm| foo\ |] `shouldBe` "foo "- [qm|\ foo |] `shouldBe` " foo"-- describe "QN (QM but without interpolation)" $ do-- describe "Examples from README" $ do-- it "First (decorative spacing and escaping space symbol)" $- [qn| hello world,- \ what's going on here? |]- `shouldBe` "hello world, what's going on here?"-- it "Second (merging lines without spaces)" $- [qn|- it's actual- ly ignored- |]- `shouldBe` "it's actually ignored"-- it "Third (explicit line-breaks symbols)" $- [qn| \ You could explicitly escape indentation or\n- line-breaks when you really need it! \- |] `shouldBe` " You could explicitly escape indentation or\n\- \line-breaks when you really need it! "-- it "Fourth (escaping interpolation blocks to show them as text)" $- [qn| {1+2} \{3+4} |] `shouldBe` "{1+2} \\{3+4}"-- it "Example of `qn` QuasiQuoter" $- [qn| foo {1+2} |] `shouldBe` "foo {1+2}"-- it "Type annotation in interpolation block" $- [qn|{10 :: Float}|] `shouldBe` "{10 :: Float}"-- it "Escaping interpolation symbols inside interpolation block" $ do- [qn|foo {"b{a{r"} baz|] `shouldBe` "foo {\"b{a{r\"} baz"- [qn|foo {"b\}a\}r"} baz|] `shouldBe` "foo {\"b\\}a\\}r\"} baz"-- it "Example from generated docs" $- [qn| foo {'b':'a':'r':""}- \ baz |] `shouldBe` "foo {'b':'a':'r':\"\"} baz"-- it "Escaping backslashes" $ do [qn| foo\bar |] `shouldBe` "foo\\bar"- [qn| foo\\bar |] `shouldBe` "foo\\bar"- [qn| foo\\\bar |] `shouldBe` "foo\\\\bar"- [qn| foo\\\\bar |] `shouldBe` "foo\\\\bar"-- it "Empty string" $ [qn| |] `shouldBe` ""-- it "Escaping space by slash at EOL after space" $- [qn| foo \- bar |] `shouldBe` "foo bar"+main :: IO ()+main = hspec $ do+ describe "QM" QM.Spec.spec+ describe "QN (QM but without interpolation)" QN.Spec.spec+ describe "QMB (interpolated string with line-*B*reaks)" QMB.Spec.spec+ describe "QNB (QMB but without interpolation)" QNB.Spec.spec+ describe "QMS (interpolated string with line breaks replaced with *S*paces)"+ QMS.Spec.spec+ describe "QNS (QMS but without interpolation)" QNS.Spec.spec - it "Escaped spaces at the edges" $ do [qn| foo\ |] `shouldBe` "foo "- [qn|\ foo |] `shouldBe` " foo"+ describe "QM (CRLF line breaks)" LineBreaks.CRLF.QM.Spec.spec+ describe "QN (CRLF line breaks)" LineBreaks.CRLF.QN.Spec.spec+ describe "QMB (CRLF line breaks)" LineBreaks.CRLF.QMB.Spec.spec+ describe "QNB (CRLF line breaks)" LineBreaks.CRLF.QNB.Spec.spec+ describe "QMS (CRLF line breaks)" LineBreaks.CRLF.QMS.Spec.spec+ describe "QNS (CRLF line breaks)" LineBreaks.CRLF.QNS.Spec.spec