packages feed

csv-enumerator 0.9.0 → 0.9.2

raw patch · 4 files changed

+95/−37 lines, 4 filesdep ~attoparsecdep ~attoparsec-enumeratordep ~enumeratorPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: attoparsec, attoparsec-enumerator, enumerator

API changes (from Hackage documentation)

+ Data.CSV.Enumerator: mapAccumCSVFile :: CSVeable r => FilePath -> CSVSettings -> (acc -> r -> (acc, [r])) -> acc -> FilePath -> IO (Either SomeException acc)
- Data.CSV.Enumerator: CSVS :: Char -> Maybe Char -> Maybe Char -> Char -> CSVSettings
+ Data.CSV.Enumerator: CSVS :: !Char -> !Maybe Char -> !Maybe Char -> !Char -> CSVSettings
- Data.CSV.Enumerator: csvOutputColSep :: CSVSettings -> Char
+ Data.CSV.Enumerator: csvOutputColSep :: CSVSettings -> !Char
- Data.CSV.Enumerator: csvOutputQuoteChar :: CSVSettings -> Maybe Char
+ Data.CSV.Enumerator: csvOutputQuoteChar :: CSVSettings -> !Maybe Char
- Data.CSV.Enumerator: csvQuoteChar :: CSVSettings -> Maybe Char
+ Data.CSV.Enumerator: csvQuoteChar :: CSVSettings -> !Maybe Char
- Data.CSV.Enumerator: csvSep :: CSVSettings -> Char
+ Data.CSV.Enumerator: csvSep :: CSVSettings -> !Char
- Data.CSV.Enumerator: writeHeaders :: CSVeable r => CSVSettings -> Handle -> [r] -> IO ()
+ Data.CSV.Enumerator: writeHeaders :: CSVeable r => CSVSettings -> Handle -> [r] -> IO Bool

Files

csv-enumerator.cabal view
@@ -1,5 +1,5 @@ Name:                csv-enumerator-Version:             0.9.0+Version:             0.9.2 Synopsis:            A flexible, fast, enumerator-based CSV parser library for Haskell.   Homepage:            http://github.com/ozataman/csv-enumerator License:             BSD3@@ -60,15 +60,16 @@   Other-modules:       Data.CSV.Enumerator.Types   build-depends:-      attoparsec >= 0.8 && < 0.10-    , attoparsec-enumerator >= 0.2.0.3+      attoparsec >= 0.8+    , attoparsec-enumerator >= 0.2     , base >= 4 && < 5     , containers >= 0.3     , directory     , bytestring-    , enumerator >= 0.4.5 && < 0.5+    , enumerator >= 0.4.5     , transformers >= 0.2     , safe     , unix-compat >= 0.2.1.1   extensions:     ScopedTypeVariables+  ghc-options: -funbox-strict-fields
src/Data/CSV/Enumerator.hs view
@@ -32,6 +32,7 @@    -- * Mapping Over CSV Files   , mapCSVFile+  , mapAccumCSVFile   , mapIntoHandle    -- * Primitive Iteratees@@ -307,6 +308,30 @@   ------------------------------------------------------------------------------+-- | Map-accumulate over a CSV file. Similar to 'mapAccumL' in 'Data.List'.+mapAccumCSVFile+  :: (CSVeable r)+  => FilePath+  -> CSVSettings+  -> (acc -> r -> (acc, [r]))+  -> acc+  -> FilePath+  -> IO (Either SomeException acc)+mapAccumCSVFile fi s f acc fo = do+  res <- foldCSVFile fi s iter (acc, (Nothing, 0))+  return $ fst `fmap` res+  where+    iter (a, outa) (ParsedRow (Just !r)) = foldM chain (a', outa) rs+      where (a', rs) = f a r+    iter (a, outa) x = do+      outa' <- fileSink s fo outa x+      return $ (a, outa')+    chain (a, outa) !r = do+      outa' <- fileSink s fo outa (ParsedRow (Just r))+      return $ (a, outa')+++------------------------------------------------------------------------------ readCSVFile :: (CSVeable r) => CSVSettings  -- ^ CSV settings             -> FilePath   -- ^ FilePath             -> IO (Either SomeException [r])  -- ^ Collected data@@ -337,19 +362,19 @@              -> [r]   -- ^ Data to be output              -> IO Int  -- ^ Number of rows written appendCSVFile s fp rs = -  let doOutput (c,h) = when c (writeHeaders s h rs) >> outputRowsIter h+  let doOutput (c,h) = when c (writeHeaders s h rs >> return ()) >> outputRowsIter h       outputRowsIter h = foldM (step h) 0  . map (rowToStr s) $ rs       step h acc x = (B.hPutStrLn h x) >> return (acc+1)       chkOpen = do-        writeHeaders <- do+        wrHeader <- do           fe <- doesFileExist fp            if fe-          	then do-          	  fs <- getFileStatus fp >>= return . fileSize-          	  return $ if fs > 0 then False else True+            then do+              fs <- getFileStatus fp >>= return . fileSize+              return $ if fs > 0 then False else True             else return True         h <- openFile fp AppendMode-        return (writeHeaders, h)+        return (wrHeader, h)   in bracket       (chkOpen)       (hClose . snd)@@ -380,10 +405,10 @@   -writeHeaders :: CSVeable r => CSVSettings -> Handle -> [r] -> IO ()+writeHeaders :: CSVeable r => CSVSettings -> Handle -> [r] -> IO Bool writeHeaders s h rs = case fileHeaders rs of-  Just hs -> B.hPutStrLn h . rowToStr s $ hs-  Nothing -> return ()+  Just hs -> (B.hPutStrLn h . rowToStr s) hs >> return True+  Nothing -> return False   outputRowIter :: CSVeable r => CSVSettings -> Handle -> r -> E.Iteratee B.ByteString IO ()@@ -468,10 +493,12 @@   where     f' acc EOF = return acc     f' acc (ParsedRow Nothing) = return acc-    f' (False, _) r'@(ParsedRow (Just r)) = do+    f' (False, i) r'@(ParsedRow (Just r)) = do       rs <- f r-      when outh $ writeHeaders csvs h rs-      f' (True, 0) r'+      headerDone <- if outh then writeHeaders csvs h rs else return True+      if headerDone +      	then f' (headerDone, 0) r'  -- Headers are done, now process row+        else return (False, i+1)    -- Problem in this row, move on to next     f' (True, !i) (ParsedRow (Just r)) = do       rs <- f r       outputRows csvs h rs@@ -487,9 +514,13 @@                                        in a' `seq` yield a' (E.Chunks []) collectRows acc (ParsedRow Nothing) = yield acc (E.Chunks []) --- * Parsers -rowParser :: (Monad m, MonadIO m) => CSVSettings -> E.Iteratee B.ByteString m (Maybe Row)+------------------------------------------------------------------------------+-- Parsers++rowParser +  :: (Monad m, MonadIO m) +  => CSVSettings -> E.Iteratee B.ByteString m (Maybe Row) rowParser csvs = E.catchError p handler    where      p = iterParser $ row csvs@@ -497,6 +528,7 @@       liftIO $ putStrLn ("Error in parsing: " ++ show e)       yield Nothing (E.Chunks [])       + row :: CSVSettings -> Parser (Maybe Row) row csvs = csvrow csvs <|> badrow @@ -506,8 +538,8 @@  csvrow :: CSVSettings -> Parser (Maybe Row) csvrow c = -  let !rowbody = (quotedField' <|> (field c)) `sepBy` C8.char (csvSep c)-      !properrow = rowbody <* (C8.endOfLine <|> P.endOfInput)+  let rowbody = (quotedField' <|> (field c)) `sepBy` C8.char (csvSep c)+      properrow = rowbody <* (C8.endOfLine <|> P.endOfInput)       quotedField' = case csvQuoteChar c of           Nothing -> mzero           Just q' -> try (quotedField q')@@ -516,7 +548,7 @@     return $ Just res  field :: CSVSettings -> Parser Field-field s = P.takeWhile (isFieldChar s) <?> "Parsing a regular field"+field s = P.takeWhile (isFieldChar s)   isFieldChar s = notInClass xs'   where xs = csvSep s : "\n\r"@@ -525,10 +557,13 @@           Just x -> x : xs  quotedField :: Char -> Parser Field-quotedField c = let w = c2w c in do-  (C8.char c) <?> "Quote start"-  f <- many (notWord8 w <|> (string (B.pack $ [w,w]) *> return w))-  (C8.char c) <?> "Quote end"-  return $ B.pack f+quotedField c = +  let quoted = string dbl *> return c+      dbl = B8.pack [c,c]+  in do+  C8.char c +  f <- many (C8.notChar c <|> quoted)+  C8.char c +  return $ B8.pack f  
src/Data/CSV/Enumerator/Types.hs view
@@ -13,16 +13,16 @@ data CSVSettings = CSVS   {      -- | Separator character to be used in between fields-    csvSep :: Char          +    csvSep :: !Char                -- | Quote character that may sometimes be present around fields. If 'Nothing' is given, the library will never expect quotation even if it is present.-  , csvQuoteChar :: Maybe Char+  , csvQuoteChar :: !(Maybe Char)        -- | Quote character that should be used in the output.-  , csvOutputQuoteChar :: Maybe Char+  , csvOutputQuoteChar :: !(Maybe Char)        -- | Field separator that should be used in the output.-  , csvOutputColSep :: Char+  , csvOutputColSep :: !Char   } deriving (Read, Show, Eq)  -- | Default settings for a CSV file. 
test/csv-enumerator-test.cabal view
@@ -9,14 +9,7 @@ Category:            Data Build-type:          Simple Cabal-version:       >=1.2-Description:-  For more information and examples, check out the README at:-  <http://github.com/ozataman/csv-enumerator>.-  -  The API is fairly well documented and I would encourage you to keep your-  haddocks handy. - extra-source-files:   README.markdown @@ -45,3 +38,32 @@   extensions:     ScopedTypeVariables     OverloadedStrings+++Executable bench+  main-is: Bench.hs+  hs-source-dirs: ./ ../src+  Other-modules:+      Data.CSV.Enumerator.Types+      Data.CSV.Enumerator+  build-depends:+      attoparsec >= 0.8 && < 0.10+    , attoparsec-enumerator >= 0.2.0.3+    , base >= 4 && < 5+    , containers >= 0.3+    , directory+    , bytestring+    , enumerator >= 0.4.5 && < 0.5+    , transformers >= 0.2+    , safe+    , unix-compat >= 0.2.1.1+    , test-framework+    , test-framework-quickcheck2+    , test-framework-hunit+    , QuickCheck >= 2+    , HUnit >= 1.2+  extensions:+    ScopedTypeVariables+    OverloadedStrings+  ghc-options: -rtsopts +  ghc-prof-options: -rtsopts -caf-all -auto-all