ledger-style account and description regexp matching
This commit is contained in:
		
							parent
							
								
									7f61228ba8
								
							
						
					
					
						commit
						edbedab32c
					
				
							
								
								
									
										57
									
								
								Models.hs
									
									
									
									
									
								
							
							
						
						
									
										57
									
								
								Models.hs
									
									
									
									
									
								
							| @ -3,8 +3,11 @@ module Models -- data types & behaviours | |||||||
| where | where | ||||||
| 
 | 
 | ||||||
| import Text.Printf | import Text.Printf | ||||||
|  | import Text.Regex | ||||||
| import Data.List | import Data.List | ||||||
| 
 | 
 | ||||||
|  | import Utils | ||||||
|  | 
 | ||||||
| -- basic types | -- basic types | ||||||
| 
 | 
 | ||||||
| type Date = String | type Date = String | ||||||
| @ -17,7 +20,7 @@ type Account = String | |||||||
| data Amount = Amount { | data Amount = Amount { | ||||||
|                       currency :: String, |                       currency :: String, | ||||||
|                       quantity :: Double |                       quantity :: Double | ||||||
|                      } deriving (Eq) |                      } deriving (Eq,Ord) | ||||||
| 
 | 
 | ||||||
| instance Num Amount where | instance Num Amount where | ||||||
|     abs (Amount c q) = Amount c (abs q) |     abs (Amount c q) = Amount c (abs q) | ||||||
| @ -57,15 +60,15 @@ instance Show PeriodicEntry where | |||||||
| 
 | 
 | ||||||
| -- entries | -- entries | ||||||
| -- a register entry is displayed as two or more lines like this: | -- a register entry is displayed as two or more lines like this: | ||||||
| -- date       description          account                    amount     balance | -- date       description          account                amount       balance | ||||||
| -- DDDDDDDDDD dddddddddddddddddddd aaaaaaaaaaaaaaaaaaaaaaaaa  AAAAAAAAAA AAAAAAAAAA | -- DDDDDDDDDD dddddddddddddddddddd aaaaaaaaaaaaaaaaaaaaa  AAAAAAAAAAAA AAAAAAAAAAAA | ||||||
| --                                 aaaaaaaaaaaaaaaaaaaaaaaaa  AAAAAAAAAA AAAAAAAAAA | --                                 aaaaaaaaaaaaaaaaaaaaa  AAAAAAAAAAAA AAAAAAAAAAAA | ||||||
| --                                 ...                        ...        ... | --                                 ...                    ...          ... | ||||||
| -- dateWidth = 10 | -- dateWidth = 10 | ||||||
| -- descWidth = 20 | -- descWidth = 20 | ||||||
| -- acctWidth = 25 | -- acctWidth = 21 | ||||||
| -- amtWidth  = 10 | -- amtWidth  = 12 | ||||||
| -- balWidth  = 10 | -- balWidth  = 12 | ||||||
| 
 | 
 | ||||||
| data Entry = Entry { | data Entry = Entry { | ||||||
|                     edate :: Date, |                     edate :: Date, | ||||||
| @ -73,7 +76,7 @@ data Entry = Entry { | |||||||
|                     ecode :: String, |                     ecode :: String, | ||||||
|                     edescription :: String, |                     edescription :: String, | ||||||
|                     etransactions :: [Transaction] |                     etransactions :: [Transaction] | ||||||
|                    } deriving (Eq) |                    } deriving (Eq,Ord) | ||||||
| 
 | 
 | ||||||
| instance Show Entry where show = showEntry | instance Show Entry where show = showEntry | ||||||
| 
 | 
 | ||||||
| @ -92,11 +95,11 @@ autofillEntry e = | |||||||
| data Transaction = Transaction { | data Transaction = Transaction { | ||||||
|                                 taccount :: Account, |                                 taccount :: Account, | ||||||
|                                 tamount :: Amount |                                 tamount :: Amount | ||||||
|                                } deriving (Eq) |                                } deriving (Eq,Ord) | ||||||
| 
 | 
 | ||||||
| instance Show Transaction where show = showTransaction | instance Show Transaction where show = showTransaction | ||||||
| 
 | 
 | ||||||
| showTransaction t = printf "%-25s  %10s" (take 25 $ taccount t) (show $ tamount t) | showTransaction t = printf "%-21s  %12.2s" (take 21 $ taccount t) (show $ tamount t) | ||||||
| 
 | 
 | ||||||
| autofillTransactions :: [Transaction] -> [Transaction] | autofillTransactions :: [Transaction] -> [Transaction] | ||||||
| autofillTransactions ts = | autofillTransactions ts = | ||||||
| @ -135,10 +138,16 @@ entryTransactionsFrom :: [Entry] -> [EntryTransaction] | |||||||
| entryTransactionsFrom es = concat $ map flattenEntry es | entryTransactionsFrom es = concat $ map flattenEntry es | ||||||
| 
 | 
 | ||||||
| matchTransactionAccount :: String -> EntryTransaction -> Bool | matchTransactionAccount :: String -> EntryTransaction -> Bool | ||||||
| matchTransactionAccount s t = s `isInfixOf` (account t) | matchTransactionAccount s t = | ||||||
|  |     case matchRegex (mkRegex s) (account t) of | ||||||
|  |       Nothing -> False | ||||||
|  |       otherwise -> True | ||||||
| 
 | 
 | ||||||
| matchTransactionDescription :: String -> EntryTransaction -> Bool | matchTransactionDescription :: String -> EntryTransaction -> Bool | ||||||
| matchTransactionDescription s t = s `isInfixOf` (description t) | matchTransactionDescription s t = | ||||||
|  |     case matchRegex (mkRegex s) (description t) of | ||||||
|  |       Nothing -> False | ||||||
|  |       otherwise -> True | ||||||
| 
 | 
 | ||||||
| showTransactionsWithBalances :: [EntryTransaction] -> Amount -> String | showTransactionsWithBalances :: [EntryTransaction] -> Amount -> String | ||||||
| showTransactionsWithBalances [] _ = [] | showTransactionsWithBalances [] _ = [] | ||||||
| @ -162,7 +171,7 @@ showTransactionAndBalance :: EntryTransaction -> Amount -> String | |||||||
| showTransactionAndBalance t b = | showTransactionAndBalance t b = | ||||||
|     (replicate 32 ' ') ++ (showTransaction $ transaction t) ++ (showBalance b) |     (replicate 32 ' ') ++ (showTransaction $ transaction t) ++ (showBalance b) | ||||||
| 
 | 
 | ||||||
| showBalance b = printf " %10.2s" (show b) | showBalance b = printf " %12.2s" (show b) | ||||||
| 
 | 
 | ||||||
| -- accounts | -- accounts | ||||||
| 
 | 
 | ||||||
| @ -175,14 +184,6 @@ expandAccounts l = nub $ concat $ map expand l | |||||||
|                 where |                 where | ||||||
|                   expand l' = map (concat . intersperse ":") (tail $ inits $ splitAtElement ':' l') |                   expand l' = map (concat . intersperse ":") (tail $ inits $ splitAtElement ':' l') | ||||||
| 
 | 
 | ||||||
| splitAtElement :: Eq a => a -> [a] -> [[a]] |  | ||||||
| splitAtElement e l =  |  | ||||||
|     case dropWhile (e==) l of |  | ||||||
|       [] -> [] |  | ||||||
|       l' -> first : splitAtElement e rest |  | ||||||
|         where |  | ||||||
|           (first,rest) = break (e==) l' |  | ||||||
| 
 |  | ||||||
| -- ledger | -- ledger | ||||||
| 
 | 
 | ||||||
| data Ledger = Ledger { | data Ledger = Ledger { | ||||||
| @ -210,6 +211,12 @@ ledgerAccountTree = sort . expandAccounts . ledgerAccountsUsed | |||||||
| ledgerTransactions :: Ledger -> [EntryTransaction] | ledgerTransactions :: Ledger -> [EntryTransaction] | ||||||
| ledgerTransactions l = entryTransactionsFrom $ entries l | ledgerTransactions l = entryTransactionsFrom $ entries l | ||||||
| 
 | 
 | ||||||
| ledgerTransactionsMatching :: String -> Ledger -> [EntryTransaction] | ledgerTransactionsMatching :: ([String],[String]) -> Ledger -> [EntryTransaction] | ||||||
| ledgerTransactionsMatching s l = filter (\t -> matchTransactionAccount s t) (ledgerTransactions l) | ledgerTransactionsMatching ([],[]) l = ledgerTransactionsMatching ([".*"],[".*"]) l | ||||||
| 
 | ledgerTransactionsMatching (rs,[]) l = ledgerTransactionsMatching (rs,[".*"]) l | ||||||
|  | ledgerTransactionsMatching ([],rs) l = ledgerTransactionsMatching ([".*"],rs) l | ||||||
|  | ledgerTransactionsMatching (acctregexps,descregexps) l = | ||||||
|  |     intersect  | ||||||
|  |     (concat [filter (matchTransactionAccount r) ts | r <- acctregexps]) | ||||||
|  |     (concat [filter (matchTransactionDescription r) ts | r <- descregexps]) | ||||||
|  |     where ts = ledgerTransactions l | ||||||
|  | |||||||
							
								
								
									
										16
									
								
								Options.hs
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								Options.hs
									
									
									
									
									
								
							| @ -7,12 +7,14 @@ import Data.Maybe ( fromMaybe ) | |||||||
| import System.Environment (getEnv) | import System.Environment (getEnv) | ||||||
| --import TildeExpand -- confuses my ghc 6.7 | --import TildeExpand -- confuses my ghc 6.7 | ||||||
|      |      | ||||||
|  | import Utils | ||||||
|  | 
 | ||||||
| data Flag = File String | Version deriving Show | data Flag = File String | Version deriving Show | ||||||
|      |      | ||||||
| options :: [OptDescr Flag] | options :: [OptDescr Flag] | ||||||
| options = [ | options = [ | ||||||
|            Option ['f']     ["file"] (OptArg inp "FILE") "ledger file, or - to read stdin" |             Option ['f'] ["file"]    (OptArg inp "FILE") "ledger file, or - to read stdin" | ||||||
|           , Option ['v'] ["version"] (NoArg Version) "show version number" |           , Option ['v'] ["version"] (NoArg Version)     "show version number" | ||||||
|           ] |           ] | ||||||
| 
 | 
 | ||||||
| inp :: Maybe String -> Flag | inp :: Maybe String -> Flag | ||||||
| @ -20,7 +22,7 @@ inp  = File . fromMaybe "stdin" | |||||||
|      |      | ||||||
| getOptions :: [String] -> IO ([Flag], [String]) | getOptions :: [String] -> IO ([Flag], [String]) | ||||||
| getOptions argv = | getOptions argv = | ||||||
|     case getOpt Permute options argv of |     case getOpt RequireOrder options argv of | ||||||
|       (o,n,[]  ) -> return (o,n) |       (o,n,[]  ) -> return (o,n) | ||||||
|       (_,_,errs) -> ioError (userError (concat errs ++ usageInfo header options)) |       (_,_,errs) -> ioError (userError (concat errs ++ usageInfo header options)) | ||||||
|         where header = "Usage: hledger [OPTIONS]" |         where header = "Usage: hledger [OPTIONS]" | ||||||
| @ -34,3 +36,11 @@ defaultLedgerFile = "ledger.dat" | |||||||
| getLedgerFilePath :: IO String | getLedgerFilePath :: IO String | ||||||
| getLedgerFilePath = do | getLedgerFilePath = do | ||||||
|   getEnv "LEDGER" `catch` \_ -> return defaultLedgerFile >>= return |   getEnv "LEDGER" `catch` \_ -> return defaultLedgerFile >>= return | ||||||
|  | 
 | ||||||
|  | -- ledger pattern args are a list of account patterns optionally followed | ||||||
|  | -- by -- and a list of description patterns | ||||||
|  | ledgerPatternArgs :: [String] -> ([String],[String]) | ||||||
|  | ledgerPatternArgs args =  | ||||||
|  |     case "--" `elem` args of | ||||||
|  |       True -> ((takeWhile (/= "--") args), tail $ (dropWhile (/= "--") args)) | ||||||
|  |       False -> (args,[]) | ||||||
|  | |||||||
							
								
								
									
										1
									
								
								TODO
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								TODO
									
									
									
									
									
								
							| @ -25,6 +25,7 @@ environment | |||||||
|  robust ledger file finding |  robust ledger file finding | ||||||
| 
 | 
 | ||||||
| documentation | documentation | ||||||
|  |  --help | ||||||
|  literate docs |  literate docs | ||||||
|  haddock |  haddock | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										9
									
								
								Tests.hs
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								Tests.hs
									
									
									
									
									
								
							| @ -282,4 +282,13 @@ props = | |||||||
|     , |     , | ||||||
|      ledgerAccountTree ledger7 ==  |      ledgerAccountTree ledger7 ==  | ||||||
|      ["assets","assets:cash","assets:checking","equity","equity:opening balances","expenses","expenses:vacation"] |      ["assets","assets:cash","assets:checking","equity","equity:opening balances","expenses","expenses:vacation"] | ||||||
|  |     , | ||||||
|  |      ledgerPatternArgs [] == ([],[]) | ||||||
|  |     ,ledgerPatternArgs ["a"] == (["a"],[]) | ||||||
|  |     ,ledgerPatternArgs ["a","b"] == (["a","b"],[]) | ||||||
|  |     ,ledgerPatternArgs ["a","b","--"] == (["a","b"],[]) | ||||||
|  |     ,ledgerPatternArgs ["a","b","--","c","b"] == (["a","b"],["c","b"]) | ||||||
|  |     ,ledgerPatternArgs ["--","c"] == ([],["c"]) | ||||||
|  |     ,ledgerPatternArgs ["--"] == ([],[]) | ||||||
|     ] |     ] | ||||||
|  | 
 | ||||||
|  | |||||||
| @ -61,5 +61,7 @@ doWithParsed a p = | |||||||
| 
 | 
 | ||||||
| printRegister :: [String] -> Ledger -> IO () | printRegister :: [String] -> Ledger -> IO () | ||||||
| printRegister args ledger = | printRegister args ledger = | ||||||
|     putStr $ showTransactionsWithBalances (ledgerTransactionsMatching (head (args ++ [""])) ledger) 0 |     putStr $ showTransactionsWithBalances  | ||||||
| 
 |                (ledgerTransactionsMatching (acctpats,descpats) ledger) | ||||||
|  |                0 | ||||||
|  |         where (acctpats,descpats) = ledgerPatternArgs args | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user