mirror of
https://github.com/simonmichael/hledger.git
synced 2024-12-26 20:02:27 +03:00
clean up account/description pattern handling
This commit is contained in:
parent
2b608a6c9c
commit
ce0d4ec85a
32
Ledger.hs
32
Ledger.hs
@ -38,15 +38,13 @@ instance Show Ledger where
|
|||||||
-- 1. filter based on account/description patterns, if any
|
-- 1. filter based on account/description patterns, if any
|
||||||
-- 2. cache per-account info
|
-- 2. cache per-account info
|
||||||
-- also, figure out the precision(s) to use
|
-- also, figure out the precision(s) to use
|
||||||
cacheLedger :: [String] -> [String] -> LedgerFile -> Ledger
|
cacheLedger :: ([Regex],[Regex]) -> LedgerFile -> Ledger
|
||||||
cacheLedger acctpats descpats l =
|
cacheLedger pats l =
|
||||||
let
|
let
|
||||||
(acctpats', descpats') = (wilddefault acctpats, wilddefault descpats)
|
lprecision = maximum $ map (precision . amount) $ rawLedgerTransactions l
|
||||||
l' = filterLedgerEntries acctpats descpats l
|
l' = filterLedgerEntries pats l
|
||||||
ant = rawLedgerAccountNameTree l'
|
ant = rawLedgerAccountNameTree l'
|
||||||
ans = flatten ant
|
ans = flatten ant
|
||||||
filterTxnsByAcctpats ts = concat [filter (matchTransactionAccount $ mkRegex r) ts | r <- acctpats']
|
|
||||||
allts = rawLedgerTransactions l
|
|
||||||
ts = rawLedgerTransactions l'
|
ts = rawLedgerTransactions l'
|
||||||
sortedts = sortBy (comparing account) ts
|
sortedts = sortBy (comparing account) ts
|
||||||
groupedts = groupBy (\t1 t2 -> account t1 == account t2) sortedts
|
groupedts = groupBy (\t1 t2 -> account t1 == account t2) sortedts
|
||||||
@ -56,7 +54,6 @@ cacheLedger acctpats descpats l =
|
|||||||
txns = (tmap !)
|
txns = (tmap !)
|
||||||
subaccts a = filter (isAccountNamePrefixOf a) ans
|
subaccts a = filter (isAccountNamePrefixOf a) ans
|
||||||
subtxns a = concat [txns a | a <- [a] ++ subaccts a]
|
subtxns a = concat [txns a | a <- [a] ++ subaccts a]
|
||||||
lprecision = maximum $ map (precision . amount) allts
|
|
||||||
bmap = Map.union
|
bmap = Map.union
|
||||||
(Map.fromList [(a, (sumTransactions $ subtxns a){precision=lprecision}) | a <- ans])
|
(Map.fromList [(a, (sumTransactions $ subtxns a){precision=lprecision}) | a <- ans])
|
||||||
(Map.fromList [(a,nullamt) | a <- ans])
|
(Map.fromList [(a,nullamt) | a <- ans])
|
||||||
@ -65,15 +62,13 @@ cacheLedger acctpats descpats l =
|
|||||||
Ledger l' ant amap lprecision
|
Ledger l' ant amap lprecision
|
||||||
|
|
||||||
-- filter entries by descpats and by whether any transactions contain any acctpats
|
-- filter entries by descpats and by whether any transactions contain any acctpats
|
||||||
filterLedgerEntries1 :: [String] -> [String] -> LedgerFile -> LedgerFile
|
filterLedgerEntries1 :: ([Regex],[Regex]) -> LedgerFile -> LedgerFile
|
||||||
filterLedgerEntries1 acctpats descpats (LedgerFile ms ps es) =
|
filterLedgerEntries1 (acctpats,descpats) (LedgerFile ms ps es) =
|
||||||
LedgerFile ms ps es'
|
LedgerFile ms ps es'
|
||||||
where
|
where
|
||||||
es' = intersect
|
es' = intersect
|
||||||
(concat [filter (matchacct r) es | r <- acctregexps])
|
(concat [filter (matchacct r) es | r <- acctpats])
|
||||||
(concat [filter (matchdesc r) es | r <- descregexps])
|
(concat [filter (matchdesc r) es | r <- descpats])
|
||||||
acctregexps = map mkRegex $ wilddefault acctpats
|
|
||||||
descregexps = map mkRegex $ wilddefault descpats
|
|
||||||
matchacct :: Regex -> LedgerEntry -> Bool
|
matchacct :: Regex -> LedgerEntry -> Bool
|
||||||
matchacct r e = any (matchtxn r) (etransactions e)
|
matchacct r e = any (matchtxn r) (etransactions e)
|
||||||
matchtxn :: Regex -> LedgerTransaction -> Bool
|
matchtxn :: Regex -> LedgerTransaction -> Bool
|
||||||
@ -86,23 +81,22 @@ filterLedgerEntries1 acctpats descpats (LedgerFile ms ps es) =
|
|||||||
otherwise -> True
|
otherwise -> True
|
||||||
|
|
||||||
-- filter txns in each entry by acctpats, then filter the modified entries by descpats
|
-- filter txns in each entry by acctpats, then filter the modified entries by descpats
|
||||||
filterLedgerEntries :: [String] -> [String] -> LedgerFile -> LedgerFile
|
-- this seems aggressive, unbalancing entries, but so far so goo-
|
||||||
filterLedgerEntries acctpats descpats (LedgerFile ms ps es) =
|
filterLedgerEntries :: ([Regex],[Regex]) -> LedgerFile -> LedgerFile
|
||||||
|
filterLedgerEntries (acctpats,descpats) (LedgerFile ms ps es) =
|
||||||
LedgerFile ms ps es'
|
LedgerFile ms ps es'
|
||||||
where
|
where
|
||||||
es' = filter matchanydesc $ map filtertxns es
|
es' = filter matchanydesc $ map filtertxns es
|
||||||
acctregexps = map mkRegex $ wilddefault acctpats
|
|
||||||
descregexps = map mkRegex $ wilddefault descpats
|
|
||||||
filtertxns :: LedgerEntry -> LedgerEntry
|
filtertxns :: LedgerEntry -> LedgerEntry
|
||||||
filtertxns (LedgerEntry d s cod desc com ts) = LedgerEntry d s cod desc com $ filter matchanyacct ts
|
filtertxns (LedgerEntry d s cod desc com ts) = LedgerEntry d s cod desc com $ filter matchanyacct ts
|
||||||
matchanyacct :: LedgerTransaction -> Bool
|
matchanyacct :: LedgerTransaction -> Bool
|
||||||
matchanyacct t = any (matchtxn t) acctregexps
|
matchanyacct t = any (matchtxn t) acctpats
|
||||||
matchtxn :: LedgerTransaction -> Regex -> Bool
|
matchtxn :: LedgerTransaction -> Regex -> Bool
|
||||||
matchtxn t r = case matchRegex r (taccount t) of
|
matchtxn t r = case matchRegex r (taccount t) of
|
||||||
Nothing -> False
|
Nothing -> False
|
||||||
otherwise -> True
|
otherwise -> True
|
||||||
matchanydesc :: LedgerEntry -> Bool
|
matchanydesc :: LedgerEntry -> Bool
|
||||||
matchanydesc e = any (matchdesc e) descregexps
|
matchanydesc e = any (matchdesc e) descpats
|
||||||
matchdesc :: LedgerEntry -> Regex -> Bool
|
matchdesc :: LedgerEntry -> Regex -> Bool
|
||||||
matchdesc e r = case matchRegex r (edescription e) of
|
matchdesc e r = case matchRegex r (edescription e) of
|
||||||
Nothing -> False
|
Nothing -> False
|
||||||
|
16
Options.hs
16
Options.hs
@ -73,8 +73,14 @@ tildeExpand xs = return xs
|
|||||||
|
|
||||||
-- ledger pattern args are 0 or more account patterns optionally followed
|
-- ledger pattern args are 0 or more account patterns optionally followed
|
||||||
-- by -- and 0 or more description patterns
|
-- by -- and 0 or more description patterns
|
||||||
parseLedgerPatternArgs :: [String] -> ([String],[String])
|
parsePatternArgs :: [String] -> ([Regex],[Regex])
|
||||||
parseLedgerPatternArgs args =
|
parsePatternArgs args = argregexes acctpats descpats
|
||||||
case "--" `elem` args of
|
where (acctpats, _:descpats) = break (=="--") args
|
||||||
True -> ((takeWhile (/= "--") args), tail $ (dropWhile (/= "--") args))
|
|
||||||
False -> (args,[])
|
argregexes :: [String] -> [String] -> ([Regex],[Regex])
|
||||||
|
argregexes as ds = (regexify as, regexify ds)
|
||||||
|
where
|
||||||
|
regexify = map mkRegex . wilddefault
|
||||||
|
wilddefault [] = [".*"]
|
||||||
|
wilddefault a = a
|
||||||
|
|
||||||
|
13
Tests.hs
13
Tests.hs
@ -283,7 +283,7 @@ ledger7 = LedgerFile
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
l7 = cacheLedger [] [] ledger7
|
l7 = cacheLedger (argregexes [] []) ledger7
|
||||||
|
|
||||||
timelogentry1_str = "i 2007/03/11 16:19:00 hledger\n"
|
timelogentry1_str = "i 2007/03/11 16:19:00 hledger\n"
|
||||||
timelogentry1 = TimeLogEntry 'i' "2007/03/11 16:19:00" "hledger"
|
timelogentry1 = TimeLogEntry 'i' "2007/03/11 16:19:00" "hledger"
|
||||||
@ -306,14 +306,7 @@ quickcheck = mapM quickCheck ([
|
|||||||
] :: [Bool])
|
] :: [Bool])
|
||||||
|
|
||||||
hunit = runTestTT $ "hunit" ~: test ([
|
hunit = runTestTT $ "hunit" ~: test ([
|
||||||
"" ~: parseLedgerPatternArgs [] @?= ([],[])
|
"" ~: punctuatethousands "" @?= ""
|
||||||
,"" ~: parseLedgerPatternArgs ["a"] @?= (["a"],[])
|
|
||||||
,"" ~: parseLedgerPatternArgs ["a","b"] @?= (["a","b"],[])
|
|
||||||
,"" ~: parseLedgerPatternArgs ["a","b","--"] @?= (["a","b"],[])
|
|
||||||
,"" ~: parseLedgerPatternArgs ["a","b","--","c","b"] @?= (["a","b"],["c","b"])
|
|
||||||
,"" ~: parseLedgerPatternArgs ["--","c"] @?= ([],["c"])
|
|
||||||
,"" ~: parseLedgerPatternArgs ["--"] @?= ([],[])
|
|
||||||
,"" ~: punctuatethousands "" @?= ""
|
|
||||||
,"" ~: punctuatethousands "1234567.8901" @?= "1,234,567.8901"
|
,"" ~: punctuatethousands "1234567.8901" @?= "1,234,567.8901"
|
||||||
,"" ~: punctuatethousands "-100" @?= "-100"
|
,"" ~: punctuatethousands "-100" @?= "-100"
|
||||||
,"" ~: test_ledgertransaction
|
,"" ~: test_ledgertransaction
|
||||||
@ -380,7 +373,7 @@ test_ledgerAccountNames =
|
|||||||
(rawLedgerAccountNames ledger7)
|
(rawLedgerAccountNames ledger7)
|
||||||
|
|
||||||
test_cacheLedger =
|
test_cacheLedger =
|
||||||
assertEqual' 15 (length $ Map.keys $ accounts $ cacheLedger [] [] ledger7)
|
assertEqual' 15 (length $ Map.keys $ accounts $ cacheLedger (argregexes [] []) ledger7)
|
||||||
|
|
||||||
test_showLedgerAccounts =
|
test_showLedgerAccounts =
|
||||||
assertEqual' 4 (length $ lines $ showLedgerAccounts l7 1)
|
assertEqual' 4 (length $ lines $ showLedgerAccounts l7 1)
|
||||||
|
3
Utils.hs
3
Utils.hs
@ -25,9 +25,6 @@ import Test.QuickCheck hiding (test, Testable)
|
|||||||
import Test.HUnit
|
import Test.HUnit
|
||||||
|
|
||||||
|
|
||||||
wilddefault [] = [".*"]
|
|
||||||
wilddefault a = a
|
|
||||||
|
|
||||||
-- lists
|
-- lists
|
||||||
|
|
||||||
splitAtElement :: Eq a => a -> [a] -> [[a]]
|
splitAtElement :: Eq a => a -> [a] -> [[a]]
|
||||||
|
43
hledger.hs
43
hledger.hs
@ -22,44 +22,44 @@ import Utils hiding (test)
|
|||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
(opts, (cmd:args)) <- getArgs >>= parseOptions
|
(opts, (cmd:args)) <- getArgs >>= parseOptions
|
||||||
let (acctpats, descpats) = parseLedgerPatternArgs args
|
let pats = parsePatternArgs args
|
||||||
run cmd opts acctpats descpats
|
run cmd opts pats
|
||||||
where run cmd opts acctpats descpats
|
where run cmd opts pats
|
||||||
| Help `elem` opts = putStr usage
|
| Help `elem` opts = putStr usage
|
||||||
| cmd `isPrefixOf` "test" = test opts acctpats descpats
|
| cmd `isPrefixOf` "test" = test opts pats
|
||||||
| cmd `isPrefixOf` "print" = printcmd opts acctpats descpats
|
| cmd `isPrefixOf` "print" = printcmd opts pats
|
||||||
| cmd `isPrefixOf` "register" = register opts acctpats descpats
|
| cmd `isPrefixOf` "register" = register opts pats
|
||||||
| cmd `isPrefixOf` "balance" = balance opts acctpats descpats
|
| cmd `isPrefixOf` "balance" = balance opts pats
|
||||||
| otherwise = putStr usage
|
| otherwise = putStr usage
|
||||||
|
|
||||||
doWithFilteredLedger :: [Flag] -> [String] -> [String] -> (Ledger -> IO ()) -> IO ()
|
doWithFilteredLedger :: [Flag] -> ([Regex],[Regex]) -> (Ledger -> IO ()) -> IO ()
|
||||||
doWithFilteredLedger opts acctpats descpats cmd = do
|
doWithFilteredLedger opts pats cmd = do
|
||||||
ledgerFilePath opts >>= parseLedgerFile >>= doWithParsed acctpats descpats cmd
|
ledgerFilePath opts >>= parseLedgerFile >>= doWithParsed pats cmd
|
||||||
|
|
||||||
doWithParsed :: [String] -> [String] -> (Ledger -> IO ()) -> (Either ParseError LedgerFile) -> IO ()
|
doWithParsed :: ([Regex],[Regex]) -> (Ledger -> IO ()) -> (Either ParseError LedgerFile) -> IO ()
|
||||||
doWithParsed acctpats descpats cmd parsed = do
|
doWithParsed pats cmd parsed = do
|
||||||
case parsed of Left e -> parseError e
|
case parsed of Left e -> parseError e
|
||||||
Right l -> cmd $ cacheLedger acctpats descpats l
|
Right l -> cmd $ cacheLedger pats l
|
||||||
|
|
||||||
type Command = [Flag] -> [String] -> [String] -> IO ()
|
type Command = [Flag] -> ([Regex],[Regex]) -> IO ()
|
||||||
|
|
||||||
test :: Command
|
test :: Command
|
||||||
test opts acctpats descpats = do
|
test opts pats = do
|
||||||
Tests.hunit
|
Tests.hunit
|
||||||
Tests.quickcheck
|
Tests.quickcheck
|
||||||
return ()
|
return ()
|
||||||
|
|
||||||
printcmd :: Command
|
printcmd :: Command
|
||||||
printcmd opts acctpats descpats = do
|
printcmd opts pats = do
|
||||||
doWithFilteredLedger opts acctpats descpats printentries
|
doWithFilteredLedger opts pats printentries
|
||||||
where
|
where
|
||||||
printentries l = putStr $ showEntries $ setprecision $ entries $ rawledger l
|
printentries l = putStr $ showEntries $ setprecision $ entries $ rawledger l
|
||||||
where
|
where
|
||||||
setprecision = map (entrySetPrecision (lprecision l))
|
setprecision = map (entrySetPrecision (lprecision l))
|
||||||
|
|
||||||
register :: Command
|
register :: Command
|
||||||
register opts acctpats descpats = do
|
register opts pats = do
|
||||||
doWithFilteredLedger opts acctpats descpats printregister
|
doWithFilteredLedger opts pats printregister
|
||||||
where
|
where
|
||||||
printregister l =
|
printregister l =
|
||||||
putStr $ showTransactionsWithBalances
|
putStr $ showTransactionsWithBalances
|
||||||
@ -67,13 +67,14 @@ register opts acctpats descpats = do
|
|||||||
nullamt{precision=lprecision l}
|
nullamt{precision=lprecision l}
|
||||||
|
|
||||||
balance :: Command
|
balance :: Command
|
||||||
balance opts acctpats descpats = do
|
balance opts pats = do
|
||||||
doWithFilteredLedger opts acctpats descpats printbalance
|
doWithFilteredLedger opts pats printbalance
|
||||||
where
|
where
|
||||||
printbalance l =
|
printbalance l =
|
||||||
putStr $ showLedgerAccounts l depth
|
putStr $ showLedgerAccounts l depth
|
||||||
where
|
where
|
||||||
showsubs = (ShowSubs `elem` opts)
|
showsubs = (ShowSubs `elem` opts)
|
||||||
|
(acctpats,_) = pats
|
||||||
depth = case (acctpats, showsubs) of
|
depth = case (acctpats, showsubs) of
|
||||||
([],False) -> 1
|
([],False) -> 1
|
||||||
otherwise -> 9999
|
otherwise -> 9999
|
||||||
|
Loading…
Reference in New Issue
Block a user