packages feed

eddie 0.2 → 0.5

raw patch · 12 files changed

+307/−115 lines, 12 files

Files

eddie.1 view
@@ -2,13 +2,9 @@ .SH NAME eddie \- run haskell filters from the command line .SH SYNOPSYS-.B eddie -[-.I options-]-[-.I expr-]+.B eddie+.RI [ options ]+.RI [ expr ] .I file ... .SH DESCRIPTION .B eddie@@ -19,44 +15,53 @@ arguments concatenated together, or standard input if no file arguments are present. .PP-If the-.B \-l-option is used, the +The+.BR \-\-line ,+.B \-\-file+and+.B \-\-list+options can be used to cause .I expression-is used to process each line instead of the entire contents.+to be used to process each line, each file,+or a list of files or lines respectively. .PP The prelude, Data.List and Data.Char modules are available for building expressions. Other modules may be added with the-.B \-M+.B \-\-Modules and-.B \-m+.B \-\-modules options. .SH OPTIONS-.IP \-e+.IP \-\-expr The-.BI \-e\  expr-(long form-.BI \-\-expr\  expr)+.B \-\-expr+.I expr+(short form+.B \-e+.IR expr ) option concatenates it's value to the haskell expression being evaluated with a newline separator. Multiple occurrences can be used to build up a multi-line expression.-.IP ""+.RS+.PP If no-.BI \-e\  expr+.B \-e+.I expr option is present, the first non-flag argument will be used for the haskell expression.-.IP \-l+.RE 1+.IP \-\-line The-.B \-l-(long form .B \-\-line-)+(short form+.BR \-l ) option causes .B eddie to process input line at a time. The .I expr-will be run on each line and the results concatenated together.+will be run on each line and the results concatenated together+(using unlines). .RS .PP The command@@ -71,32 +76,101 @@ .PP .B eddie "unlines . map+.IR expr  .+lines"+.I file ...+.+.RE 1+.IP \-\-file+The+.B \-\-file+(short form+.BR \-f )+causes each file to be processed individually.+.RS+.PP+Note that the+.B \-l+and+.B \-f+options cannot be used together.+.RE 1+.IP \-\-list+The+.B \-\-list+(short form+.BR \-L )+option causes+.B eddie+to pass the expression a list of lines or files.+This requires one of the+.B \-l+or+.B \-f+options be used.+.RS+.PP+The command+.RS+.PP+.B eddie \-lL+.I expr file ...+.RE+.PP+is equivalent to the command+.RS+.PP+.B eddie+"unlines . .I expr \&. lines" .I file ... . .RE 1-.IP \-m+.IP \-\-binary The-.BI \-m name-(long form-.BI \-\-module name-)+.B \-\-binary+(short form+.BR \-b )+option switches the output mode to binary.+It also disables the maybe newline processing.+Normally +.B eddie+will output a final newline if the last character+of the input is not a newline to place the prompt properly.+If the+.B \-b+option is used, the final newline will not be output.+.RE 1+.IP \-\-modules+The+.B \-\-modules+.I name+(short form+.B \-m +.IR name ) option is used to import module .I name into haskell before evaluating the expression.-.IP \-M+.IP \-\-Modules The-.BI \-M name,as-(long form-.BI \-\-Modules name,as-)+.B \-\-Modules+.I name,as+(short form+.B \-M+.IR name,as ) option imports the .I name module using a qualified import with an as clause, with  .I as being the value for the as clause.+.SH DIAGNOSTICS+If the command runs with no problems, eddie will exit with a status of 0.+If there are problems with the options, such that the expression is never+evaluated, then eddie will exit with a status of 1.+If haskell returns an error - probably a compilation problem - then+eddie will exit with the status of 2. .SH SEE ALSO The wiki at <http://code.google.com/p/eddie/w/list> for examples. .SH BUGS
eddie.cabal view
@@ -1,5 +1,5 @@ Name:                eddie-Version:             0.2+Version:             0.5 Synopsis:	     Command line file filtering with haskell Description:	     A tool to let you use short haskell expressions to filter 		     files at the command line.@@ -12,7 +12,7 @@ Build-type:          Simple Homepage:	     http://eddie.googlecode.com/ Cabal-version:       >=1.8-Extra-source-files:  test.sh eddie.1+Extra-source-files:  eddie.1 tests/*.test tests/*.data  Executable eddie     Main-is:         eddie.hs
eddie.hs view
@@ -1,76 +1,103 @@+#!/usr/bin/env runghc {-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE GADTs #-}  -- import Data.ByteString.Lazy (readFile) import Language.Haskell.Interpreter   (setImportsQ, interpret, runInterpreter, as, MonadInterpreter) import Data.IORef (newIORef, readIORef, writeIORef) import System.Environment (getArgs, getProgName)-import System.IO (openFile, openBinaryFile, hClose, stdin, IOMode (ReadMode), -                  hIsEOF, hGetChar, Handle, hSetBinaryMode, stdout)+import System.IO+       (openFile, openBinaryFile, hClose, stdin, IOMode (ReadMode), hIsEOF,+        hGetChar, Handle, hSetBinaryMode, stdout, stderr, hPutStrLn) import System.IO.Unsafe (unsafeInterleaveIO) import System.Console.CmdArgs.Implicit   (cmdArgs, (&=), Data, Typeable, help, explicit, name, args, summary, program,    details)+import System.Exit (exitWith, ExitCode (..)) import Control.Exception (finally, evaluate)-import Control.Monad     (when)+import Control.Monad     (when, liftM, join)  main = do   myName <- getProgName   opts <- cmdArgs (eddie &= program myName)   case parseOpts opts of-    Left e -> putStrLn $ "usage: " ++ myName ++ " " ++ e+    Left e -> do hPutStrLn stderr $ "usage: " ++ myName ++ " " ++ e+                 exitWith (ExitFailure 1)     Right o -> runIt myName o       where runIt name opts = do-              fun <- runInterpreter $ makeFun opts               let opener = if binary opts then openBinaryFile else openFile-              let outputFunction = if binary opts then putStr else putStrLn-              when (binary opts) $-                hSetBinaryMode stdout True+              let outputFunc = putStrMaybeLn (binary opts)+              when (binary opts) $ hSetBinaryMode stdout True+              fun <- runInterpreter $ makeFun opts               case fun of-                Left e -> putStrLn $ name ++ ": Error: " ++ show e-                Right f -> withFiles (files opts) opener (outputFunction . f)+                Left e -> do hPutStrLn stderr $ name ++ ": Error: " ++ show e+                             exitWith (ExitFailure 2)+                Right f -> withFiles (files opts) opener (outputFunc . f) -makeFun :: MonadInterpreter m => Eddie -> m (String->String)+putStrMaybeLn :: Bool -> String -> IO ()+putStrMaybeLn binary val = +  (if binary || last val == '\n' then putStr else putStrLn) val+++makeFun :: MonadInterpreter m => Eddie -> m ([String] -> String) makeFun opts = do   setImportsQ (asModules opts)-  fun <- interpret (head (expr opts)) (as :: String -> String)-  return $ if line opts then unlines . map fun . lines else fun+  eval (head (expr opts)) mode+    where mode | line opts && list opts = Mode (as :: [String] -> [String]) id+                                               (lines . concat) unlines+               | line opts = Mode (as :: String -> String) map +                                  (lines . concat) unlines+               | file opts && list opts = Mode (as :: [String] -> [String]) id +                                               id concat+               | file opts = Mode (as :: String -> String) map id concat+               | otherwise = Mode (as :: String -> String) id concat id ++data Mode where+    Mode :: (Typeable a, Typeable b)+         => (a -> b)              -- witness to `interpret`+         -> ((a -> b) -> c -> d)  -- application of interpreted function+         -> ([String] -> c)       -- preprocess+         -> (d -> String)         -- postprocess+         -> Mode++eval :: MonadInterpreter m => String -> Mode -> m ([String] -> String)+eval s (Mode f t bra ket) = liftM ((ket .) . (. bra) . t) $ interpret s f+ -- an even lazier version of  withFile (courtesy of Heinrich Apfelmus)--- Tweaked by mwm so withFiles uses stdin if [FilePath] is an empty list--- Further tweaked by mwm to allow caller to specify opening function.-withFile' :: Maybe FilePath -> (FilePath -> IOMode -> IO Handle) ->-             (String -> IO a) -> IO a-withFile' name opener f = do+-- Tweaked by mwm to accept a handle instead of a file so caller can+-- use favorite opening function or pass in stdin.+withFile :: IO Handle -> (String -> IO a) -> IO a+withFile ih f = do     fin <- newIORef (return ())-    let-        close = readIORef fin >>= id+    h <- ih+    let close = join (readIORef fin)         open  = do-          h <- maybe (return stdin) (flip opener ReadMode) name           writeIORef fin (hClose h)           lazyRead h     finally (unsafeInterleaveIO open >>= f >>= evaluate) close -    where-    lazyRead h = hIsEOF h >>= \b ->-        if b+    where lazyRead h = hIsEOF h >>= \b ->+            if b             then do hClose h; return []-            else do-                c  <- hGetChar h-                cs <- unsafeInterleaveIO $ lazyRead h-                return (c:cs)+            else do c  <- hGetChar h+                    cs <- unsafeInterleaveIO $ lazyRead h+                    return (c:cs)   withFiles :: [FilePath] -> (FilePath -> IOMode -> IO Handle) -> -             (String -> IO a) -> IO a-withFiles []     o f = withFile' Nothing o f-withFiles [x]    o f = withFile' (Just x) o f-withFiles (x:xs) o f = withFile' (Just x) o $ \s ->-    let f' t = f (s ++ t) in withFiles xs o f'+             ([String] -> IO a) -> IO a+withFiles []     o f = withFile (return stdin) (f . (:[]))+withFiles [x]    o f = withFile (o x ReadMode) (f . (:[]))+withFiles (x:xs) o f = withFile (o x ReadMode) $ \s ->+    let f' t = f (s:t) in withFiles xs o f'   -- argument processing data Eddie = Eddie { line :: Bool,+                     file :: Bool,+                     list :: Bool,                      binary :: Bool,                      expr :: [String],                      files :: [String],@@ -88,18 +115,22 @@         (_, _) -> unlines es:fs       mods = zip (modules opts) (repeat Nothing) ++ asModules opts   in-   if e == "" then Left $ unlines ["[options] (-e expr | expr) [files ...]",+   if e == "" || (file opts && null fs') || (file opts && line opts)+              || (list opts && not (file opts || line opts))+   then Left $ unlines ["[options] (-e expr | expr) [files ...]",                                    "--help for options"]    else Right $ opts {expr = [e], asModules = mods, files = fs' }     -eddie = Eddie {line = False &= help "Process one line at a time",+eddie = Eddie {line = False &= help "Process one line at a time (conflicts with --file)",+               file = False &= help "Process files individually (requires at least one file name)",+               list  = False &= help "Process the list of files/lines (requires --line or --file)" &= name "L",                binary = False &= help "Process a binary file",-               expr = [] &= help "Line of expression to evaluate",+               expr = [] &= help "Line of expression to evaluate" &= name "e",                modules = ["Prelude", "Data.List", "Data.Char"]                          &= help "Modules to import for expr",                asModules = [] &= help "Modules to import qualified" &= explicit                            &= name "M" &= name "Modules",                files = [] &= args} -        &= summary "eddie 0.2" &= details ["Haskell for shell scripts."]+        &= summary "eddie 0.5" &= details ["Haskell for shell scripts."]  
− test.sh
@@ -1,42 +0,0 @@-#!/bin/sh--# $1 is args to use with eddie.hs to process a file, $2 is a shell command to-# run the same process. Run them both on our test file.-# If the outputs differ, report failure of $3, including output unless $4-# is present.-test () {-   TEST=$(eval runghc eddie.hs $1 < eddie.hs)-   EXPECTED=$(eval "cat eddie.hs | $2")-   if [ "$EXPECTED" != "$TEST" ]-   then-       FAILED="yes"-       echo -e-       if [ -n "$4" ]-       then-	   echo $3 failed "(output supressed)"-       else-	   echo $3 failed: expected $EXPECTED, got $TEST-       fi-   fi-   echo -n .-}       --FAILED="no"-test "" "echo 'usage: eddie.hs [options] (-e expr | expr) [files ...]'; echo '--help for options'" "No arguments test"-test "show.length" "wc -c | xargs echo" "simple char count"-test "show.length.lines" "wc -l | xargs echo" "line count"-test "show.length.words" "wc -w | xargs echo " "word count"-test "-e show.length" "wc -c | xargs echo" "test -e option"-test "-e 'let taker = take 10 in' -e unlines.taker.lines" head "double -e option test"-test "-l reverse" "rev eddie.hs" "test -l option" X-test "-m Text.Printf 'unlines . (zipWith (printf \"%6d\t%s\") [(1::Int) ..]) . lines'" 'cat -n' 'test -m option' X-test "-M Text.Printf,P 'unlines . (zipWith (P.printf \"%6d\t%s\") [(1::Int) ..]) . lines'" 'cat -n' 'test -M option' X-echo -e--if [ $FAILED = "yes" ]-then-    exit 1-else-    exit 0-fi-
+ tests/counters.test view
@@ -0,0 +1,23 @@+eddie show.length+<<<+asdf+>>>+5+>>>= 0++eddie show.length.lines+<<<+1+2+3+4+>>>+4+>>>= 0++eddie show.length.words+<<<+now is the time for all good programmers to come to haskell+>>>+12+>>>= 0
+ tests/error.test view
@@ -0,0 +1,3 @@+eddie the.lines+>>>2 /Error: /+>>>= 2
+ tests/expr.test view
@@ -0,0 +1,27 @@+eddie -e show.length.words+<<<+now is the time for all good programmers to come to haskell+>>>+12+>>>= 0++eddie -e "let taker = take 4 in" -e unlines.taker.lines+<<<+now+is+the+time+for+all+good+programmers+to+come+to+haskell.+>>>+now+is+the+time+>>>= 0
+ tests/files.test view
@@ -0,0 +1,9 @@+eddie -fL "(:[]).show.length" tests/test.data tests/test.data+>>>+2+>>>= 0++eddie -f "show.length" tests/test.data tests/test.data+>>>+6161+>>>= 0
+ tests/imports.test view
@@ -0,0 +1,17 @@+eddie -m GHC.Exts the.lines+<<<+aaaa+aaaa+aaaa+>>>+aaaa+>>>= 0++eddie -M GHC.Exts,E E.the.lines+<<<+aaaa+aaaa+aaaa+>>>+aaaa+>>>= 0
+ tests/lines.test view
@@ -0,0 +1,27 @@+eddie -l reverse+<<<+now+is+the+time+>>>+won+si+eht+emit+>>>= 0++eddie -lL "take 4"+<<<+now+is+the+time+for+all+>>>+now+is+the+time+>>>= 0
+ tests/test.data view
@@ -0,0 +1,12 @@+now+is+the+time+for+all+good+programmers+to+come+to+haskell.
+ tests/usage.test view
@@ -0,0 +1,11 @@+eddie+>>>2 /usage:/+>>>= 1++eddie -lf reverse+>>>2 /usage:/+>>>= 1++eddie -L reverse+>>>2 /usage:/+>>>= 1