packages feed

penny-lib 0.10.0.0 → 0.12.0.0

raw patch · 13 files changed

+715/−185 lines, 13 filesdep ~multiargdep ~prednotePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: multiarg, prednote

API changes (from Hackage documentation)

- Penny.Brenner: instance Eq Arg
- Penny.Brenner: instance Show Arg
- Penny.Lincoln.Predicates: DEQ :: Comp
- Penny.Lincoln.Predicates: DGT :: Comp
- Penny.Lincoln.Predicates: DGTEQ :: Comp
- Penny.Lincoln.Predicates: DLT :: Comp
- Penny.Lincoln.Predicates: DLTEQ :: Comp
- Penny.Lincoln.Predicates: DNE :: Comp
- Penny.Lincoln.Predicates: data Comp
- Penny.Lincoln.Predicates: descComp :: Ord a => Comp -> (Text, a -> a -> Bool)
- Penny.Lincoln.Predicates: instance Eq Comp
+ Penny: Version :: [Int] -> [String] -> Version
+ Penny: data Version :: *
+ Penny: versionBranch :: Version -> [Int]
+ Penny: versionTags :: Version -> [String]
+ Penny.Liberty: version :: Version -> OptSpec (IO a)
+ Penny.Lincoln.HasText: instance HasText Filename
+ Penny.Lincoln.Predicates: filename :: MakePdct
+ Penny.Lincoln.Predicates.Siblings: account :: Matcher -> LPdct
+ Penny.Lincoln.Predicates.Siblings: accountAny :: Matcher -> LPdct
+ Penny.Lincoln.Predicates.Siblings: accountLevel :: Int -> Matcher -> LPdct
+ Penny.Lincoln.Predicates.Siblings: commodity :: Matcher -> LPdct
+ Penny.Lincoln.Predicates.Siblings: credit :: LPdct
+ Penny.Lincoln.Predicates.Siblings: debit :: LPdct
+ Penny.Lincoln.Predicates.Siblings: drCr :: DrCr -> LPdct
+ Penny.Lincoln.Predicates.Siblings: flag :: MakePdct
+ Penny.Lincoln.Predicates.Siblings: number :: MakePdct
+ Penny.Lincoln.Predicates.Siblings: parseQty :: Text -> Maybe (Qty -> LPdct)
+ Penny.Lincoln.Predicates.Siblings: payee :: MakePdct
+ Penny.Lincoln.Predicates.Siblings: postingMemo :: MakePdct
+ Penny.Lincoln.Predicates.Siblings: qty :: Ordering -> Qty -> LPdct
+ Penny.Lincoln.Predicates.Siblings: reconciled :: LPdct
+ Penny.Lincoln.Predicates.Siblings: tag :: Matcher -> LPdct
+ Penny.Lincoln.Predicates.Siblings: type LPdct = Pdct PostFam
+ Penny.Lincoln.Predicates.Siblings: type MakePdct = Matcher -> LPdct
+ Penny.Lincoln.Queries.Siblings: account :: PostFam -> [Account]
+ Penny.Lincoln.Queries.Siblings: amount :: PostFam -> [Amount]
+ Penny.Lincoln.Queries.Siblings: balance :: PostFam -> [Balance]
+ Penny.Lincoln.Queries.Siblings: bestSibs :: (Posting -> Maybe a) -> (TopLine -> Maybe a) -> PostFam -> [Maybe a]
+ Penny.Lincoln.Queries.Siblings: commodity :: PostFam -> [Commodity]
+ Penny.Lincoln.Queries.Siblings: drCr :: PostFam -> [DrCr]
+ Penny.Lincoln.Queries.Siblings: entry :: PostFam -> [Entry]
+ Penny.Lincoln.Queries.Siblings: filePosting :: PostFam -> [Maybe FilePosting]
+ Penny.Lincoln.Queries.Siblings: flag :: PostFam -> [Maybe Flag]
+ Penny.Lincoln.Queries.Siblings: globalPosting :: PostFam -> [Maybe GlobalPosting]
+ Penny.Lincoln.Queries.Siblings: number :: PostFam -> [Maybe Number]
+ Penny.Lincoln.Queries.Siblings: payee :: PostFam -> [Maybe Payee]
+ Penny.Lincoln.Queries.Siblings: postingLine :: PostFam -> [Maybe PostingLine]
+ Penny.Lincoln.Queries.Siblings: postingMemo :: PostFam -> [Maybe Memo]
+ Penny.Lincoln.Queries.Siblings: qty :: PostFam -> [Qty]
+ Penny.Lincoln.Queries.Siblings: sibs :: (Posting -> a) -> PostFam -> [a]
+ Penny.Lincoln.Queries.Siblings: side :: PostFam -> [Maybe Side]
+ Penny.Lincoln.Queries.Siblings: spaceBetween :: PostFam -> [Maybe SpaceBetween]
+ Penny.Lincoln.Queries.Siblings: tags :: PostFam -> [Tags]
- Penny: runPenny :: (Runtime -> Defaults) -> IO ()
+ Penny: runPenny :: Version -> (Runtime -> Defaults) -> IO ()
- Penny.Brenner: brennerMain :: Config -> IO ()
+ Penny.Brenner: brennerMain :: Version -> Config -> IO ()
- Penny.Liberty: parseComparer :: String -> Exceptional Error Comp
+ Penny.Liberty: parseComparer :: String -> (Ordering -> Pdct a) -> Exceptional Error (Pdct a)
- Penny.Lincoln.Predicates: date :: Comp -> UTCTime -> LPdct
+ Penny.Lincoln.Predicates: date :: Ordering -> UTCTime -> LPdct
- Penny.Lincoln.Predicates: qty :: Comp -> Qty -> LPdct
+ Penny.Lincoln.Predicates: qty :: Ordering -> Qty -> LPdct
- Penny.Wheat: main :: (Runtime -> WheatConf) -> IO ()
+ Penny.Wheat: main :: Version -> (Runtime -> WheatConf) -> IO ()
- Penny.Zinc: runZinc :: Defaults -> Runtime -> [Report] -> IO ()
+ Penny.Zinc: runZinc :: Version -> Defaults -> Runtime -> [Report] -> IO ()

Files

Penny.hs view
@@ -5,7 +5,8 @@      -- | Everything you need to create a custom Penny program is     -- available by importing only this module.-    Defaults(..)+    Version(..)+  , Defaults(..)   , Z.Matcher(..)    -- ** Color schemes@@ -85,6 +86,7 @@   ) where  import qualified Data.Text as X+import Data.Version (Version(..)) import qualified Penny.Cabin.Balance.Convert as Conv import qualified Penny.Cabin.Balance.Convert.Parser as CP import qualified Penny.Cabin.Balance.Convert.Options as ConvOpts@@ -231,16 +233,18 @@  -- | Creates an IO action that you can use for the main function. runPenny-  :: (S.Runtime -> Defaults)+  :: Version+  -- ^ Version of the executable+  -> (S.Runtime -> Defaults)      -- ^ runPenny will apply this function to the Runtime. This way      -- the defaults you use can vary depending on environment      -- variables, the terminal type, the date, etc.   -> IO ()-runPenny getDefaults = do+runPenny ver getDefaults = do   rt <- S.runtime   let df = getDefaults rt       rs = allReports df-  Z.runZinc (toZincDefaults df) rt rs+  Z.runZinc ver (toZincDefaults df) rt rs  -- | The commodity to which to convert the commodities in the convert -- report.
Penny/Brenner.hs view
@@ -18,8 +18,11 @@   ) where  import qualified Penny.Brenner.Types as Y-import Data.Maybe (mapMaybe)+import Control.Monad (join)+import Data.Either (partitionEithers) import qualified Data.Text as X+import qualified Data.Version as V+import qualified Penny.Liberty as Ly import qualified Penny.Lincoln as L import qualified Penny.Lincoln.Builders as Bd import qualified Penny.Copper.Render as R@@ -32,33 +35,46 @@ import qualified System.Console.MultiArg as MA import qualified Control.Monad.Exception.Synchronous as Ex -brennerMain :: Config -> IO ()-brennerMain cf = do+brennerMain+  :: V.Version+  -- ^ Binary version+  -> Config+  -> IO ()+brennerMain v cf = do   let cf' = convertConfig cf-  ioAction <- MA.modesWithHelp (help cf') globalOpts+  join $ MA.modesWithHelp (help cf') (globalOpts v)     (preProcessor cf')-  ioAction -data Arg = AFitAcct String-  deriving (Eq, Show)--toFitAcctOpt :: Arg -> Maybe String-toFitAcctOpt a = case a of { AFitAcct s -> Just s }--globalOpts :: [MA.OptSpec Arg]-globalOpts =-  [ MA.OptSpec ["fit-account"] "f" (MA.OneArg AFitAcct) ]+globalOpts+  :: V.Version+  -- ^ Binary version+  -> [MA.OptSpec (Either (IO ()) String)]+globalOpts v =+  [ MA.OptSpec ["fit-account"] "f" (MA.OneArg Right)+  , fmap Left (Ly.version v)+  ]  preProcessor-  :: Y.Config -> [Arg] -> Either (a -> IO ()) [MA.Mode (IO ())]-preProcessor cf as = Ex.toEither . Ex.mapException (const . fail) $ do-  let mayFiStr = case mapMaybe toFitAcctOpt as of-        [] -> Nothing-        xs -> Just . last $ xs-  fi <- case mayFiStr of-    Nothing -> return $ Y.defaultFitAcct cf-    Just s ->+  :: Y.Config+  -> [Either (IO ()) String]+  -> Either (a -> IO ()) [MA.Mode (IO ())]+preProcessor cf args =+  let (vers, as) = partitionEithers args+  in case vers of+      [] -> makeModes cf as+      x:_ -> Left (const x)++makeModes+  :: Y.Config+  -> [String]+  -- ^ Names of financial institutions given on command line+  -> Either (a -> IO ()) [MA.Mode (IO ())]+makeModes cf as = Ex.toEither . Ex.mapException (const . fail) $ do+  fi <- case as of+    [] -> return $ Y.defaultFitAcct cf+    _ ->       let pdct (Y.Name n, _) = n == X.pack s+          s = last as       in case filter pdct (Y.moreFitAccts cf) of            [] -> Ex.throw $               "financial institution account "
Penny/Cabin/Posts/Parser.hs view
@@ -26,7 +26,6 @@ import qualified Data.Prednote.Expressions as Exp import qualified Data.Prednote.Pdct as Pt import qualified Penny.Lincoln as L-import qualified Penny.Lincoln.Predicates as Pd import qualified Penny.Shield as S import qualified Text.Matchers as M @@ -99,14 +98,12 @@ optBoxSerial nm f = C.OptSpec [nm] "" (C.TwoArg g)   where     g a1 a2 st = do-      cmp <- Ly.parseComparer a1       i <- Ly.parseInt a2-      let (cmpDesc, cmpFn) = Pd.descComp cmp-          desc = "serial " <> X.pack nm <> " is " <> cmpDesc-                 <> " " <> X.pack (show i)-          pdct box = (f . L.boxMeta $ box) `cmpFn` i-          opnd = Pt.operand desc pdct-          tok = Exp.operand opnd+      let getPd = Pt.compareBy (X.pack . show $ i)+                  ("serial " <> X.pack nm) cmp+          cmp l = compare (f . L.boxMeta $ l) i+      pd <- Ly.parseComparer a1 getPd+      let tok = Exp.operand pd       return $ st { tokens = tokens st ++ [tok] }  optFilteredNum :: C.OptSpec (State -> Ex.Exceptional Error State)
Penny/Liberty.hs view
@@ -36,6 +36,9 @@   caseSelectSpecs,   operatorSpecs, +  -- * Version+  version,+   -- * Errors   Error @@ -49,14 +52,16 @@ import Data.List (sortBy) import Data.Text (Text, pack) import qualified Data.Time as Time+import qualified System.Console.MultiArg as MA import qualified System.Console.MultiArg.Combinator as C import System.Console.MultiArg.Combinator (OptSpec) import Text.Parsec (parse)  import qualified Penny.Copper.Parsec as Pc -import Penny.Lincoln.Family.Child (child, parent)+import Penny.Lincoln.Family.Child (Child(Child), child, parent) import qualified Penny.Lincoln.Predicates as P+import qualified Penny.Lincoln.Predicates.Siblings as PS import qualified Data.Prednote.Pdct as E import qualified Penny.Lincoln as L import qualified System.Console.Rainbow as C@@ -66,6 +71,10 @@   CaseSensitive(Sensitive, Insensitive)) import qualified Text.Matchers as TM +import qualified Paths_penny_lib as PPL+import qualified Data.Version as V+import qualified System.Exit as Exit+ -- | A multiline Text that holds an error message. type Error = Text @@ -224,19 +233,12 @@  -- | Parses comparers given on command line to a function. Fails if -- the string given is invalid.-parseComparer :: String -> Ex.Exceptional Error P.Comp-parseComparer t-  | t == "<" = return P.DLT-  | t == "<=" = return P.DLTEQ-  | t == "==" = return P.DEQ-  | t == "=" = return P.DEQ-  | t == ">" = return P.DGT-  | t == ">=" = return P.DGTEQ-  | t == "/=" = return P.DNE-  | t == "!=" = return P.DNE-  | otherwise = Ex.throw msg-  where-    msg = "bad comparer: " <> pack t <> "\n"+parseComparer+  :: String+  -> (Ordering -> E.Pdct a)+  -> Ex.Exceptional Error (E.Pdct a)+parseComparer s f = Ex.fromMaybe ("bad comparer: " <> pack s <> "\n")+                  $ E.parseComparer (pack s) f  -- | Parses a date from the command line. On failure, throws back the -- error message from the failed parse.@@ -256,13 +258,15 @@ date :: OptSpec (Ex.Exceptional Error Operand) date = C.OptSpec ["date"] ['d'] (C.TwoArg f)   where-    f a1 a2 = P.date <$> parseComparer a1 <*> parseDate a2+    f a1 a2 = do+      utct <- parseDate a2+      parseComparer a1 (flip P.date utct)   current :: L.DateTime -> OptSpec Operand current dt = C.OptSpec ["current"] [] (C.NoArg f)   where-    f = P.date P.DLTEQ (L.toUTC dt)+    f = E.or [P.date LT (L.toUTC dt), P.date EQ (L.toUTC dt)]  -- | Parses exactly one integer; fails if it cannot read exactly one. parseInt :: String -> Ex.Exceptional Error Int@@ -338,18 +342,23 @@ number :: OptSpec ( CaseSensitive                     -> MatcherFactory                     -> Ex.Exceptional Error Operand )-number = patternOption "number" Nothing P.number+number = patternOption "number" (Just 'n') P.number  flag :: OptSpec ( CaseSensitive                   -> MatcherFactory                   -> Ex.Exceptional Error Operand)-flag = patternOption "flag" Nothing P.flag+flag = patternOption "flag" (Just 'f') P.flag  commodity :: OptSpec ( CaseSensitive                        -> MatcherFactory                        -> Ex.Exceptional Error Operand)-commodity = patternOption "commodity" Nothing P.commodity+commodity = patternOption "commodity" (Just 'y') P.commodity +filename :: OptSpec ( CaseSensitive+                      -> MatcherFactory+                      -> Ex.Exceptional Error Operand )+filename = patternOption "filename" Nothing P.filename+ postingMemo :: OptSpec ( CaseSensitive                          -> MatcherFactory                          -> Ex.Exceptional Error Operand)@@ -368,9 +377,11 @@ credit = C.OptSpec ["credit"] [] (C.NoArg P.credit)  qtyOption :: OptSpec (Ex.Exceptional Error Operand)-qtyOption = C.OptSpec ["qty"] [] (C.TwoArg f)+qtyOption = C.OptSpec ["qty"] "q" (C.TwoArg f)   where-    f a1 a2 = P.qty <$> parseComparer a1 <*> parseQty a2+    f a1 a2 = do+      qt <- parseQty a2+      parseComparer a1 (flip P.qty qt)     parseQty a = case parse Pc.quantity "" (pack a) of       Left e -> Ex.throw $ "could not parse quantity: "         <> pack a <> " - "@@ -378,7 +389,6 @@       Right g -> pure g  - -- | Creates two options suitable for comparison of serial numbers, -- one for ascending, one for descending. serialOption ::@@ -397,20 +407,64 @@ serialOption getSerial n = (osA, osD)   where     osA = C.OptSpec [n] []-          (C.TwoArg (f L.forward))-    osD = C.OptSpec [addPrefix "rev" n] []-          (C.TwoArg (f L.backward))-    f getInt a1 a2 = do-      cmp <- parseComparer a1+          (C.TwoArg (f n L.forward))+    osD = let name = addPrefix "rev" n+          in C.OptSpec [name] []+             (C.TwoArg (f name L.backward))+    f name getInt a1 a2 = do       num <- parseInt a2-      let op pf = case getSerial pf of-            Nothing -> False-            Just ser -> getInt ser `cmpFn` num-          (cmpDesc, cmpFn) = P.descComp cmp-          desc = pack n <> " is " <> cmpDesc <> " " <> (pack . show $ num)-      return (E.operand desc op)+      let getPdct = E.compareByMaybe (pack . show $ num) (pack name) cmp+          cmp l = case getSerial l of+            Nothing -> Nothing+            Just ser -> Just $ compare (getInt ser) num+      parseComparer a1 getPdct  +-- | Creates two options suitable for comparison of sibling serial+-- numbers. Similar to 'serialOption'.+siblingSerialOption++  :: (L.Posting -> Maybe L.Serial)+  -- ^ Function that, when applied to a PostFam, returns the serial+  -- you are interested in.++  -> String+  -- ^ Name of the command line option, such as @global-posting@++  -> ( OptSpec (Ex.Exceptional Error Operand)+     , OptSpec (Ex.Exceptional Error Operand) )+  -- ^ Parses both descending and ascending serial options.++siblingSerialOption getSerial n = (osA, osD)+  where+    osA = C.OptSpec ["s-" ++ n] []+          (C.TwoArg (f n L.forward))+    osD = let name = addPrefix "rev" n+          in C.OptSpec ["s-" ++ name] []+             (C.TwoArg (f name L.backward))+    f name getInt a1 a2 = do+      num <- parseInt a2+      let getPdct ord = E.operand desc fn+            where+              desc = "any sibling serial " <> pack name+                     <> " is " <> descCmp ord+                     <> " " <> (pack . show $ num)+              fn = any doCmp . getSiblings . L.unPostFam+              doCmp p = case getSerial p of+                Nothing -> False+                Just ser -> compare (getInt ser) num == ord+      parseComparer a1 getPdct+++getSiblings :: Child p c -> [c]+getSiblings (Child _ s1 ss _) = s1:ss++descCmp :: Ordering -> Text+descCmp o = case o of+  LT -> "less than"+  EQ -> "equal to"+  GT -> "greater than"+ -- | Takes a string, adds a prefix and capitalizes the first letter of -- the old string. e.g. applied to "rev" and "globalTransaction", -- returns "revGlobalTransaction".@@ -476,9 +530,23 @@   , commodity   , postingMemo   , transactionMemo+  , filename   , fmap (const . const . pure) debit   , fmap (const . const . pure) credit   , fmap (const . const) qtyOption++  , sAccount+  , sAccountLevel+  , sAccountAny+  , sPayee+  , sTag+  , sNumber+  , sFlag+  , sCommodity+  , sPostingMemo+  , fmap (const . const . pure) sDebit+  , fmap (const . const. pure) sCredit+  , fmap (const . const) sQtyOption   ]   ++ serialSpecs @@ -489,7 +557,8 @@   = concat   $ [unDouble]   <*> [ globalTransaction, globalPosting,-        filePosting, fileTransaction ]+        filePosting, fileTransaction,+        sGlobalPosting, sFilePosting ]  unDouble   :: Functor f@@ -533,9 +602,6 @@ -- Matcher control ------------------------------------------------------------ -noArg :: a -> String -> OptSpec a-noArg a s = C.OptSpec [s] "" (C.NoArg a)- parseInsensitive :: OptSpec CaseSensitive parseInsensitive =   C.OptSpec ["case-insensitive"] ['i'] (C.NoArg Insensitive)@@ -547,16 +613,19 @@   within :: OptSpec MatcherFactory-within = noArg (\c t -> return (TM.within c t)) "within"+within =+  C.OptSpec ["within"] "w" . C.NoArg $ \c t ->+    return (TM.within c t)  pcre :: OptSpec MatcherFactory-pcre = noArg TM.pcre "pcre"+pcre = C.OptSpec ["pcre"] "r" (C.NoArg TM.pcre)  posix :: OptSpec MatcherFactory-posix = noArg TM.tdfa "posix"+posix = C.OptSpec ["posix"] "" (C.NoArg TM.tdfa)  exact :: OptSpec MatcherFactory-exact = noArg (\c t -> return (TM.exact c t)) "exact"+exact = C.OptSpec ["exact"] "x" . C.NoArg $ \c t ->+        return (TM.exact c t)  matcherSelectSpecs :: [OptSpec MatcherFactory] matcherSelectSpecs = [within, pcre, posix, exact]@@ -570,23 +639,23 @@  -- | Open parentheses open :: OptSpec (X.Token a)-open = noArg X.openParen "open"+open = C.OptSpec ["open"] "(" (C.NoArg X.openParen)  -- | Close parentheses close :: OptSpec (X.Token a)-close = noArg X.closeParen "close"+close = C.OptSpec ["close"] ")" (C.NoArg X.closeParen)  -- | and operator parseAnd :: OptSpec (X.Token a)-parseAnd = noArg X.opAnd "and"+parseAnd = C.OptSpec ["and"] "A" (C.NoArg X.opAnd)  -- | or operator parseOr :: OptSpec (X.Token a)-parseOr = noArg X.opOr "or"+parseOr = C.OptSpec ["or"] "O" (C.NoArg X.opOr)  -- | not operator parseNot :: OptSpec (X.Token a)-parseNot = noArg X.opNot "not"+parseNot = C.OptSpec ["not"] "N" (C.NoArg X.opNot)  operatorSpecs :: [OptSpec (X.Token a)] operatorSpecs =@@ -595,18 +664,125 @@ -- Infix and RPN expression selectors  parseInfix :: OptSpec X.ExprDesc-parseInfix = noArg X.Infix "infix"+parseInfix = C.OptSpec ["infix"] "" (C.NoArg X.Infix)  parseRPN :: OptSpec X.ExprDesc-parseRPN = noArg X.RPN "rpn"+parseRPN = C.OptSpec ["rpn"] "" (C.NoArg X.RPN)  -- | Both Infix and RPN options. exprDesc :: [OptSpec X.ExprDesc] exprDesc = [ parseInfix, parseRPN ]  showExpression :: OptSpec ()-showExpression = noArg () "show-expression"+showExpression = C.OptSpec ["show-expression"] "" (C.NoArg ())  verboseFilter :: OptSpec ()-verboseFilter = noArg () "verbose-filter"+verboseFilter = C.OptSpec ["verbose-filter"] "" (C.NoArg ()) +--+-- Siblings+--++sGlobalPosting :: ( OptSpec (Ex.Exceptional Error Operand)+                  , OptSpec (Ex.Exceptional Error Operand) )+sGlobalPosting =+  siblingSerialOption (fmap (fmap L.unGlobalPosting) L.pGlobalPosting)+                      "globalPosting"++sFilePosting :: ( OptSpec (Ex.Exceptional Error Operand)+                  , OptSpec (Ex.Exceptional Error Operand) )+sFilePosting =+  siblingSerialOption (fmap (fmap L.unFilePosting) L.pFilePosting)+                      "filePosting"++sAccount :: OptSpec ( CaseSensitive+                    -> MatcherFactory+                    -> Ex.Exceptional Error Operand )+sAccount = C.OptSpec ["s-account"] "" (C.OneArg f)+  where+    f a1 cs fty = fmap PS.account+                  $ getMatcher a1 cs fty++sAccountLevel :: OptSpec ( CaseSensitive+                         -> MatcherFactory+                         -> Ex.Exceptional Error Operand )+sAccountLevel = C.OptSpec ["s-account-level"] "" (C.TwoArg f)+  where+    f a1 a2 cs fty+      = PS.accountLevel <$> parseInt a1 <*> getMatcher a2 cs fty++sAccountAny :: OptSpec ( CaseSensitive+                        -> MatcherFactory+                        -> Ex.Exceptional Error Operand )+sAccountAny = patternOption "s-account-any" Nothing PS.accountAny++-- | The payee option; returns True if the matcher matches the payee+-- name.+sPayee :: OptSpec ( CaseSensitive+                 -> MatcherFactory+                 -> Ex.Exceptional Error Operand )+sPayee = patternOption "s-payee" (Just 'p') PS.payee++sTag :: OptSpec ( CaseSensitive+                 -> MatcherFactory+                 -> Ex.Exceptional Error Operand)+sTag = patternOption "s-tag" (Just 't') PS.tag++sNumber :: OptSpec ( CaseSensitive+                    -> MatcherFactory+                    -> Ex.Exceptional Error Operand )+sNumber = patternOption "s-number" Nothing PS.number++sFlag :: OptSpec ( CaseSensitive+                  -> MatcherFactory+                  -> Ex.Exceptional Error Operand)+sFlag = patternOption "s-flag" Nothing PS.flag++sCommodity :: OptSpec ( CaseSensitive+                       -> MatcherFactory+                       -> Ex.Exceptional Error Operand)+sCommodity = patternOption "s-commodity" Nothing PS.commodity++sPostingMemo :: OptSpec ( CaseSensitive+                         -> MatcherFactory+                         -> Ex.Exceptional Error Operand)+sPostingMemo = patternOption "s-posting-memo" Nothing PS.postingMemo++sDebit :: OptSpec Operand+sDebit = C.OptSpec ["s-debit"] [] (C.NoArg PS.debit)++sCredit :: OptSpec Operand+sCredit = C.OptSpec ["s-credit"] [] (C.NoArg PS.credit)++sQtyOption :: OptSpec (Ex.Exceptional Error Operand)+sQtyOption = C.OptSpec ["s-qty"] [] (C.TwoArg f)+  where+    f a1 a2 = do+      qt <- parseQty a2+      parseComparer a1 (flip PS.qty qt)+    parseQty a = case parse Pc.quantity "" (pack a) of+      Left e -> Ex.throw $ "could not parse quantity: "+        <> pack a <> " - "+        <> (pack . show $ e)+      Right g -> pure g++--+-- Versions+--++-- | Parses the @--version@ option and returns an IO action that+-- prints it and exits successfully. You supply the version of the+-- executable, as there is no easy way to get that automatically.++version+  :: V.Version+  -- ^ Version of binary+  -> OptSpec (IO a)+version v = C.OptSpec ["version"] [] (C.NoArg f)+  where+    f = do+      pn <- MA.getProgName+      putStrLn $ pn ++ " version " ++ V.showVersion v+      putStrLn $ "using version " ++ V.showVersion PPL.version+                 ++ " of penny-lib"+      Exit.exitSuccess
Penny/Lincoln/Bits/Qty.hs view
@@ -93,6 +93,9 @@              else b ++ ['.'] ++ end  +-- | Compares Qty after equalizing their exponents.+--+-- > compare (newQty 15 1) (newQty 1500 3) == EQ instance Ord Qty where   compare q1 q2 = compare (mantissa q1') (mantissa q2')     where
Penny/Lincoln/HasText.hs view
@@ -28,6 +28,9 @@ instance HasText B.Tag where   text = B.unTag +instance HasText B.Filename where+  text = B.unFilename+ class HasTextList a where   textList :: a -> [Text] 
Penny/Lincoln/Predicates.hs view
@@ -11,8 +11,6 @@   , flag   , postingMemo   , transactionMemo-  , Comp(..)-  , descComp   , date   , qty   , drCr@@ -23,6 +21,7 @@   , accountLevel   , accountAny   , tag+  , filename   , reconciled   , clonedTransactions   , clonedTopLines@@ -149,6 +148,9 @@ flag :: MakePdct flag = matchMaybe "flag" Q.flag +filename :: MakePdct+filename = matchMaybe "filename" Q.filename+ postingMemo :: MakePdct postingMemo = matchMemo "posting memo" Q.postingMemo @@ -157,55 +159,19 @@  -- * Date --- | Comparisons.-data Comp-  = DLT-  -- ^ Less than--  | DLTEQ-  -- ^ Less than or equal to--  | DEQ-  -- ^ Equal to--  | DGTEQ-  -- ^ Greater than or equal to--  | DGT-  -- ^ Greater than--  | DNE-  -- ^ Not equal to-  deriving Eq---- | Describes a Comp, and returns a function to actually perform--- comparisons.-descComp :: Ord a => Comp -> (Text, a -> a -> Bool)-descComp c = case c of-  DLT -> ("less than", (<))-  DLTEQ -> ("less than or equal to", (<=))-  DEQ -> ("equal to", (==))-  DGTEQ -> ("greater than or equal to", (>=))-  DGT -> ("greater than", (>))-  DNE -> ("not equal to", (/=))- date-  :: Comp+  :: Ordering   -> Time.UTCTime   -> LPdct-date c d = P.operand desc pd-  where-    desc = "UTC date is " <> dd <> " " <> X.pack (show d)-    (dd, cmp) = descComp c-    pd pf = (B.toUTC . Q.dateTime $ pf) `cmp` d+date ord u = P.compareBy (X.pack . show $ u)+             "UTC date and time"+           (\l -> compare (B.toUTC . Q.dateTime $ l) u) ord  -qty :: Comp -> B.Qty -> LPdct-qty c q = P.operand desc pd-  where-    desc = "quantity is " <> dd <> " " <> X.pack (show q)-    (dd, cmp) = descComp c-    pd pf = (Q.qty pf) `cmp` q+qty :: Ordering -> B.Qty -> LPdct+qty o q = P.compareBy (X.pack . show $ q) "quantity"+          (\l -> compare (Q.qty l) q) o+  drCr :: B.DrCr -> LPdct drCr dc = P.operand desc pd
+ Penny/Lincoln/Predicates/Siblings.hs view
@@ -0,0 +1,210 @@+{-# LANGUAGE OverloadedStrings #-}++-- | Functions that return a boolean based upon some criterion that+-- matches something, often a PostFam. Useful when filtering+-- Postings.+module Penny.Lincoln.Predicates.Siblings+  ( LPdct+  , MakePdct+  , payee+  , number+  , flag+  , postingMemo+  , qty+  , parseQty+  , drCr+  , debit+  , credit+  , commodity+  , account+  , accountLevel+  , accountAny+  , tag+  , reconciled+  ) where+++import Data.List (intersperse)+import Data.Monoid ((<>))+import Data.Text (Text)+import qualified Data.Text as X+import qualified Penny.Lincoln.Bits as B+import Penny.Lincoln.HasText (HasText, text, HasTextList, textList)+import qualified Penny.Lincoln.Queries.Siblings as Q+import Penny.Lincoln.Transaction (PostFam)+import qualified Text.Matchers as M+import qualified Data.Prednote.Pdct as P++type LPdct = P.Pdct PostFam++type MakePdct = M.Matcher -> LPdct++-- * Matching helpers+match+  :: HasText a+  => Text+  -- ^ Description of this field+  -> (PostFam -> [a])+  -- ^ Function that returns the field being matched+  -> M.Matcher+  -> LPdct+match t f m = P.operand desc pd+  where+    desc = makeDesc t m+    pd = any (M.match m) . map text . f++matchMaybe+  :: HasText a+  => Text+  -- ^ Description of this field+  -> (PostFam -> [Maybe a])+  -> M.Matcher+  -> LPdct+matchMaybe t f m = P.operand desc pd+  where+    desc = makeDesc t m+    pd = any (== (Just True))+         . map (fmap (M.match m . text))+         . f++makeDesc :: Text -> M.Matcher -> Text+makeDesc t m+  = "subject: " <> t <> " (any sibling posting) matcher: "+  <> M.matchDesc m++-- | Does the given matcher match any of the elements of the Texts in+-- a HasTextList?+matchAny+  :: HasTextList a+  => Text+  -> (PostFam -> [a])+  -> M.Matcher+  -> LPdct+matchAny t f m = P.operand desc pd+  where+    desc = makeDesc t m+    pd = any (any (M.match m)) . map textList . f++-- | Does the given matcher match the text that is at the given+-- element of a HasTextList? If the HasTextList does not have a+-- sufficent number of elements to perform this test, returns False.+matchLevel+  :: HasTextList a+  => Int+  -> Text+  -> (PostFam -> [a])+  -> M.Matcher+  -> LPdct+matchLevel l d f m = P.operand desc pd+  where+    desc = makeDesc ("level " <> X.pack (show l) <> " of " <> d) m+    pd pf = let doMatch list = if l < 0 || l >= length list+                               then False+                               else M.match m (list !! l)+            in any doMatch . map textList . f $ pf++-- | Does the matcher match the text of the memo? Joins each line of+-- the memo with a space.+matchMemo+  :: Text+  -> (PostFam -> [Maybe B.Memo])+  -> M.Matcher+  -> LPdct+matchMemo t f m = P.operand desc pd+  where+    desc = makeDesc t m+    pd = any (maybe False doMatch) . f+    doMatch = M.match m+              . X.intercalate (X.singleton ' ')+              . B.unMemo++matchDelimited+  :: HasTextList a+  => Text+  -- ^ Separator+  -> Text+  -- ^ Label+  -> (PostFam -> [a])+  -> M.Matcher+  -> LPdct+matchDelimited sep lbl f m = match lbl f' m+  where+    f' = map (X.concat . intersperse sep . textList) . f++-- * Pattern matching fields++payee :: MakePdct+payee = matchMaybe "payee" Q.payee++number :: MakePdct+number = matchMaybe "number" Q.number++flag :: MakePdct+flag = matchMaybe "flag" Q.flag++postingMemo :: MakePdct+postingMemo = matchMemo "posting memo" Q.postingMemo++-- | A Pdct that returns True if @compare subject qty@ returns the+-- given Ordering.+qty :: Ordering -> B.Qty -> LPdct+qty o q = P.operand desc pd+  where+    desc = "quantity of any sibling is " <> dd <> " " <> X.pack (show q)+    dd = case o of+      LT -> "less than"+      GT -> "greater than"+      EQ -> "equal to"+    pd = any ((== o) . (`compare` q)) . Q.qty++parseQty+  :: X.Text+  -> Maybe (B.Qty -> LPdct)+parseQty x+  | x == "==" = Just (qty EQ)+  | x == "=" = Just (qty EQ)+  | x == ">" = Just (qty GT)+  | x == "<" = Just (qty LT)+  | x == "/=" = Just (\q -> P.not (qty EQ q))+  | x == "!=" = Just (\q -> P.not (qty EQ q))+  | x == ">=" = Just (\q -> P.or [qty GT q, qty EQ q])+  | x == "<=" = Just (\q -> P.or [qty LT q, qty EQ q])+  | otherwise = Nothing++drCr :: B.DrCr -> LPdct+drCr dc = P.operand desc pd+  where+    desc = "entry of any sibling is a " <> s+    s = case dc of { B.Debit -> "debit"; B.Credit -> "credit" }+    pd = any (== dc) . Q.drCr++debit :: LPdct+debit = drCr B.Debit++credit :: LPdct+credit = drCr B.Credit++commodity :: M.Matcher -> LPdct+commodity = match "commodity" Q.commodity++account :: M.Matcher -> LPdct+account = matchDelimited ":" "account" Q.account++accountLevel :: Int -> M.Matcher -> LPdct+accountLevel i = matchLevel i "account" Q.account++accountAny :: M.Matcher -> LPdct+accountAny = matchAny "any sub-account" Q.account++tag :: M.Matcher -> LPdct+tag = matchAny "any tag" Q.tags++-- | True if a posting is reconciled; that is, its flag is exactly+-- @R@.+reconciled :: LPdct+reconciled = P.operand d p+  where+    d = "posting flag is exactly \"R\" (is reconciled)"+    p = any (maybe False ((== X.singleton 'R') . B.unFlag))+        . Q.flag+
Penny/Lincoln/Queries.hs view
@@ -1,3 +1,9 @@+-- | Examining a PostFam for a particular component of the main+-- posting (as opposed to the sibling postings) in the PostFam. For+-- some components, such as the payee, the posting might have one+-- piece of data while the TopLine has something else. These functions+-- will examine the Posting first and, if it has no information, use+-- the data from the TopLine if it is there. module Penny.Lincoln.Queries where  import qualified Penny.Lincoln.Bits as B@@ -6,6 +12,8 @@ import Penny.Lincoln.Balance (Balance, entryToBalance) import qualified Data.Time as Time +-- | Uses the data from the Posting if it is set; otherwise, use the+-- data from the TopLine. best ::   (T.Posting -> Maybe a)   -> (T.TopLine -> Maybe a)
+ Penny/Lincoln/Queries/Siblings.hs view
@@ -0,0 +1,87 @@+-- | Like 'Penny.Lincoln.Queries' but instead of querying the main+-- posting of the PostFam, queries the siblings. Therefore, these+-- functions return a list, with each entry in the list containing the+-- best answer for each sibling. There is one item in the list for+-- each sibling, even if all these items contain the same data (for+-- instance, a posting might have five siblings, but all five siblings+-- might have the same payee. Nonetheless the 'payee' function will+-- return a list of five items.)+module Penny.Lincoln.Queries.Siblings where++import qualified Penny.Lincoln.Bits as B+import Penny.Lincoln.Family.Child (Child(Child))+import qualified Penny.Lincoln.Transaction as T+import Penny.Lincoln.Balance (Balance, entryToBalance)++-- | For all siblings, uses information from the Posting if it is set;+-- otherwise, uses data from the TopLine.+bestSibs+  :: (T.Posting -> Maybe a)+  -> (T.TopLine -> Maybe a)+  -> T.PostFam+  -> [Maybe a]+bestSibs fp ft pf =+  let (Child _ s1 ss p) = T.unPostFam pf+      get = maybe (ft p) Just . fp+  in get s1 : map get ss++-- | For all siblings, get the information from the Posting if it+-- exists; otherwise Nothing.+sibs+  :: (T.Posting -> a)+  -> T.PostFam+  -> [a]+sibs fp pf =+  let (Child _ s1 ss _) = T.unPostFam pf+  in fp s1 : map fp ss++payee :: T.PostFam -> [Maybe B.Payee]+payee = bestSibs T.pPayee T.tPayee++number :: T.PostFam -> [Maybe B.Number]+number = bestSibs T.pNumber T.tNumber++flag :: T.PostFam -> [Maybe B.Flag]+flag = bestSibs T.pFlag T.tFlag++postingMemo :: T.PostFam -> [Maybe B.Memo]+postingMemo = sibs T.pMemo++account :: T.PostFam -> [B.Account]+account = sibs T.pAccount++tags :: T.PostFam -> [B.Tags]+tags = sibs T.pTags++entry :: T.PostFam -> [B.Entry]+entry = sibs T.pEntry++balance :: T.PostFam -> [Balance]+balance = map entryToBalance . entry++drCr :: T.PostFam -> [B.DrCr]+drCr = map B.drCr . entry++amount :: T.PostFam -> [B.Amount]+amount = map B.amount . entry++qty :: T.PostFam -> [B.Qty]+qty = map B.qty . amount++commodity :: T.PostFam -> [B.Commodity]+commodity = map B.commodity . amount++postingLine :: T.PostFam -> [Maybe B.PostingLine]+postingLine = sibs T.pPostingLine++side :: T.PostFam -> [Maybe B.Side]+side = map B.side . amount++spaceBetween :: T.PostFam -> [Maybe B.SpaceBetween]+spaceBetween = map B.spaceBetween . amount++globalPosting :: T.PostFam -> [Maybe B.GlobalPosting]+globalPosting = sibs T.pGlobalPosting++filePosting :: T.PostFam -> [Maybe B.FilePosting]+filePosting = sibs T.pFilePosting
Penny/Wheat.hs view
@@ -26,10 +26,12 @@  import Control.Monad (when) import qualified Control.Monad.Exception.Synchronous as Ex+import Data.Either (partitionEithers) import Data.Maybe (mapMaybe) import qualified Penny.Copper as Cop import qualified Penny.Copper.Parsec as CP import qualified Penny.Lincoln as L+import qualified Penny.Liberty as Ly import qualified Data.Text as X import qualified Data.Time as Time import qualified Text.Matchers as M@@ -38,6 +40,7 @@ import qualified System.IO as IO import qualified Penny.Shield as S +import qualified Data.Version as V import qualified Data.Prednote.TestTree as TT import qualified Data.Prednote.Pdct as Pe import qualified System.Console.Rainbow as Rb@@ -153,24 +156,19 @@  allOpts :: [MA.OptSpec (Parsed -> Parsed)] allOpts =+  let allChoices =+        [ ("silent", \p -> p { p_failVerbosity = TT.Silent })+        , ("minimal", \p -> p { p_failVerbosity = TT.PassFail })+        , ("false", \p -> p { p_failVerbosity = TT.FalseSubjects })+        , ("true", \p -> p { p_failVerbosity = TT.TrueSubjects })+        , ("all", \p -> p { p_failVerbosity = TT.Discards })+        ] in   [ MA.OptSpec ["indentation"] "i"     (fmap (\i p -> p { p_indentAmt = i }) (MA.OneArgE MA.reader)) -  , MA.OptSpec ["pass-verbosity"] "p" $ MA.ChoiceArg-    [ ("silent", \p -> p { p_passVerbosity = TT.Silent })-    , ("minimal", \p -> p { p_passVerbosity = TT.PassFail })-    , ("false", \p -> p { p_passVerbosity = TT.FalseSubjects })-    , ("true", \p -> p { p_passVerbosity = TT.TrueSubjects })-    , ("all", \p -> p { p_passVerbosity = TT.Discards })-    ]+  , MA.OptSpec ["pass-verbosity"] "p" $ MA.ChoiceArg allChoices -  , MA.OptSpec ["fail-verbosity"] "f" $ MA.ChoiceArg-    [ ("silent", \p -> p { p_failVerbosity = TT.Silent })-    , ("minimal", \p -> p { p_failVerbosity = TT.PassFail })-    , ("false", \p -> p { p_failVerbosity = TT.FalseSubjects })-    , ("true", \p -> p { p_failVerbosity = TT.TrueSubjects })-    , ("all", \p -> p { p_failVerbosity = TT.Discards })-    ]+  , MA.OptSpec ["fail-verbosity"] "f" $ MA.ChoiceArg allChoices    , MA.OptSpec ["group-regexp"] "g"     (fmap (\f p -> p { p_groupPred = f }) (MA.OneArgE parseRegexp))@@ -216,13 +214,22 @@ -- | Runs Wheat tests. Prints the result to standard output. Exits -- unsuccessfully if the user gave bad command line options or if at -- least a single test failed; exits successfully if all tests--- succeeded.-main :: (S.Runtime -> WheatConf) -> IO ()-main getWc = do+-- succeeded. Shows the version number and exits successfully if that+-- was requested.+main+  :: V.Version+  -- ^ Version of the binary+  -> (S.Runtime -> WheatConf) -> IO ()+main ver getWc = do   rt <- S.runtime   let wc = getWc rt-  fns <- MA.simpleWithHelp (help wc) MA.Intersperse allOpts-         parseArg+  parsed <- MA.simpleWithHelp (help wc) MA.Intersperse+         (fmap Left (Ly.version ver) : (map (fmap Right) allOpts))+         (fmap Right parseArg)+  let (showVers, fns) = partitionEithers parsed+  case showVers of+    [] -> return ()+    x:_ -> x   let fn = foldl (flip (.)) id fns       psd = fn (getParsedFromWheatConf wc)   term <- Rb.smartTermFromEnv (p_colorToFile psd) IO.stdout
Penny/Zinc.hs view
@@ -32,6 +32,7 @@ import Data.Monoid (mappend, mconcat, (<>)) import Data.Ord (comparing) import Data.Text (Text, pack)+import Data.Version (Version) import qualified Data.Text.IO as TIO import qualified System.Console.MultiArg as MA import qualified System.Exit as Exit@@ -40,14 +41,16 @@ import qualified System.Console.Rainbow as R  runZinc-  :: Defaults+  :: Version+  -- ^ Version of the executable+  -> Defaults   -> S.Runtime   -> [I.Report]   -> IO ()-runZinc df rt rs = do+runZinc ver df rt rs = do   let ord = sortPairsToFn . sorter $ df       hlp = helpText df rt rs-  join $ MA.modesWithHelp hlp (allOpts (S.currentTime rt) df)+  join $ MA.modesWithHelp hlp (allOpts ver (S.currentTime rt) df)     (processGlobal rt ord df rs)  @@ -160,6 +163,7 @@   | RExprDesc X.ExprDesc   | RShowExpression   | RVerboseFilter+  | RShowVersion (IO ())  getPostFilters   :: [OptResult]@@ -196,6 +200,13 @@      then return i      else fmap mconcat . sequence $ exSpecs +getShowVersion :: [OptResult] -> Maybe (IO ())+getShowVersion ls = case mapMaybe f ls of+  [] -> Nothing+  xs -> Just $ last xs+  where+    f o = case o of { RShowVersion i -> Just i; _ -> Nothing }+ type Factory = M.CaseSensitive              -> Text -> Ex.Exceptional Text M.Matcher @@ -237,8 +248,8 @@   in fmap (\xs -> (xs, st')) . sequence . catMaybes $ ls  -allOpts :: L.DateTime -> Defaults -> [MA.OptSpec OptResult]-allOpts dt df =+allOpts :: Version -> L.DateTime -> Defaults -> [MA.OptSpec OptResult]+allOpts ver dt df =   map (fmap ROperand) (Ly.operandSpecs dt)   ++ [fmap RPostFilter . fst $ Ly.postFilterSpecs]   ++ [fmap RPostFilter . snd $ Ly.postFilterSpecs]@@ -252,6 +263,7 @@   ++ map (fmap RExprDesc) Ly.exprDesc   ++ [ RShowExpression <$ Ly.showExpression      , RVerboseFilter <$ Ly.verboseFilter+     , fmap RShowVersion (Ly.version ver)      ]  optColorToFile :: MA.OptSpec OptResult@@ -334,25 +346,32 @@ processGlobal rt srt df rpts os   = case processFiltOpts srt df os of       Ex.Exception s -> Left $ (const $ handleTextError s)-      Ex.Success fo -> Right $ map (makeMode rt fo) rpts+      Ex.Success mayFo -> case mayFo of+        Left i -> Left . const $ i+        Right fo -> Right $ map (makeMode rt fo) rpts  processFiltOpts   :: Orderer   -> Defaults   -> [OptResult]-  -> Ex.Exceptional Error FilterOpts-processFiltOpts ord df os = do-  postFilts <- getPostFilters os-  sortSpec <- getSortSpec ord os-  (toks, (rs, rf)) <- makeTokens df os-  let ctf = getColorToFile df os-      sch = getScheme df os-      expDsc = getExprDesc df os-      showExpr = getShowExpression os-      verbFilt = getVerboseFilter os-  pdct <- Ly.parsePredicate expDsc toks-  let sf = Ly.xactionsToFiltered pdct postFilts sortSpec-  return $ FilterOpts rf rs sf sch ctf expDsc pdct showExpr verbFilt+  -> Ex.Exceptional Error (Either (IO ()) FilterOpts)+  -- ^ Left if the user asked to see the version; Right with the+  -- FilterOpts otherwise.+processFiltOpts ord df os = case getShowVersion os of+  Just i -> return $ Left i+  Nothing -> do+    postFilts <- getPostFilters os+    sortSpec <- getSortSpec ord os+    (toks, (rs, rf)) <- makeTokens df os+    let ctf = getColorToFile df os+        sch = getScheme df os+        expDsc = getExprDesc df os+        showExpr = getShowExpression os+        verbFilt = getVerboseFilter os+    pdct <- Ly.parsePredicate expDsc toks+    let sf = Ly.xactionsToFiltered pdct postFilts sortSpec+    return . Right $ FilterOpts rf rs sf sch+                                ctf expDsc pdct showExpr verbFilt  makeMode   :: S.Runtime@@ -524,7 +543,7 @@   , "Dates"   , "-----"   , ""-  , "--date cmp timespec, -d cmp timespec"+  , "-d, --date cmp timespec"   , "  Date must be within the time frame given. timespec"   , "  is a day or a day and a time. Valid values for cmp:"   , "     <, >, <=, >=, ==, /=, !="@@ -561,12 +580,12 @@   , "  Payee must match pattern"   , "-t pattern, --tag pattern"   , "  Tag must match pattern"-  , "--number pattern"+  , "-n, --number pattern"   , "  Number must match pattern"-  , "--flag pattern"+  , "-f, --flag pattern"   , "  Flag must match pattern"-  , "--commodity pattern"-  , "  Pattern must match colon-separated commodity name"+  , "-y, --commodity pattern"+  , "  Pattern must match commodity name"   , "--posting-memo pattern"   , "  Posting memo must match pattern"   , "--transaction-memo pattern"@@ -578,9 +597,30 @@   , "  Entry must be a debit"   , "--credit"   , "  Entry must be a credit"-  , "--qty cmp number"+  , "-q, --qty cmp number"   , "  Entry quantity must fall within given range"+  , "--filename pattern"+  , "  Filename of posting must match pattern"   , ""+  , "Filtering based upon sibling postings"+  , "-------------------------------------"+  , "--s-globalPosting"+  , "--s-revGlobalPosting"+  , "--s-filePosting"+  , "--s-revFilePosting"+  , "--s-account"+  , "--s-account-level"+  , "--s-account-any"+  , "--s-payee"+  , "--s-tag"+  , "--s-number"+  , "--s-flag"+  , "--s-commodity"+  , "--s-posting-memo"+  , "--s-debit"+  , "--s-credit"+  , "--s-qty"+  , ""   , "Options affecting patterns"   , "--------------------------"   , ""@@ -595,11 +635,11 @@    , "" -  , "--within"+  , "-w, --within"   , "  Use \"within\" matcher"     ++ ifDefault (matcher d == Within) -  , "--pcre"+  , "-r, --pcre"   , "  Use \"pcre\" matcher"     ++ ifDefault (matcher d == PCRE) @@ -607,7 +647,7 @@   , "  Use \"posix\" matcher"     ++ ifDefault (matcher d == TDFA) -  , "--exact"+  , "-x, --exact"   , "  Use \"exact\" matcher"     ++ ifDefault (matcher d == Exact)   , ""@@ -622,19 +662,22 @@   , "(all are left associative)"   , "--------------------------"   , "--open expr --close"+  , "-( expr -)"   , "  Force precedence (as in \"open\" and \"close\" parentheses)"-  , "--not expr"+  , "--not, -N expr"   , "  True if expr is false"-  , "expr1 --and expr2 "+  , "expr1 --and expr2"+  , "expr -A expr2"   , "  True if expr and expr2 are both true"   , "expr1 --or expr2"+  , "expr1 -O expr2"   , "  True if either expr1 or expr2 is true"   , ""   , "RPN Operators"   , "-------------"-  , "--not"-  , "--and"-  , "--or"+  , "--not, -N"+  , "--and, -A"+  , "--or, -O"   , "  RPN counterparts to the infix operators"   , "  are postfix and manipulate the RPN stack accordingly"   , ""@@ -687,6 +730,11 @@   , "  Whether to use color when standard output is not a"   , "  terminal (default: " ++     if unColorToFile . colorToFile $ d then "yes)" else "no)"+  , ""+  , "Meta"+  , "----"+  , "--help, -h - show this help and exit"+  , "--version - show version and exit"   ]  
penny-lib.cabal view
@@ -1,5 +1,5 @@ Name: penny-lib-Version: 0.10.0.0+Version: 0.12.0.0 Cabal-version: >=1.8 Build-Type: Simple License: BSD3@@ -45,11 +45,11 @@     , explicit-exception ==0.1.*     , matchers ==0.6.*     , monad-loops ==0.3.*-    , multiarg ==0.12.*+    , multiarg ==0.14.*     , old-locale ==1.0.*     , parsec >= 3.1.2 && < 3.2     , pcre-light ==0.4.*-    , prednote == 0.4.*+    , prednote == 0.8.*     , pretty-show ==1.5.*     , rainbow ==0.2.*     , semigroups ==0.9.*@@ -121,8 +121,10 @@     , Penny.Lincoln.HasText     , Penny.Lincoln.Matchers     , Penny.Lincoln.Predicates+    , Penny.Lincoln.Predicates.Siblings     , Penny.Lincoln.PriceDb     , Penny.Lincoln.Queries+    , Penny.Lincoln.Queries.Siblings     , Penny.Lincoln.Serial     , Penny.Lincoln.Transaction     , Penny.Lincoln.Transaction.Unverified@@ -131,6 +133,9 @@     , Penny.Steel.NestedMap     , Penny.Wheat     , Penny.Zinc++  Other-modules:+      Paths_penny_lib     ghc-options: -Wall