packages feed

spreadsheet 0.1.2.1 → 0.1.3

raw patch · 3 files changed

+159/−4 lines, 3 filesdep +bytestringnew-component:exe:csvreplace

Dependencies added: bytestring

Files

spreadsheet.cabal view
@@ -1,5 +1,5 @@ Name:             spreadsheet-Version:          0.1.2.1+Version:          0.1.3 License:          BSD3 License-File:     LICENSE Author:           Henning Thielemann <haskell@henning-thielemann.de>@@ -16,13 +16,55 @@      <http://www.xoltar.org/languages/haskell/CSV.hs>.   Both do not parse lazy.   Reading from other source than plain 'String's could be easily added.+  .+  If you install this package by+  .+  cabal install -fbuildExamples+  .+  then an example program is compiled and installed, too.+  This program fills a template text using data from a CSV file.+  E.g. given a file @template.txt@ with content+  .+  > Name: FIRSTNAME SURNAME+  > Born: BIRTH+  .+  and @names.csv@ with content+  .+  > "FIRSTNAME","SURNAME",BIRTH+  > "Georg","Cantor",1845+  > "Haskell","Curry",1900+  > "Ada","Lovelace",1815+  .+  the call+  .+  > csvreplace --template=template.txt <names.csv+  .+  produces the output+  .+  > Name: Georg Cantor+  > Born: 1845+  > Name: Haskell Curry+  > Born: 1900+  > Name: Ada Lovelace+  > Born: 1815+  .+  For similar (non-Haskell) programs see @cut@, @csvfix@, @csvtool@. Tested-With:       GHC==6.8.2, GHC==6.12.3 Cabal-Version:     >=1.6 Build-Type:        Simple Source-Repository head-  type:     darcs-  location: http://code.haskell.org/~thielema/spreadsheet/+  Type:     darcs+  Location: http://code.haskell.org/~thielema/spreadsheet/ +Source-Repository this+  Tag:      0.1.3+  Type:     darcs+  Location: http://code.haskell.org/~thielema/spreadsheet/++Flag buildExamples+  description: Build example executables+  default:     False+ Flag splitBase   description: Choose the new smaller, split-up base package. @@ -37,10 +79,19 @@     Build-Depends: base >= 1.0 && < 2    GHC-Options:      -Wall-  Extensions:       GeneralizedNewtypeDeriving   Hs-Source-Dirs:   src   Exposed-Modules:     Data.Spreadsheet   Other-Modules:     Data.Spreadsheet.Parser     Data.Spreadsheet.CharSource++Executable csvreplace+  If flag(buildExamples)+    Build-Depends:+      bytestring >=0.9 && <0.10+  Else+    Buildable:      False+  GHC-Options:      -Wall+  Hs-Source-Dirs:   src+  Main-Is: CSVReplace.hs
+ src/CSVReplace.hs view
@@ -0,0 +1,103 @@+module Main where++import qualified Data.Spreadsheet as Sheet+import qualified Data.List.HT as ListHT++import System.Console.GetOpt (getOpt, ArgOrder(..), OptDescr(..), ArgDescr(..), usageInfo, )+import System.Environment (getArgs, getProgName, )+import qualified System.Exit as Exit+import qualified System.IO as IO++import qualified Data.ByteString.Char8 as B+import qualified Data.ByteString.Lazy.Char8 as BL++import qualified Control.Monad.Exception.Asynchronous as AExc+import qualified Control.Monad.Exception.Synchronous as Exc+import Control.Monad.Trans.Class (lift, )+import Control.Monad (when, )+import Data.Foldable (forM_, )+++data Flags =+   Flags {+      optMultiFile :: Maybe FilePath,+      optQuotation,+      optDelimiter :: Char+   }++defltFlags :: Flags+defltFlags = Flags {+      optMultiFile = Nothing,+      optQuotation = '"',+      optDelimiter = ','+   }++exitFailureMsg :: String -> IO a+exitFailureMsg msg = do+   IO.hPutStrLn IO.stderr msg+   Exit.exitFailure++options :: [OptDescr (Flags -> IO Flags)]+options =+   Option ['h'] ["help"]+      (NoArg (\_ -> do+         programName <- getProgName+         putStrLn $ flip usageInfo options $+            "Usage: " ++ programName ++ " [OPTIONS] TEMPLATE-FILE\n" +++            "The CSV file is read from standard input.\n"+         Exit.exitSuccess))+      "show options" :+   Option [] ["multifile"]+      (flip ReqArg "FILEPATTERN" $ \str flags ->+         return $ flags{optMultiFile = Just str})+      "generate one file per CSV row" :+   Option ['d'] ["delimiter"]+      (flip ReqArg "CHAR" $ \str flags -> do+         case str of+            [c] -> return $ flags{optDelimiter = c}+            _ -> exitFailureMsg $ "delimiter must be one character, which " ++ show str ++ " is not")+      "field delimiter character" :+   Option ['q'] ["quotation"]+      (flip ReqArg "CHAR" $ \str flags -> do+         case str of+            [c] -> return $ flags{optQuotation = c}+            _ -> exitFailureMsg $ "quotation mark must be one character, which " ++ show str ++ " is not")+      "quotation mark character" :+   []+++replaceRow :: String -> [String] -> [String] -> String+replaceRow template names row =+   ListHT.multiReplace (filter (not . null . fst) $ zip names row) template++replace :: String -> [String] -> Sheet.T -> String+replace template names =+   concatMap (replaceRow template names)+++main :: IO ()+main =+   Exc.resolveT (\e -> exitFailureMsg $ "Aborted: " ++ e) $ do+      argv <- lift getArgs+      let (opts, files, errors) = getOpt RequireOrder options argv+      when (not (null errors)) $ Exc.throwT $ concat $ errors+      flags <- lift $ foldr (=<<) (return defltFlags) opts+      case files of+         [templateName] -> do+            template <- fmap B.unpack $ lift $ B.readFile templateName+            sheet <-+               fmap (Sheet.fromString (optQuotation flags) (optDelimiter flags)+                      . BL.unpack) $+               lift BL.getContents+            case AExc.result sheet of+               [] -> Exc.throwT "empty CSV input"+               (names:rows) ->+                  case optMultiFile flags of+                     Nothing -> do+                        lift $ putStr $ replace template names rows+                        forM_ (AExc.exception sheet) $ Exc.throwT+                     Just filePattern ->+                        lift $ forM_ rows $ \row ->+                           writeFile (replaceRow filePattern names row) $+                              replaceRow template names row+         _ -> Exc.throwT "I need exactly one template file."
src/Data/Spreadsheet/CharSource.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE GeneralizedNewtypeDeriving #-} module Data.Spreadsheet.CharSource where  import Control.Monad.Trans.State (StateT(StateT), gets, runStateT, mapStateT, )