eddie (empty) → 0.1
raw patch · 6 files changed
+280/−0 lines, 6 filesdep +basedep +cmdargsdep +hintsetup-changed
Dependencies added: base, cmdargs, hint
Files
+ LICENSE view
@@ -0,0 +1,26 @@+Copyright (c) 2011 Mike Meyer++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions+are met:+1. Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.+2. Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.++THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE+ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF+SUCH DAMAGE.++The views and conclusions contained in the software and documentation are+those of the authors and should not be interpreted as representing official+policies, either expressed or implied, of Mike Meyer.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ eddie.1 view
@@ -0,0 +1,105 @@+.TH eddie 1+.SH NAME+eddie \- run haskell filters from the command line+.SH SYNOPSYS+.B eddie +[+.I options+]+[+.I expr+]+.I file ...+.SH DESCRIPTION+.B eddie+evalutes the provided+.I expression+on either the contents of the+.I file+arguments concatenated together,+or standard input if no file arguments are present.+.PP+If the+.B \-l+option is used, the +.I expression+is used to process each line instead of the entire contents.+.PP+The prelude, Data.List and Data.Char modules are available for building+expressions. Other modules may be added with the+.B \-M+and+.B \-m+options.+.SH OPTIONS+.IP \-e+The+.BI \-e\ expr+(long form+.BI \-\-expr\ 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 ""+If no+.BI \-e\ expr+option is present, the first non-flag argument will be used for+the haskell expression.+.IP \-l+The+.B \-l+(long form+.B \-\-line+)+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.+.RS+.PP+The command+.RS+.PP+.B eddie \-l+.I expr file ...+.RE+.PP+is equivalent to the command+.RS+.PP+.B eddie+"unlines . map+.I expr+\&. lines"+.I file ...+.+.RE 1+.IP \-m+The+.BI \-m name+(long form+.BI \-\-module name+)+option is used to import module+.I name+into haskell before evaluating the expression.+.IP \-M+The+.BI \-M name,as+(long form+.BI \-\-Modules 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 SEE ALSO+The wiki at <http://code.google.com/p/eddie/w/list> for examples.+.SH BUGS+See the issues list at <http://code.google.com/p/eddie/issues/list>.+.SH AUTHOR+Mike Meyer (mwm@mired.org)
+ eddie.cabal view
@@ -0,0 +1,23 @@+Name: eddie+Version: 0.1+Synopsis: Command line file filtering with haskell+Description: A tool to let you use short haskell expressions to filter+ files at the command line.+Category: CLI tool+License: BSD3+License-file: LICENSE+Author: Mike Meyer+Copyright: (c) 2011 Mike Meyer+Maintainer: mwm@mired.org+Build-type: Simple+Homepage: http://eddie.googlecode.com/+Cabal-version: >=1.8+Extra-source-files: test.sh eddie.1++Executable eddie+ Main-is: eddie.hs+ Build-Depends: hint >= 0.3.3.2, base >= 4.3.1 && < 5, cmdargs >= 0.7++Source-repository head+ Type: hg+ Location: http://eddie.googlecode.com/hg/
+ eddie.hs view
@@ -0,0 +1,83 @@+{-# LANGUAGE DeriveDataTypeable #-}++-- import Data.ByteString.Lazy (readFile)+import Language.Haskell.Interpreter+ (setImportsQ, interpret, runInterpreter, as, MonadInterpreter)+import Data.List (intercalate)+import Data.IORef (newIORef, readIORef, writeIORef)+import System.Environment (getArgs, getProgName)+import System.IO (openFile, hClose, stdin, IOMode (ReadMode), hIsEOF, hGetChar, withFile)+import System.IO.Unsafe (unsafeInterleaveIO)+import System.Console.CmdArgs.Implicit+ (cmdArgs, (&=), Data, Typeable, help, explicit, name, args, summary, program,+ details)+import Control.Exception (finally, evaluate)++main = do+ myname <- getProgName+ opts <- cmdArgs (eddie &= program myname)+ let opts' = parseOpts opts+ fun <- runInterpreter $ makeFun opts'+ case fun of+ Left e -> putStrLn $ myname ++ ": Error: " ++ show e+ Right f -> withFiles (files opts') (putStrLn . f)++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++-- an even lazier version of withFile (courtesy of Heinrich Apfelmus)+-- Tweaked by mwm so withFiles uses stdin if [FilePath] is an empty list+withFile' :: Maybe FilePath -> (String -> IO a) -> IO a+withFile' name f = do+ fin <- newIORef (return ())+ let+ close = readIORef fin >>= id+ open = do+ h <- maybe (return stdin) (flip openFile ReadMode) name+ writeIORef fin (hClose h)+ lazyRead h+ finally (unsafeInterleaveIO open >>= f >>= evaluate) close++ 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)+++withFiles :: [FilePath] -> (String -> IO a) -> IO a+withFiles [] f = withFile' Nothing f+withFiles [x] f = withFile' (Just x) f+withFiles (x:xs) f = withFile' (Just x) $ \s ->+ let f' t = f (s ++ t) in withFiles xs f'+++-- argument processing+data Eddie = Eddie { line :: Bool,+ expr :: [String],+ files :: [String],+ modules :: [String],+ asModules :: [(String, Maybe String)]+ } deriving (Show, Data, Typeable)++parseOpts :: Eddie -> Eddie+parseOpts opts = opts {expr = [e], asModules = mods, files = fs' }+ where es = expr opts+ fs = files opts+ e:fs' = if null es then fs else intercalate "\n" es:fs+ mods = zip (modules opts) (repeat Nothing) ++ asModules opts+ +eddie = Eddie {line = False &= help "Process line at a time.",+ expr = [] &= help "Line of expression to evaluate.",+ 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.1" &= details ["Haskell for shell scripts."]
+ test.sh view
@@ -0,0 +1,41 @@+#!/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 "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 /etc/motd" "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+