packages feed

command-qq 0.2.1.0 → 0.2.2.0

raw patch · 13 files changed

+370/−361 lines, 13 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ System.Command.QQ: substituteVars :: String -> Q Exp

Files

CHANGELOG.md view
@@ -1,9 +1,14 @@+0.2.2.0+=======++  * Exported `substituteVars`+ 0.2.1.0 ======= -  * Add a bunch of predefined quasiquoters to `System.Command.QQ.Predef`+  * Added a bunch of predefined quasiquoters to `System.Command.QQ.Predef` -  * Add `Embed` instances for `Data.Text.Text` and `Data.Text.Lazy.Text`+  * Added `Embed` instances for `Data.Text.Text` and `Data.Text.Lazy.Text`  0.2.0.0 =======@@ -12,6 +17,6 @@    * Moved `Eval` onto `Text` to speed I/O up. -  * Quasiquoters support literals and constructors with no arguments+  * Added support for embedding literals and constructors with no arguments -  * More `Embed` instances+  * Mored `Embed` instances
command-qq.cabal view
@@ -1,5 +1,5 @@ name:                command-qq-version:             0.2.1.0+version:             0.2.2.0 synopsis:            Quasiquoters for external commands description:   Features:@@ -39,7 +39,7 @@ extra-source-files:   CHANGELOG.md   README.md-  examples/CommandT.hs+  example/CommandT.hs  source-repository head   type:              git@@ -48,7 +48,7 @@ source-repository this   type:              git   location:          https://github.com/biegunka/command-qq-  tag:               0.2.1.0+  tag:               0.2.2.0  library   default-language:  Haskell2010@@ -70,7 +70,7 @@   build-depends:       base == 4.*     , doctest-  hs-source-dirs:    tests+  hs-source-dirs:    test   main-is:           Doctests.hs  test-suite spec@@ -83,8 +83,8 @@     , template-haskell     , text   hs-source-dirs:-      tests-    , examples+      test+    , example   main-is:           Spec.hs   other-modules:     System.Command.QQ.EmbedSpec
+ example/CommandT.hs view
@@ -0,0 +1,128 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TypeFamilies #-}+-- | Example DSL made on top of "System.Command.QQ"+--+-- Provides [semi-]convenient way to run external commands+-- in sequence and parse their output.+--+-- DSL does not use any custom quasiquoters but provides 'Eval'+-- instances for custom datatypes that implement desired semantics+module CommandT where++import Control.Applicative                         -- base+  ( Applicative(..), Alternative(..) )+import Control.Monad (MonadPlus(..))               -- base+import Control.Monad.IO.Class (MonadIO(..))        -- transformers+import Control.Monad.Trans.Class (MonadTrans(..))  -- transformers+import Control.Monad.Trans.Except                  -- transformers+import Data.Monoid (Last(..))                      -- base+import Data.Text.Lazy (Text)                       -- text+import System.Exit (ExitCode(..))                  -- base+import System.Command.QQ (Eval(..))                -- command-qq++-- $setup+-- >>> :set -XQuasiQuotes+-- >>> import System.Command.QQ+-- >>> import qualified Data.Text.Lazy as T+-- >>> let lengths = [sh|while read line; do echo ${#line}; done|] :: Text -> CommandT IO Text+++infixl 1 >>! -- same as >>=+++-- | External commands sequencing result+--+-- Every external command results either in failure (thus provides non-zero+-- exit code and @stderr@) or some value (typically its @stdout@)+--+-- For example:+--+-- >>> runCommandT $ [sh|echo -e "hello\nworld!!!"|] >>= lengths+-- Right "5\n8\n"+--+-- 'CommandT' implements the usual 'Alternative' instance semantics:+--+-- >>> runCommandT $ [sh|exit 1|] <|> [sh|echo hello|]+-- Right "hello\n"+--+-- If everything fails, then last failure is returned:+--+-- >>> do Left (Last (Just (Failure _ i _))) <- runCommandT $ [sh|exit 1|] <|> [sh|exit 3|]; print i+-- 3+newtype CommandT m a = CommandT { unCommandT :: ExceptT (Last Failure) m a }++-- | Failed command with exit code and @stderr@+data Failure = Failure Command Int Text+    deriving (Show, Read)++-- | Command name and arguments+data Command = Command String [String]+    deriving (Show, Read)++-- | Run external commands and get the result+runCommandT :: CommandT m a -> m (Either (Last Failure) a)+runCommandT = runExceptT . unCommandT++instance (Functor m, Monad m) => Functor (CommandT m) where+  fmap f (CommandT x) = CommandT (fmap f x)++instance (Functor m, Monad m) => Applicative (CommandT m) where+  pure = CommandT . pure+  CommandT f <*> CommandT x = CommandT (f <*> x)++instance (Functor m, Monad m) => Monad (CommandT m) where+  return = pure+  CommandT x >>= k = CommandT (x >>= unCommandT . k)++instance (Functor m, Monad m) => Alternative (CommandT m) where+  empty = CommandT empty+  CommandT f <|> CommandT x = CommandT (f <|> x)++instance (Functor m, Monad m) => MonadPlus (CommandT m) where+  mzero = empty+  mplus = (<|>)++instance MonadTrans CommandT where+  lift = CommandT . lift++instance (Functor m, MonadIO m) => MonadIO (CommandT m) where+  liftIO = lift . liftIO++instance (o ~ Text, MonadIO m) => Eval (CommandT m o) where+  eval command args = CommandT . ExceptT $ do+    (status, out, err) <- liftIO $ eval command args+    return $ case status of+      ExitSuccess   -> Right out+      ExitFailure i -> Left (Last (Just (Failure (Command command args) i err)))++instance (i ~ Text, o ~ Text, MonadIO m) => Eval (i -> CommandT m o) where+  eval command args input = CommandT . ExceptT $ do+    (status, out, err) <- liftIO $ eval command args input+    return $ case status of+      ExitSuccess   -> Right out+      ExitFailure i -> Left (Last (Just (Failure (Command command args) i err)))+++-- | Pass @stderr@ of failed external command to function+--+-- If nothing has failed, we do not have @stderr@, really:+--+-- >>> runCommandT $ [sh|echo -e "hello\nworld!!!">&2|] >>! lengths+-- Left (Last {getLast = Nothing})+--+-- If something has failed, we do have @stderr@ to play with:+--+-- >>> runCommandT $ [sh|echo -e "hello\nworld!!!">&2; exit 1|] >>! lengths+-- Right "5\n8\n"+--+-- And playing may involve arbitrary Haskell functions, of course:+--+-- >>> runCommandT $ [sh|echo -e "hello\nworld!!!">&2; exit 1|] >>! lengths . T.unlines . reverse . T.lines+-- Right "8\n5\n"+(>>!) :: Monad m => CommandT m a -> (Text -> CommandT m b) -> CommandT m b+x >>! k = CommandT . ExceptT $ do+  t <- runCommandT x+  case t of+    Left (Last Nothing) -> return (Left (Last Nothing))+    Left (Last (Just (Failure _ _ err))) -> runCommandT $ k err+    Right _ -> return (Left (Last Nothing))
− examples/CommandT.hs
@@ -1,128 +0,0 @@-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TypeFamilies #-}--- | Example DSL made on top of "System.Command.QQ"------ Provides [semi-]convenient way to run external commands--- in sequence and parse their output.------ DSL does not use any custom quasiquoters but provides 'Eval'--- instances for custom datatypes that implement desired semantics-module CommandT where--import Control.Applicative                         -- base-  ( Applicative(..), Alternative(..) )-import Control.Monad (MonadPlus(..))               -- base-import Control.Monad.IO.Class (MonadIO(..))        -- transformers-import Control.Monad.Trans.Class (MonadTrans(..))  -- transformers-import Control.Monad.Trans.Either                  -- either-import Data.Monoid (Last(..))                      -- base-import Data.Text.Lazy (Text)                       -- text-import System.Exit (ExitCode(..))                  -- base-import System.Command.QQ (Eval(..))                -- command-qq---- $setup--- >>> :set -XQuasiQuotes--- >>> import System.Command.QQ--- >>> import qualified Data.Text.Lazy as T--- >>> let lengths = [sh|while read line; do echo ${#line}; done|] :: Text -> CommandT IO Text---infixl 1 >>! -- same as >>=----- | External commands sequencing result------ Every external command results either in failure (thus provides non-zero--- exit code and @stderr@) or some value (typically its @stdout@)------ For example:------ >>> runCommandT $ [sh|echo -e "hello\nworld!!!"|] >>= lengths--- Right "5\n8\n"------ 'CommandT' implements the usual 'Alternative' instance semantics:------ >>> runCommandT $ [sh|exit 1|] <|> [sh|echo hello|]--- Right "hello\n"------ If everything fails, then last failure is returned:------ >>> do Left (Last (Just (Failure _ i _))) <- runCommandT $ [sh|exit 1|] <|> [sh|exit 3|]; print i--- 3-newtype CommandT m a = CommandT { unCommandT :: EitherT (Last Failure) m a }---- | Failed command with exit code and @stderr@-data Failure = Failure Command Int Text-    deriving (Show, Read)---- | Command name and arguments-data Command = Command String [String]-    deriving (Show, Read)---- | Run external commands and get the result-runCommandT :: CommandT m a -> m (Either (Last Failure) a)-runCommandT = runEitherT . unCommandT--instance Monad m => Functor (CommandT m) where-  fmap f (CommandT x) = CommandT (fmap f x)--instance Monad m => Applicative (CommandT m) where-  pure = CommandT . pure-  CommandT f <*> CommandT x = CommandT (f <*> x)--instance Monad m => Monad (CommandT m) where-  return = pure-  CommandT x >>= k = CommandT (x >>= unCommandT . k)--instance Monad m => Alternative (CommandT m) where-  empty = CommandT empty-  CommandT f <|> CommandT x = CommandT (f <|> x)--instance Monad m => MonadPlus (CommandT m) where-  mzero = empty-  mplus = (<|>)--instance MonadTrans CommandT where-  lift = CommandT . lift--instance MonadIO m => MonadIO (CommandT m) where-  liftIO = lift . liftIO--instance (o ~ Text, MonadIO m) => Eval (CommandT m o) where-  eval command args = CommandT . EitherT $ do-    (status, out, err) <- liftIO $ eval command args-    return $ case status of-      ExitSuccess   -> Right out-      ExitFailure i -> Left (Last (Just (Failure (Command command args) i err)))--instance (i ~ Text, o ~ Text, MonadIO m) => Eval (i -> CommandT m o) where-  eval command args input = CommandT . EitherT $ do-    (status, out, err) <- liftIO $ eval command args input-    return $ case status of-      ExitSuccess   -> Right out-      ExitFailure i -> Left (Last (Just (Failure (Command command args) i err)))----- | Pass @stderr@ of failed external command to function------ If nothing has failed, we do not have @stderr@, really:------ >>> runCommandT $ [sh|echo -e "hello\nworld!!!">&2|] >>! lengths--- Left (Last {getLast = Nothing})------ If something has failed, we do have @stderr@ to play with:------ >>> runCommandT $ [sh|echo -e "hello\nworld!!!">&2; exit 1|] >>! lengths--- Right "5\n8\n"------ And playing may involve arbitrary Haskell functions, of course:------ >>> runCommandT $ [sh|echo -e "hello\nworld!!!">&2; exit 1|] >>! lengths . T.unlines . reverse . T.lines--- Right "8\n5\n"-(>>!) :: Monad m => CommandT m a -> (Text -> CommandT m b) -> CommandT m b-x >>! k = CommandT . EitherT $ do-  t <- runCommandT x-  case t of-    Left (Last Nothing) -> return (Left (Last Nothing))-    Left (Last (Just (Failure _ _ err))) -> runCommandT $ k err-    Right _ -> return (Left (Last Nothing))
src/System/Command/QQ.hs view
@@ -6,11 +6,15 @@ module System.Command.QQ   ( -- * Quasiquoters     -- ** Default shell-    sh_, sh+    sh_+  , sh     -- ** Constructors-  , shell, interpreter+  , shell+  , interpreter     -- * Customizations-  , quoter, callCommand+  , quoter+  , callCommand+  , substituteVars   , module System.Command.QQ.Embed   , module System.Command.QQ.Eval   ) where@@ -96,7 +100,7 @@ -- and producing Haskell expression. -- -- Other kinds of quasiquoters (patterns, types or--- declarations quasiquoters) will fail in compile time+-- declarations quasiquoters) will fail at compile time quoter :: (String -> Q Exp) -> QuasiQuoter quoter quote = QuasiQuoter   { quoteExp  = quote@@ -115,7 +119,7 @@   -> String   -- ^ Quasiquoter contents   -> Q Exp callCommand path args string =-  [e| eval path (args ++ [$(string2exp string)]) |]+  [e| eval path (args ++ [$(substituteVars string)]) |]  -- | Construct Haskell expression for external command call callCommand_@@ -124,11 +128,12 @@   -> String   -- ^ Quasiquoter contents   -> Q Exp callCommand_ path args string =-  [e| eval path (args ++ [$(string2exp string)]) :: IO () |]+  [e| eval path (args ++ [$(substituteVars string)]) :: IO () |] --- | Parse references to Haskell variables-string2exp :: String -> Q Exp-string2exp = raw where+-- | Construct Haskell expression from the string, substituting variables+-- for their values. Variable expansion uses a ruby-like syntax+substituteVars :: String -> Q Exp+substituteVars = raw where   raw, var :: String -> Q Exp   raw (break (== '#') -> parts) = case parts of     (before, '#':'{' :after) -> [e| before ++ $(var after) |]@@ -140,7 +145,6 @@   var (break (== '}') -> parts) = case parts of      (b:efore, '}':after)         | isLower b                    -> external (VarE (mkName (b:efore))) after-        | isUpper b                    -> external (ConE (mkName (b:efore))) after         | isUpper b                    -> external (ConE (mkName (b:efore))) after         | Just i <- readMaybe (b:efore) -> external (LitE (IntegerL i)) after         | Just d <- readMaybe (b:efore) -> external (LitE (RationalL (toRational (d :: Double)))) after
+ test/Doctests.hs view
@@ -0,0 +1,13 @@+module Main where++import Test.DocTest (doctest)+++main :: IO ()+main = doctest+  [ "src/System/Command/QQ.hs"+  , "src/System/Command/QQ/Embed.hs"+  , "src/System/Command/QQ/Eval.hs"+  , "src/System/Command/QQ/Predef.hs"+  , "example/CommandT.hs"+  ]
+ test/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
+ test/System/Command/QQ/EmbedSpec.hs view
@@ -0,0 +1,105 @@+module System.Command.QQ.EmbedSpec (spec) where++import Data.Int+import Data.Ratio+import Data.Word+import Foreign.C.Types+import System.Command.QQ+import Test.Hspec+++spec :: Spec+spec =+  describe "embedding" $ do+    describe "Haskell types" $ do+      describe "numeric types" $ do+        it "embeds Integer" $+          embed (4 :: Integer) `shouldBe` "4"++        it "embeds Int" $+          embed (4 :: Int) `shouldBe` "4"++        it "embeds Int8" $+          embed (4 :: Int8) `shouldBe` "4"++        it "embeds Int16" $+          embed (4 :: Int16) `shouldBe` "4"++        it "embeds Int32" $+          embed (4 :: Int32) `shouldBe` "4"++        it "embeds Int64" $+          embed (4 :: Int64) `shouldBe` "4"++        it "embeds Word" $+          embed (4 :: Word) `shouldBe` "4"++        it "embeds Word8" $+          embed (4 :: Word8) `shouldBe` "4"++        it "embeds Word16" $+          embed (4 :: Word16) `shouldBe` "4"++        it "embeds Word32" $+          embed (4 :: Word32) `shouldBe` "4"++        it "embeds Word64" $+          embed (4 :: Word64) `shouldBe` "4"++        it "embeds Float" $+          embed (7 :: Float) `shouldBe` "7.0"++        it "embeds Double" $+          embed (7 :: Double) `shouldBe` "7.0"++        it "embeds Rational" $+          embed (3 % 5) `shouldBe` "0.6"++      it "embeds Char" $+        embed 'e' `shouldBe` "e"++      it "embeds String" $+        embed "foo" `shouldBe` "foo"++    describe "C types" $ do+      it "embeds CChar" $+        embed (4 :: CChar) `shouldBe` "4"++      it "embeds CSChar" $+        embed (4 :: CSChar) `shouldBe` "4"++      it "embeds CUChar" $+        embed (4 :: CUChar) `shouldBe` "4"++      it "embeds CShort" $+        embed (4 :: CShort) `shouldBe` "4"++      it "embeds CUShort" $+        embed (4 :: CUShort) `shouldBe` "4"++      it "embeds CInt" $+        embed (4 :: CInt) `shouldBe` "4"++      it "embeds CUInt" $+        embed (4 :: CUInt) `shouldBe` "4"++      it "embeds CLong" $+        embed (4 :: CLong) `shouldBe` "4"++      it "embeds CULong" $+        embed (4 :: CULong) `shouldBe` "4"++      it "embeds CSize" $+        embed (4 :: CSize) `shouldBe` "4"++      it "embeds CLLong" $+        embed (4 :: CLLong) `shouldBe` "4"++      it "embeds CULLong" $+        embed (4 :: CULLong) `shouldBe` "4"++      it "embeds CFloat" $+        embed (7 :: CFloat) `shouldBe` "7.0"++      it "embeds CDouble" $+        embed (7 :: CDouble) `shouldBe` "7.0"
+ test/System/Command/QQ/EvalSpec.hs view
@@ -0,0 +1,94 @@+{-# LANGUAGE ExtendedDefaultRules #-}+{-# LANGUAGE QuasiQuotes #-}+module System.Command.QQ.EvalSpec (spec) where++import Data.Text.Lazy (Text, pack)+import System.Command.QQ+import System.Exit (ExitCode(..))+import Test.Hspec+++spec :: Spec+spec = do+  describe "quasiquotation" $ do+    context "unicode" $ do+      it "works with unicode symbols in the String output" $+        [sh|echo -n "ДМИТРИЙ МАЛИКОВ"|] `shouldReturn` "ДМИТРИЙ МАЛИКОВ"++      it "works with unicode symbols in the Text output" $+        [sh|echo -n "ЕГОР ЛЕТОВ"|] `shouldReturn` text "ЕГОР ЛЕТОВ"++    context "exit code" $ do+      it "is possible to get successful exit code" $+        [sh|exit 0|] `shouldReturn` ExitSuccess++      it "is possible to get unsuccessful exit code" $+        [sh|exit 4|] `shouldReturn` ExitFailure 4++    it "is possible to get all of exitcode, stdout, and stderr" $+      [sh|echo -n hello; echo -n world >&2; exit 4|] `shouldReturn`+        (ExitFailure 4, text "hello", text "world")++  describe "embedding" $ do+    describe "variable embeddings" $ do++      it "can embed integers" $+        let foo = 7 in [sh|echo #{foo}|] `shouldReturn` "7\n"++      it "can embed doubles" $+        let foo = 7.0 in [sh|echo #{foo}|] `shouldReturn` "7.0\n"++      it "can embed characters" $+        let foo = 'z' in [sh|echo #{foo}|] `shouldReturn` "z\n"++      it "can embed strings" $+        let foo = "hello" in [sh|echo #{foo}|] `shouldReturn` "hello\n"++    describe "multi-line embeddings" $ do+      it "supports multiline commands" $+        [sh|+          echo hello+          echo world+          echo !!!+        |] `shouldReturn` "hello\nworld\n!!!\n"++      it "supports embeddings in multiline commands" $+        let foo = 4+            bar = 7+        in [sh|+          echo #{foo}+          echo #{bar}+        |] `shouldReturn` "4\n7\n"++    describe "escapings" $ do+      it "is possible to write #{} literally as a comment" $ do+        [sh|echo #\{foo}|] `shouldReturn` "\n"+        [sh|echo #\\{foo}|] `shouldReturn` "\n"++      it "is possible to write #{} literally as a string" $ do+        [sh|echo "#\{foo}"|] `shouldReturn` "#{foo}\n"+        [sh|echo "#\\{foo}"|] `shouldReturn` "#\\{foo}\n"++    describe "literals" $ do+      it "is possible to embed integer literals" $+        [sh|echo -n #{4}|] `shouldReturn` "4"++      it "is possible to embed rational literals" $+        [sh|echo -n #{4.0}|] `shouldReturn` "4.0"++      it "is possible to embed char literals" $+        [sh|echo -n #{'q'}|] `shouldReturn` "q"++      it "is possible to embed string literals" $+        [sh|echo -n #{"hello"}|] `shouldReturn` "hello"++    describe "custom data types" $+      it "is possible to embed custom data types" $+        [sh|echo -n hello#{Bang}|] `shouldReturn` "hello!"++data Bang = Bang++instance Embed Bang where embed Bang = "!"++text :: String -> Text+text = pack
− tests/Doctests.hs
@@ -1,13 +0,0 @@-module Main where--import Test.DocTest (doctest)---main :: IO ()-main = doctest-  [ "src/System/Command/QQ.hs"-  , "src/System/Command/QQ/Embed.hs"-  , "src/System/Command/QQ/Eval.hs"-  , "src/System/Command/QQ/Predef.hs"-  , "examples/CommandT.hs"-  ]
− tests/Spec.hs
@@ -1,1 +0,0 @@-{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
− tests/System/Command/QQ/EmbedSpec.hs
@@ -1,105 +0,0 @@-module System.Command.QQ.EmbedSpec (spec) where--import Data.Int-import Data.Ratio-import Data.Word-import Foreign.C.Types-import System.Command.QQ-import Test.Hspec---spec :: Spec-spec =-  describe "embedding" $ do-    describe "Haskell types" $ do-      describe "numeric types" $ do-        it "embeds Integer" $-          embed (4 :: Integer) `shouldBe` "4"--        it "embeds Int" $-          embed (4 :: Int) `shouldBe` "4"--        it "embeds Int8" $-          embed (4 :: Int8) `shouldBe` "4"--        it "embeds Int16" $-          embed (4 :: Int16) `shouldBe` "4"--        it "embeds Int32" $-          embed (4 :: Int32) `shouldBe` "4"--        it "embeds Int64" $-          embed (4 :: Int64) `shouldBe` "4"--        it "embeds Word" $-          embed (4 :: Word) `shouldBe` "4"--        it "embeds Word8" $-          embed (4 :: Word8) `shouldBe` "4"--        it "embeds Word16" $-          embed (4 :: Word16) `shouldBe` "4"--        it "embeds Word32" $-          embed (4 :: Word32) `shouldBe` "4"--        it "embeds Word64" $-          embed (4 :: Word64) `shouldBe` "4"--        it "embeds Float" $-          embed (7 :: Float) `shouldBe` "7.0"--        it "embeds Double" $-          embed (7 :: Double) `shouldBe` "7.0"--        it "embeds Rational" $-          embed (3 % 5) `shouldBe` "0.6"--      it "embeds Char" $-        embed 'e' `shouldBe` "e"--      it "embeds String" $-        embed "foo" `shouldBe` "foo"--    describe "C types" $ do-      it "embeds CChar" $-        embed (4 :: CChar) `shouldBe` "4"--      it "embeds CSChar" $-        embed (4 :: CSChar) `shouldBe` "4"--      it "embeds CUChar" $-        embed (4 :: CUChar) `shouldBe` "4"--      it "embeds CShort" $-        embed (4 :: CShort) `shouldBe` "4"--      it "embeds CUShort" $-        embed (4 :: CUShort) `shouldBe` "4"--      it "embeds CInt" $-        embed (4 :: CInt) `shouldBe` "4"--      it "embeds CUInt" $-        embed (4 :: CUInt) `shouldBe` "4"--      it "embeds CLong" $-        embed (4 :: CLong) `shouldBe` "4"--      it "embeds CULong" $-        embed (4 :: CULong) `shouldBe` "4"--      it "embeds CSize" $-        embed (4 :: CSize) `shouldBe` "4"--      it "embeds CLLong" $-        embed (4 :: CLLong) `shouldBe` "4"--      it "embeds CULLong" $-        embed (4 :: CULLong) `shouldBe` "4"--      it "embeds CFloat" $-        embed (7 :: CFloat) `shouldBe` "7.0"--      it "embeds CDouble" $-        embed (7 :: CDouble) `shouldBe` "7.0"
− tests/System/Command/QQ/EvalSpec.hs
@@ -1,94 +0,0 @@-{-# LANGUAGE ExtendedDefaultRules #-}-{-# LANGUAGE QuasiQuotes #-}-module System.Command.QQ.EvalSpec (spec) where--import Data.Text.Lazy (Text, pack)-import System.Command.QQ-import System.Exit (ExitCode(..))-import Test.Hspec---spec :: Spec-spec = do-  describe "quasiquotation" $ do-    context "unicode" $ do-      it "works with unicode symbols in the String output" $-        [sh|echo -n "ДМИТРИЙ МАЛИКОВ"|] `shouldReturn` "ДМИТРИЙ МАЛИКОВ"--      it "works with unicode symbols in the Text output" $-        [sh|echo -n "ЕГОР ЛЕТОВ"|] `shouldReturn` text "ЕГОР ЛЕТОВ"--    context "exit code" $ do-      it "is possible to get successful exit code" $-        [sh|exit 0|] `shouldReturn` ExitSuccess--      it "is possible to get unsuccessful exit code" $-        [sh|exit 4|] `shouldReturn` ExitFailure 4--    it "is possible to get all of exitcode, stdout, and stderr" $-      [sh|echo -n hello; echo -n world >&2; exit 4|] `shouldReturn`-        (ExitFailure 4, text "hello", text "world")--  describe "embedding" $ do-    describe "variable embeddings" $ do--      it "can embed integers" $-        let foo = 7 in [sh|echo #{foo}|] `shouldReturn` "7\n"--      it "can embed doubles" $-        let foo = 7.0 in [sh|echo #{foo}|] `shouldReturn` "7.0\n"--      it "can embed characters" $-        let foo = 'z' in [sh|echo #{foo}|] `shouldReturn` "z\n"--      it "can embed strings" $-        let foo = "hello" in [sh|echo #{foo}|] `shouldReturn` "hello\n"--    describe "multi-line embeddings" $ do-      it "supports multiline commands" $-        [sh|-          echo hello-          echo world-          echo !!!-        |] `shouldReturn` "hello\nworld\n!!!\n"--      it "supports embeddings in multiline commands" $-        let foo = 4-            bar = 7-        in [sh|-          echo #{foo}-          echo #{bar}-        |] `shouldReturn` "4\n7\n"--    describe "escapings" $ do-      it "is possible to write #{} literally as a comment" $ do-        [sh|echo #\{foo}|] `shouldReturn` "\n"-        [sh|echo #\\{foo}|] `shouldReturn` "\n"--      it "is possible to write #{} literally as a string" $ do-        [sh|echo "#\{foo}"|] `shouldReturn` "#{foo}\n"-        [sh|echo "#\\{foo}"|] `shouldReturn` "#\\{foo}\n"--    describe "literals" $ do-      it "is possible to embed integer literals" $-        [sh|echo -n #{4}|] `shouldReturn` "4"--      it "is possible to embed rational literals" $-        [sh|echo -n #{4.0}|] `shouldReturn` "4.0"--      it "is possible to embed char literals" $-        [sh|echo -n #{'q'}|] `shouldReturn` "q"--      it "is possible to embed string literals" $-        [sh|echo -n #{"hello"}|] `shouldReturn` "hello"--    describe "custom data types" $-      it "is possible to embed custom data types" $-        [sh|echo -n hello#{Bang}|] `shouldReturn` "hello!"--data Bang = Bang--instance Embed Bang where embed Bang = "!"--text :: String -> Text-text = pack