packages feed

command-qq 0.3.0.0 → 0.3.1.0

raw patch · 10 files changed

+168/−63 lines, 10 filesdep +transformersPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: transformers

API changes (from Hackage documentation)

- System.Command.QQ.Embed: instance Embed CChar
- System.Command.QQ.Embed: instance Embed CDouble
- System.Command.QQ.Embed: instance Embed CFloat
- System.Command.QQ.Embed: instance Embed CInt
- System.Command.QQ.Embed: instance Embed CLLong
- System.Command.QQ.Embed: instance Embed CLong
- System.Command.QQ.Embed: instance Embed CSChar
- System.Command.QQ.Embed: instance Embed CShort
- System.Command.QQ.Embed: instance Embed CSize
- System.Command.QQ.Embed: instance Embed CUChar
- System.Command.QQ.Embed: instance Embed CUInt
- System.Command.QQ.Embed: instance Embed CULLong
- System.Command.QQ.Embed: instance Embed CULong
- System.Command.QQ.Embed: instance Embed CUShort
- System.Command.QQ.Embed: instance Embed Char
- System.Command.QQ.Embed: instance Embed Double
- System.Command.QQ.Embed: instance Embed Float
- System.Command.QQ.Embed: instance Embed Int
- System.Command.QQ.Embed: instance Embed Int16
- System.Command.QQ.Embed: instance Embed Int32
- System.Command.QQ.Embed: instance Embed Int64
- System.Command.QQ.Embed: instance Embed Int8
- System.Command.QQ.Embed: instance Embed Integer
- System.Command.QQ.Embed: instance Embed String
- System.Command.QQ.Embed: instance Embed Text
- System.Command.QQ.Embed: instance Embed Word
- System.Command.QQ.Embed: instance Embed Word16
- System.Command.QQ.Embed: instance Embed Word32
- System.Command.QQ.Embed: instance Embed Word64
- System.Command.QQ.Embed: instance Embed Word8
- System.Command.QQ.Embed: instance a ~ Integer => Embed (Ratio a)
- System.Command.QQ.Eval: instance (i ~ Text, o ~ (ExitCode, Text, Text)) => Eval (i -> IO o)
- System.Command.QQ.Eval: instance (s ~ ExitCode, o ~ Text, e ~ Text) => Eval (IO (s, o, e))
- System.Command.QQ.Eval: instance Eval (IO ())
- System.Command.QQ.Eval: instance Eval (IO ExitCode)
- System.Command.QQ.Eval: instance Eval (IO String)
- System.Command.QQ.Eval: instance Eval (IO Text)
+ System.Command.QQ.Embed: instance (a Data.Type.Equality.~ GHC.Integer.Type.Integer) => System.Command.QQ.Embed.Embed (GHC.Real.Ratio a)
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed Data.Text.Internal.Lazy.Text
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed Data.Text.Internal.Text
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed Foreign.C.Types.CChar
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed Foreign.C.Types.CDouble
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed Foreign.C.Types.CFloat
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed Foreign.C.Types.CInt
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed Foreign.C.Types.CLLong
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed Foreign.C.Types.CLong
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed Foreign.C.Types.CSChar
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed Foreign.C.Types.CShort
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed Foreign.C.Types.CSize
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed Foreign.C.Types.CUChar
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed Foreign.C.Types.CUInt
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed Foreign.C.Types.CULLong
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed Foreign.C.Types.CULong
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed Foreign.C.Types.CUShort
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed GHC.Base.String
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed GHC.Int.Int16
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed GHC.Int.Int32
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed GHC.Int.Int64
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed GHC.Int.Int8
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed GHC.Integer.Type.Integer
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed GHC.Types.Char
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed GHC.Types.Double
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed GHC.Types.Float
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed GHC.Types.Int
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed GHC.Types.Word
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed GHC.Word.Word16
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed GHC.Word.Word32
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed GHC.Word.Word64
+ System.Command.QQ.Embed: instance System.Command.QQ.Embed.Embed GHC.Word.Word8
+ System.Command.QQ.Eval: instance (i Data.Type.Equality.~ Data.Text.Internal.Lazy.Text, o Data.Type.Equality.~ (GHC.IO.Exception.ExitCode, Data.Text.Internal.Lazy.Text, Data.Text.Internal.Lazy.Text)) => System.Command.QQ.Eval.Eval (i -> GHC.Types.IO o)
+ System.Command.QQ.Eval: instance (s Data.Type.Equality.~ GHC.IO.Exception.ExitCode, o Data.Type.Equality.~ Data.Text.Internal.Lazy.Text, e Data.Type.Equality.~ Data.Text.Internal.Lazy.Text) => System.Command.QQ.Eval.Eval (GHC.Types.IO (s, o, e))
+ System.Command.QQ.Eval: instance System.Command.QQ.Eval.Eval (GHC.Types.IO ())
+ System.Command.QQ.Eval: instance System.Command.QQ.Eval.Eval (GHC.Types.IO Data.Text.Internal.Lazy.Text)
+ System.Command.QQ.Eval: instance System.Command.QQ.Eval.Eval (GHC.Types.IO GHC.Base.String)
+ System.Command.QQ.Eval: instance System.Command.QQ.Eval.Eval (GHC.Types.IO GHC.IO.Exception.ExitCode)
- System.Command.QQ.Embed: class Embed a where embed = show
+ System.Command.QQ.Embed: class Embed a
- System.Command.QQ.Embed: embed :: Embed a => a -> String
+ System.Command.QQ.Embed: embed :: (Embed a, Show a) => a -> String

Files

CHANGELOG.md view
@@ -1,3 +1,12 @@+0.3.1.0+=======++  * Improved exception handling++  * Relaxed the licesnse to BSD2++  * Made compatible with GHC 8.8+ 0.3.0.0 ======= 
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2013, Matvey Aksenov+Copyright (c) 2013-2017, Matvey Aksenov  All rights reserved. @@ -12,10 +12,6 @@       copyright notice, this list of conditions and the following       disclaimer in the documentation and/or other materials provided       with the distribution.--    * Neither the name of Matvey Aksenov nor the names of other-      contributors may be used to endorse or promote products derived-      from this software without specific prior written permission.  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
README.md view
@@ -74,4 +74,4 @@ See [`examples/CommandT.hs`][1]    [0]: https://github.com/biegunka/command-qq/blob/master/src/System/Command/QQ/Predef.hs-  [1]: https://github.com/biegunka/command-qq/blob/master/examples/CommandT.hs+  [1]: https://github.com/biegunka/command-qq/blob/master/example/CommandT.hs
command-qq.cabal view
@@ -1,5 +1,5 @@ name:                command-qq-version:             0.3.0.0+version:             0.3.1.0 synopsis:            Quasiquoters for external commands description:   Features:@@ -29,7 +29,7 @@     See @examples/CommandT.hs@   . homepage:            http://biegunka.github.io/command-qq/-license:             BSD3+license:             BSD2 license-file:        LICENSE author:              Matvey Aksenov maintainer:          matvey.aksenov@gmail.com@@ -48,7 +48,7 @@ source-repository this   type:              git   location:          https://github.com/biegunka/command-qq-  tag:               0.3.0.0+  tag:               0.3.1.0  library   default-language:  Haskell2010@@ -70,6 +70,7 @@   build-depends:       base == 4.*     , doctest+    , transformers   hs-source-dirs:    test   main-is:           Doctests.hs @@ -89,3 +90,5 @@   other-modules:     System.Command.QQ.EmbedSpec     System.Command.QQ.EvalSpec+    System.Command.QQ.PredefSpec+    System.Command.QQSpec
src/System/Command/QQ.hs view
@@ -19,16 +19,16 @@   , module System.Command.QQ.Eval   ) where -import Control.Applicative-import Data.Char (isLower, isUpper)-import Data.Maybe (fromMaybe)-import Language.Haskell.TH-import Language.Haskell.TH.Quote-import System.Environment (lookupEnv)-import Text.Read (readMaybe)+import           Data.Char (isLower, isUpper)+import           Data.Maybe (fromMaybe)+import           Language.Haskell.TH (Q, Exp)+import qualified Language.Haskell.TH as TH+import           Language.Haskell.TH.Quote (QuasiQuoter(..))+import           System.Environment (lookupEnv)+import           Text.Read (readMaybe) -import System.Command.QQ.Embed-import System.Command.QQ.Eval+import           System.Command.QQ.Embed+import           System.Command.QQ.Eval  -- $setup -- >>> :set -XQuasiQuotes@@ -56,7 +56,7 @@ -- "7 apples!\n" sh :: QuasiQuoter sh = quoter $ \string -> do-  shellEx <- runIO $ getEnvDefault "/bin/sh" "SHELL"+  shellEx <- TH.runIO (getEnvDefault "/bin/sh" "SHELL")   callCommand shellEx ["-c"] string  -- | Simple quasiquoter for the default shell@@ -68,7 +68,7 @@ -- hello, world! sh_ :: QuasiQuoter sh_ = quoter $ \string -> do-  shellEx <- runIO $ getEnvDefault "/bin/sh" "SHELL"+  shellEx <- TH.runIO (getEnvDefault "/bin/sh" "SHELL")   callCommand_ shellEx ["-c"] string  -- | Shell's quasiquoter constructor@@ -110,7 +110,7 @@   }  where   failure kind =-    fail $ "this quasiquoter does not support splicing " ++ kind+    error ("this quasiquoter does not support splicing " ++ kind)  -- | Construct Haskell expression for external command call callCommand@@ -146,14 +146,14 @@       _                            -> fail "Should never happen"    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-        | Just i <- readMaybe (b:efore) -> external (LitE (IntegerL i)) after-        | Just d <- readMaybe (b:efore) -> external (LitE (RationalL (toRational (d :: Double)))) after-        | Just c <- readMaybe (b:efore) -> external (LitE (CharL c)) after-        | Just s <- readMaybe (b:efore) -> external (LitE (StringL s)) after-     (before, _)                        -> fail $ "Invalid name: " ++ before+    (b : efore, '}' : after)+      | isLower b                     -> external (TH.VarE (TH.mkName (b:efore))) after+      | isUpper b                     -> external (TH.ConE (TH.mkName (b:efore))) after+      | Just i <- readMaybe (b:efore) -> external (TH.LitE (TH.IntegerL i)) after+      | Just d <- readMaybe (b:efore) -> external (TH.LitE (TH.RationalL (toRational (d :: Double)))) after+      | Just c <- readMaybe (b:efore) -> external (TH.LitE (TH.CharL c)) after+      | Just s <- readMaybe (b:efore) -> external (TH.LitE (TH.StringL s)) after+    (before, _)                        -> fail ("Invalid name: " ++ before)    external :: Exp -> String -> Q Exp   external e after = [e| embed $(return e) ++ $(raw after) |]@@ -163,4 +163,4 @@   :: String -- ^ The default vefault   -> String -- ^ Environment variable   -> IO String-getEnvDefault def query = fromMaybe def <$> lookupEnv query+getEnvDefault def = fmap (fromMaybe def) . lookupEnv
src/System/Command/QQ/Embed.hs view
@@ -6,7 +6,6 @@   ( Embed(..)   ) where -import           Control.Applicative import           Data.Int import           Data.Ratio (Ratio) import qualified Data.Text as Text@@ -71,7 +70,7 @@ -- >>> embed 'c' -- "c" instance Embed Char where-  embed = pure+  embed x = [x]  -- | -- >>> embed ("hi" :: String)
src/System/Command/QQ/Eval.hs view
@@ -5,13 +5,13 @@   ( Eval(..)   ) where -import           Control.Applicative import           Control.Concurrent-import           Control.Exception (evaluate)+import           Control.Exception (evaluate, mask, onException) import           Control.Monad+import           Data.Foldable (traverse_) import           Data.Text.Lazy (Text)-import qualified Data.Text.Lazy as T-import qualified Data.Text.Lazy.IO as T+import qualified Data.Text.Lazy as Text+import qualified Data.Text.Lazy.IO as Text import           System.Exit (ExitCode) import qualified System.Process as P import           System.IO (hFlush, hClose)@@ -33,7 +33,7 @@ -- >>> [sh|echo hello world|] :: IO () -- hello world instance Eval (IO ()) where-  eval command args = () <$ P.rawSystem command args+  eval command = void . P.rawSystem command  -- | Return exit code of the external process --@@ -44,7 +44,7 @@ -- ExitFailure 7 instance Eval (IO ExitCode) where   eval command args = do-    (s, _, _) <- eval command args (T.pack "")+    (s, _, _) <- eval command args Text.empty     return s  -- | Return stdout of the external process as 'Text'@@ -65,7 +65,7 @@ -- >>> [sh|echo -n hello world|] :: IO String -- "hello world" instance Eval (IO String) where-  eval command args = T.unpack <$> eval command args+  eval command = fmap Text.unpack . eval command  -- | Return exit code, stdout, and stderr of external process --@@ -76,7 +76,7 @@   , o ~ Text   , e ~ Text   ) => Eval (IO (s, o, e)) where-  eval command args = eval command args (T.pack "")+  eval command args = eval command args Text.empty  -- | Return exit code, stdout, and stderr of the external process -- and pass supplied 'Text' to its stdin@@ -90,30 +90,36 @@   eval = readProcessWithExitCode  readProcessWithExitCode :: String -> [String] -> Text -> IO (ExitCode, Text, Text)-readProcessWithExitCode cmd args input = do-  (Just inh, Just outh, Just errh, p) <--      P.createProcess (P.proc cmd args)-        { P.std_in  = P.CreatePipe-        , P.std_out = P.CreatePipe-        , P.std_err = P.CreatePipe-        }+readProcessWithExitCode cmd args input =+  mask $ \restore -> do+    (Just inh, Just outh, Just errh, pid) <-+        P.createProcess (P.proc cmd args)+          { P.std_in  = P.CreatePipe+          , P.std_out = P.CreatePipe+          , P.std_err = P.CreatePipe+          } -  var <- newEmptyMVar-  out <- T.hGetContents outh-  err <- T.hGetContents errh+    onException+      (restore $ do+        var <- newEmptyMVar+        out <- Text.hGetContents outh+        err <- Text.hGetContents errh -  forkFinally (evaluate (T.length out)) (\_ -> putMVar var ())-  forkFinally (evaluate (T.length err)) (\_ -> putMVar var ())+        forkFinally (evaluate (Text.length out)) (\_ -> putMVar var ())+        forkFinally (evaluate (Text.length err)) (\_ -> putMVar var ()) -  unless (T.null input) $-    T.hPutStr inh input >> hFlush inh-  hClose inh+        unless (Text.null input) $+          Text.hPutStr inh input >> hFlush inh+        hClose inh -  takeMVar var-  takeMVar var-  hClose outh-  hClose errh+        takeMVar var+        takeMVar var+        hClose outh+        hClose errh -  s <- P.waitForProcess p+        s <- P.waitForProcess pid -  return (s, out, err)+        return (s, out, err))+      (do P.terminateProcess pid+          traverse_ hClose [inh, outh, errh]+          P.waitForProcess pid)
src/System/Command/QQ/Predef.hs view
@@ -5,6 +5,7 @@  import System.Command.QQ (interpreter, shell, quoter, callCommand) + -- | @bash@ shell bash :: QuasiQuoter bash = shell "bash"@@ -15,11 +16,11 @@  -- | @awk@ interpreter awk :: QuasiQuoter-awk = quoter $ callCommand "awk" []+awk = quoter (callCommand "awk" [])  -- | @ghci@ interpreter ghci :: QuasiQuoter-ghci = quoter $ callCommand "ghc" ["-ignore-dot-ghci", "-e"]+ghci = quoter (callCommand "ghc" ["-ignore-dot-ghci", "-e"])  -- | @perl@ interpreter perl :: QuasiQuoter
+ test/System/Command/QQ/PredefSpec.hs view
@@ -0,0 +1,54 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}+module System.Command.QQ.PredefSpec (spec) where++import           Data.Text.Lazy (Text)+import qualified Data.Text.Lazy as Text+import           System.Exit (ExitCode(..))+import           Test.Hspec++import           System.Command.QQ.Predef+++spec :: Spec+spec = do+  it "runs bash" $+    fmap stdout [bash|echo $0|] `shouldReturn` "bash\n"++  it "runs zsh" $+    fmap stdout [zsh|echo $0|] `shouldReturn` "zsh\n"++  it "runs awk interpreter" $+    fmap stdout [awk|BEGIN { print 4 * 7 } |] `shouldReturn` "28\n"++  it "runs ghci" $+    fmap stdout [ghci|print (4 * 7)|] `shouldReturn` "28\n"++  it "runs perl interpreter" $+    fmap stdout [perl|print 4 * 7 . "\n"|] `shouldReturn` "28\n"++  it "runs ruby interpreter" $+    fmap stdout [ruby|puts 4 * 7|] `shouldReturn` "28\n"++  let traceback = "Traceback (most recent call last):"++  it "python shows tracebacks" $ do+    err <- fmap (Text.lines . stderr) [python|print(4 / 0)|]+    err `shouldContain` [traceback]++  it "python2 shows tracebacks" $ do+    err <- fmap (Text.lines . stderr) [python2|print(4 / 0)|]+    err `shouldContain` [traceback]++  it "python3 shows tracebacks" $ do+    err <- fmap (Text.lines . stderr) [python3|print(4 / 0)|]+    err `shouldContain` [traceback]++  it "python3 really runs python 3" $ do+    err <- fmap (Text.lines . stderr) [python3|print 7|]+    err `shouldSatisfy` (any ("SyntaxError:" `Text.isPrefixOf`))+++stdout, stderr :: (ExitCode, Text, Text) -> Text+stderr (_, _, xs) = xs+stdout (_, xs, _) = xs
+ test/System/Command/QQSpec.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE TemplateHaskell #-}+module System.Command.QQSpec (spec) where++import Test.Hspec++import System.Command.QQ (substituteVars)+++spec :: Spec+spec = do+  describe "substituteVars" $ do+    it "does not change simple string literals" $+      $(substituteVars "hello!") `shouldBe` "hello!"++    it "substitutes variables of type Int" $ do+      let foo = 5 :: Int+      $(substituteVars "hello#{foo}bye!") `shouldBe` "hello5bye!"++    it "substitutes variables of type String" $ do+      let foo = "or"+      $(substituteVars "hello#{foo}bye!") `shouldBe` "helloorbye!"++    it "leaves an escape hatch for typing literal #{} in" $ do+      let foo = "or"+      $(substituteVars "hello#\\{foo}bye!") `shouldBe` "hello#{foo}bye!"++    it "escape hatch can be escaped" $ do+      let foo = "or"+      $(substituteVars "hello#\\\\{foo}bye!") `shouldBe` "hello#\\{foo}bye!"++    it "leaves another (possibly more natural) escape hatch for typing literal #{} in" $ do+      let foo = "or"+      $(substituteVars "hello\\#{foo}bye!") `shouldBe` "hello#{foo}bye!"++    it "another escape hatch can be escaped too" $ do+      let foo = "or"+      $(substituteVars "hello\\\\#{foo}bye!") `shouldBe` "hello\\orbye!"