parsing: alias/end aliases directives, like ledger's but a bit more powerful
This commit is contained in:
		
							parent
							
								
									4015e02097
								
							
						
					
					
						commit
						30b7448f45
					
				
							
								
								
									
										40
									
								
								MANUAL.md
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								MANUAL.md
									
									
									
									
									
								
							| @ -436,6 +436,46 @@ Included files are also affected, eg: | ||||
|     !include personal.journal | ||||
|     !end | ||||
| 
 | ||||
| ### Account aliases | ||||
| 
 | ||||
| You can define account aliases to rewrite certain account names (and their subaccounts). | ||||
| The format is `alias ORIGACCT = ALIAS`. Use `end aliases` to forget all previously defined aliases. | ||||
| 
 | ||||
| Here's an example: say a sole proprietor has a personal.journal: | ||||
| 
 | ||||
|     1/1 | ||||
|         expenses:food  $1 | ||||
|         assets:cash | ||||
| 
 | ||||
| and a business.journal: | ||||
| 
 | ||||
|     1/1 | ||||
|         expenses:office supplies  $1 | ||||
|         assets:business checking | ||||
| 
 | ||||
| Here each entity has a simple journal with its own simple chart of | ||||
| accounts.  But at tax reporting time, we need to view these as a single | ||||
| entity.  So in unified.journal we adjust the personal account names to fit | ||||
| within the business chart of accounts: | ||||
| 
 | ||||
|     alias expenses    = equity:draw:personal | ||||
|     alias assets:cash = assets:personal cash | ||||
|     include personal.journal | ||||
|     end aliases | ||||
|     include business.journal | ||||
| 
 | ||||
| giving: | ||||
| 
 | ||||
|     $ hledger -f unified.journal print | ||||
|     2011/01/01 | ||||
|         equity:draw:personal:food            $1 | ||||
|         assets:personal cash                $-1 | ||||
|      | ||||
|     2011/01/01 | ||||
|         expenses:office supplies            $1 | ||||
|         assets:business checking           $-1 | ||||
| 
 | ||||
| 
 | ||||
| ## Core commands | ||||
| 
 | ||||
| These commands are provided by the main hledger package and are always | ||||
|  | ||||
| @ -56,7 +56,7 @@ nulljournal = Journal { jmodifiertxns = [] | ||||
|                       } | ||||
| 
 | ||||
| nullctx :: JournalContext | ||||
| nullctx = Ctx { ctxYear = Nothing, ctxCommodity = Nothing, ctxAccount = [] } | ||||
| nullctx = Ctx { ctxYear = Nothing, ctxCommodity = Nothing, ctxAccount = [], ctxAliases = [] } | ||||
| 
 | ||||
| nullfilterspec :: FilterSpec | ||||
| nullfilterspec = FilterSpec { | ||||
|  | ||||
| @ -150,6 +150,7 @@ data JournalContext = Ctx { | ||||
|     , ctxAccount   :: ![AccountName]     -- ^ the current stack of parent accounts/account name components | ||||
|                                         --   specified with "account" directive(s). Concatenated, these | ||||
|                                         --   are the account prefix prepended to parsed account names. | ||||
|     , ctxAliases   :: ![(AccountName,AccountName)] -- ^ the current list of account name aliases in effect | ||||
|     } deriving (Read, Show, Eq) | ||||
| 
 | ||||
| data Journal = Journal { | ||||
|  | ||||
| @ -202,6 +202,8 @@ ledgerDirective = do | ||||
|   optional $ char '!' | ||||
|   choice' [ | ||||
|     ledgerInclude | ||||
|    ,ledgerAlias | ||||
|    ,ledgerEndAliases | ||||
|    ,ledgerAccountBegin | ||||
|    ,ledgerAccountEnd | ||||
|    ,ledgerTagDirective | ||||
| @ -248,6 +250,23 @@ ledgerAccountEnd = do | ||||
|   popParentAccount | ||||
|   return (return id) | ||||
| 
 | ||||
| ledgerAlias :: GenParser Char JournalContext JournalUpdate | ||||
| ledgerAlias = do | ||||
|   string "alias" | ||||
|   many1 spacenonewline | ||||
|   orig <- many1 $ noneOf "=" | ||||
|   char '=' | ||||
|   alias <- restofline | ||||
|   addAccountAlias (accountNameWithoutPostingType $ strip orig | ||||
|                   ,accountNameWithoutPostingType $ strip alias) | ||||
|   return $ return id | ||||
| 
 | ||||
| ledgerEndAliases :: GenParser Char JournalContext JournalUpdate | ||||
| ledgerEndAliases = do | ||||
|   string "end aliases" | ||||
|   clearAccountAliases | ||||
|   return (return id) | ||||
| 
 | ||||
| ledgerTagDirective :: GenParser Char JournalContext JournalUpdate | ||||
| ledgerTagDirective = do | ||||
|   string "tag" <?> "tag directive" | ||||
| @ -447,7 +466,7 @@ ledgerposting = do | ||||
|   many1 spacenonewline | ||||
|   status <- ledgerstatus | ||||
|   many spacenonewline | ||||
|   account <- transactionaccountname | ||||
|   account <- modifiedaccountname | ||||
|   let (ptype, account') = (accountNamePostingType account, unbracket account) | ||||
|   amount <- postingamount | ||||
|   many spacenonewline | ||||
| @ -456,9 +475,19 @@ ledgerposting = do | ||||
|   md <- ledgermetadata | ||||
|   return (Posting status account' amount comment ptype md Nothing) | ||||
| 
 | ||||
| -- Prepend any parent account currently in effect. | ||||
| transactionaccountname :: GenParser Char JournalContext AccountName | ||||
| transactionaccountname = liftM2 joinAccountNames getParentAccount ledgeraccountname | ||||
| -- Parse an account name, then apply any parent account prefix and/or account aliases currently in effect. | ||||
| modifiedaccountname :: GenParser Char JournalContext AccountName | ||||
| modifiedaccountname = do | ||||
|   a <- ledgeraccountname | ||||
|   prefix <- getParentAccount | ||||
|   let prefixed = prefix `joinAccountNames` a | ||||
|   aliases <- getAccountAliases | ||||
|   let t = accountNamePostingType prefixed | ||||
|       a' = accountNameWithoutPostingType prefixed | ||||
|       match = headDef Nothing $ map Just $ filter (\(orig,_) -> orig == a' || orig `isAccountNamePrefixOf` a') aliases | ||||
|       rewritten = maybe a' (\(orig,alias) -> alias++drop (length orig) a') match | ||||
|       withtype = accountNameWithPostingType t rewritten | ||||
|   return withtype | ||||
| 
 | ||||
| -- | Parse an account name. Account names may have single spaces inside | ||||
| -- them, and are terminated by two or more spaces. They should have one or | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| {-# LANGUAGE RecordWildCards #-} | ||||
| {-| | ||||
| Utilities common to hledger journal readers. | ||||
| -} | ||||
| @ -62,6 +63,15 @@ popParentAccount = do ctx0 <- getState | ||||
| getParentAccount :: GenParser tok JournalContext String | ||||
| getParentAccount = liftM (concatAccountNames . reverse . ctxAccount) getState | ||||
| 
 | ||||
| addAccountAlias :: (AccountName,AccountName) -> GenParser tok JournalContext () | ||||
| addAccountAlias a = updateState (\(ctx@Ctx{..}) -> ctx{ctxAliases=a:ctxAliases}) | ||||
| 
 | ||||
| getAccountAliases :: GenParser tok JournalContext [(AccountName,AccountName)] | ||||
| getAccountAliases = liftM ctxAliases getState | ||||
| 
 | ||||
| clearAccountAliases :: GenParser tok JournalContext () | ||||
| clearAccountAliases = updateState (\(ctx@Ctx{..}) -> ctx{ctxAliases=[]}) | ||||
| 
 | ||||
| -- | Convert a possibly relative, possibly tilde-containing file path to an absolute one. | ||||
| -- using the current directory from a parsec source position. ~username is not supported. | ||||
| expandPath :: (MonadIO m) => SourcePos -> FilePath -> m FilePath | ||||
|  | ||||
| @ -96,6 +96,11 @@ tests_Hledger_Cli = TestList | ||||
| 
 | ||||
|    ] | ||||
| 
 | ||||
|    ,"account aliases" ~: do | ||||
|       Right j <- readJournal Nothing "!alias expenses = equity:draw:personal\n1/1\n (expenses:food)  1\n" | ||||
|       let p = head $ tpostings $ head $ jtxns j | ||||
|       assertBool "" $ paccount p == "equity:draw:personal:food" | ||||
| 
 | ||||
|   ,"ledgerAccountNames" ~: | ||||
|     ledgerAccountNames ledger7 `is` | ||||
|      ["assets","assets:cash","assets:checking","assets:saving","equity","equity:opening balances", | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user