packages feed

tsparse 0.2.0.0 → 0.4.0.0

raw patch · 2 files changed

+83/−44 lines, 2 files

Files

TsParse.hs view
@@ -26,6 +26,7 @@     -- ** Basic types     Dollars   , Shares+  , TxnType      -- ** Transaction Detail By Source   , BySource(..)@@ -36,6 +37,7 @@   , BySourcePosting(..)      -- ** Transaction Detail By Fund+  , FundName   , ByFund(..)   , ByFundBeginningBal(..)   , ByFundGainLoss(..)@@ -98,7 +100,7 @@ genDollars = D.Decimal <$> pure 2 <*> genMantissa  newtype DollarsRen = DollarsRen { unDollarsRen :: Rendered Dollars }-  deriving (Eq, Show)+  deriving (Eq, Ord, Show)  instance Arbitrary DollarsRen where   arbitrary = do@@ -110,7 +112,7 @@ genShares = D.Decimal <$> pure 4 <*> genMantissa  newtype SharesRen = SharesRen { unSharesRen :: Rendered Dollars }-  deriving (Eq, Show)+  deriving (Eq, Ord, Show)  instance Arbitrary SharesRen where   arbitrary = do@@ -140,7 +142,7 @@ data Rendered a = Rendered   { ast :: a   , rendering :: String-  } deriving (Eq, Show)+  } deriving (Eq, Ord, Show)   genWord :: Gen (Rendered String)@@ -165,7 +167,7 @@   return $ Rendered (map ast ws) withSpaces  newtype WordsRen = WordsRen { unWordsRen :: Rendered [String] }-  deriving (Eq, Show)+  deriving (Eq, Ord, Show)  instance Arbitrary WordsRen where   arbitrary = WordsRen <$> genWords@@ -175,6 +177,16 @@  #endif +dollarSign :: Parser ()+dollarSign = () <$ optional (P.char '$')++space :: Parser ()+space = () <$ optional (P.char ' ')++digits :: Parser String+digits = fmap (filter (/= ',')) (P.many1 (P.oneOf "0123456789,"))+         <?> "digits"+ -- | Parses a single decimal value. Recognizes negative signs. Strips -- out dollar signs and commas. --@@ -183,16 +195,18 @@ -- consumes the entire string if there is one. decimal :: Parser D.Decimal decimal = do-  ws <- fmap (map (filter (not . (`elem` "$, ")))) words-  (isNeg, num) <- case ws of-    [] -> fail "empty string, cannot parse decimal"-    x:[] -> return (False, x)-    x:y:[] -> if x == "-"-              then return (True, y)-              else fail "could not parse decimal: too many words"-    _ -> fail "could not parse decimal, too many words"-  dec <- case readMaybe num of-    Nothing -> fail $ "could not parse decimal: " ++ num+  dollarSign+  maybeNeg <- optional (P.char '-')+  let isNeg = maybe False (const True) maybeNeg+  dollarSign+  space+  dollarSign+  whole <- digits+  _ <- P.char '.'+  frac <- digits+  let numStr = whole ++ "." ++ frac+  dec <- case readMaybe (whole ++ "." ++ frac) of+    Nothing -> fail $ "could not parse decimal: " ++ numStr     Just r -> return r   return $ if isNeg then negate dec else dec @@ -202,7 +216,7 @@ prop_Decimal = testRendered decimal . unDecimalRen  newtype DecimalRen = DecimalRen { unDecimalRen :: Rendered D.Decimal }-  deriving (Eq, Show)+  deriving (Eq, Ord, Show)  instance Arbitrary DecimalRen where   arbitrary = do@@ -274,7 +288,7 @@   c -> c  newtype DayRen = DayRen { unDayRen :: Rendered T.Day }-  deriving (Eq, Show)+  deriving (Eq, Ord, Show)  instance Arbitrary DayRen where   arbitrary =@@ -300,8 +314,7 @@   _ -> fail $ "could not read string: " ++ s  columnBreak :: Parser ()-columnBreak-  = () <$ P.char ' ' <* P.char ' ' <* P.many (P.char ' ')+columnBreak = () <$ P.many (P.char ' ')   class Pretty a where@@ -319,22 +332,27 @@ instance Pretty T.Day where   pretty = Y.text . show +-- | A list of words that indicates the transaction type.  Each string+-- in this list will not have any spaces in it.+type TxnType = [String]+ data BySourcePosting = BySourcePosting   { bspPayrollOffice :: String   , bspPostingDate :: T.Day-  , bspTxnType :: [String]+  , bspTxnType :: TxnType   , bspTraditional :: Dollars   , bspRoth :: Dollars   , bspAutomatic :: Dollars   , bspMatching :: Dollars   , bspTotal :: Dollars-  } deriving (Eq, Show)+  } deriving (Eq, Ord, Show)  #ifdef test + data RenTxnBySource = RenTxnBySource   { unRenTxnBySource :: Rendered BySourcePosting }-  deriving (Eq, Show)+  deriving (Eq, Ord, Show)   instance Arbitrary RenTxnBySource where@@ -350,11 +368,16 @@     let rAst = BySourcePosting (ast rPayroll) (ast rPostingDate)           (ast rTxnType) (ast rTrad) (ast rRoth) (ast rAuto)           (ast rMatch) (ast rTot)-    ren <- columns [ rendering rPayroll, rendering rPostingDate,-                     rendering rTxnType,-                     rendering rTrad,-                     rendering rRoth, rendering rAuto,-                     rendering rMatch, rendering rTot ]+        clmns = [ return $ rendering rPayroll       , columnSpaceOne+                , return $ rendering rPostingDate   , columnSpaceOne+                , return $ rendering rTxnType       , columnSpaceTwo+                , return $ rendering rTrad          , columnSpaceOne+                , return $ rendering rRoth          , columnSpaceOne+                , return $ rendering rAuto          , columnSpaceOne+                , return $ rendering rMatch         , columnSpaceOne+                , return $ rendering rTot+                ]+    ren <- fmap concat . sequence $ clmns     leader <- fmap (flip replicate ' ') Q.arbitrarySizedIntegral     return . RenTxnBySource $ Rendered rAst (leader ++ ren ++ "\n") @@ -364,13 +387,20 @@ genInterleaved :: Gen a -> [a] -> Gen [a] genInterleaved g = sequence . intersperse g . map return -columnSpacer :: Gen String-columnSpacer = fmap (f . abs) Q.arbitrarySizedIntegral+-- | Generates at least two spaces.+columnSpaceTwo :: Gen String+columnSpaceTwo = fmap (f . abs) Q.arbitrarySizedIntegral   where     f i = "  " ++ replicate i ' ' +-- | Generates at least one space.+columnSpaceOne :: Gen String+columnSpaceOne = fmap (f . abs) Q.arbitrarySizedIntegral+  where+    f i = " " ++ replicate i ' '+ columns :: [String] -> Gen String-columns = fmap concat . genInterleaved columnSpacer+columns = fmap concat . genInterleaved columnSpaceTwo   #endif@@ -424,7 +454,7 @@   , bssAuto :: Dollars   , bssMatching :: Dollars   , bssTotal :: Dollars-  } deriving (Eq, Show)+  } deriving (Eq, Ord, Show)  #ifdef test @@ -509,7 +539,7 @@  newtype FundNameRen = FundNameRen   { unFundNameRen :: Rendered [String] }-  deriving (Eq, Show)+  deriving (Eq, Ord, Show)  instance Arbitrary FundNameRen where   arbitrary = do@@ -532,7 +562,7 @@   , bfpTotal :: Dollars   , bfpSharePrice :: Dollars   , bfpNumShares :: Shares-  } deriving (Eq, Show)+  } deriving (Eq, Ord, Show)  #ifdef test @@ -548,10 +578,15 @@   leader <- fmap (flip replicate ' ') Q.arbitrarySizedIntegral   let rAst = ByFundPosting (ast rdy) (ast rty) (ast rtrad) (ast rroth)                        (ast rtot) (ast rpri) (ast rsha)-  ren <- columns [ rendering rdy,-                   rendering rty,-                   rendering rtrad, rendering rroth,-                   rendering rtot, rendering rpri, rendering rsha ]+  let clmns = [ return $ rendering rdy            , columnSpaceOne+              , return $ rendering rty            , columnSpaceTwo+              , return $ rendering rtrad          , columnSpaceOne+              , return $ rendering rroth          , columnSpaceOne+              , return $ rendering rtot           , columnSpaceOne+              , return $ rendering rpri           , columnSpaceOne+              , return $ rendering rsha+              ]+  ren <- fmap concat . sequence $ clmns   return $ Rendered rAst (leader ++ ren ++ "\n")  prop_txnByFund :: QP.Property@@ -595,7 +630,7 @@   { bfbbSharePrice :: Dollars   , bfbbNumShares :: Shares   , bfbbDollarBalance :: Dollars-  } deriving (Eq, Show)+  } deriving (Eq, Ord, Show)  #ifdef test @@ -640,7 +675,7 @@ -- FUND@ section. data ByFundGainLoss = ByFundGainLoss   { bfglDollarBalance :: Dollars }-  deriving (Eq, Show)+  deriving (Eq, Ord, Show)  #ifdef test @@ -675,7 +710,7 @@   { bfebSharePrice :: Dollars   , bfebNumShares :: Shares   , bfebDollarBalance :: Dollars-  } deriving (Eq, Show)+  } deriving (Eq, Ord, Show)  #ifdef test @@ -722,7 +757,7 @@   , bsTxns :: [BySourcePosting]   , bsGainLoss :: BySourceGainLoss   , bsEndingBal :: BySourceEndingBal-  } deriving (Eq, Show)+  } deriving (Eq, Ord, Show)  #ifdef test @@ -865,15 +900,19 @@            <?> "transactions by source summary")   return $ BySource begBal txns gainLoss endBal +-- | The name of a fund, eg @C Fund@. This is a list of words; each+-- word will not contain any spaces.+type FundName = [String]+ -- | A single fund in the @YOUR TRANSACTION DETAIL BY FUND@ section -- (e.g. the @G Fund@, @L 2040 Fund@, etc.) data ByFund = ByFund-  { bfFundName :: [String]+  { bfFundName :: FundName   , bfBeginningBal :: ByFundBeginningBal   , bfPostings :: [ByFundPosting]   , bfGainLoss :: ByFundGainLoss   , bfEndingBal :: ByFundEndingBal-  } deriving (Eq, Show)+  } deriving (Eq, Ord, Show)  #ifdef test @@ -980,7 +1019,7 @@ data TspStatement = TspStatement   { tspDetailBySource :: BySource   , tspDetailByFund :: [ByFund]-  } deriving (Eq, Show)+  } deriving (Eq, Ord, Show)  instance Pretty TspStatement where   pretty x = Y.vcat
tsparse.cabal view
@@ -4,7 +4,7 @@ -- The name of the package. name:                tsparse -version:             0.2.0.0+version:             0.4.0.0  -- A short (one-line) description of the package. synopsis: Parses U.S. federal Thrift Savings Plan PDF quarterly statements