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
|
!include personal.journal
|
||||||
!end
|
!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
|
## Core commands
|
||||||
|
|
||||||
These commands are provided by the main hledger package and are always
|
These commands are provided by the main hledger package and are always
|
||||||
|
|||||||
@ -56,7 +56,7 @@ nulljournal = Journal { jmodifiertxns = []
|
|||||||
}
|
}
|
||||||
|
|
||||||
nullctx :: JournalContext
|
nullctx :: JournalContext
|
||||||
nullctx = Ctx { ctxYear = Nothing, ctxCommodity = Nothing, ctxAccount = [] }
|
nullctx = Ctx { ctxYear = Nothing, ctxCommodity = Nothing, ctxAccount = [], ctxAliases = [] }
|
||||||
|
|
||||||
nullfilterspec :: FilterSpec
|
nullfilterspec :: FilterSpec
|
||||||
nullfilterspec = FilterSpec {
|
nullfilterspec = FilterSpec {
|
||||||
|
|||||||
@ -150,6 +150,7 @@ data JournalContext = Ctx {
|
|||||||
, ctxAccount :: ![AccountName] -- ^ the current stack of parent accounts/account name components
|
, ctxAccount :: ![AccountName] -- ^ the current stack of parent accounts/account name components
|
||||||
-- specified with "account" directive(s). Concatenated, these
|
-- specified with "account" directive(s). Concatenated, these
|
||||||
-- are the account prefix prepended to parsed account names.
|
-- 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)
|
} deriving (Read, Show, Eq)
|
||||||
|
|
||||||
data Journal = Journal {
|
data Journal = Journal {
|
||||||
|
|||||||
@ -202,6 +202,8 @@ ledgerDirective = do
|
|||||||
optional $ char '!'
|
optional $ char '!'
|
||||||
choice' [
|
choice' [
|
||||||
ledgerInclude
|
ledgerInclude
|
||||||
|
,ledgerAlias
|
||||||
|
,ledgerEndAliases
|
||||||
,ledgerAccountBegin
|
,ledgerAccountBegin
|
||||||
,ledgerAccountEnd
|
,ledgerAccountEnd
|
||||||
,ledgerTagDirective
|
,ledgerTagDirective
|
||||||
@ -248,6 +250,23 @@ ledgerAccountEnd = do
|
|||||||
popParentAccount
|
popParentAccount
|
||||||
return (return id)
|
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 :: GenParser Char JournalContext JournalUpdate
|
||||||
ledgerTagDirective = do
|
ledgerTagDirective = do
|
||||||
string "tag" <?> "tag directive"
|
string "tag" <?> "tag directive"
|
||||||
@ -447,7 +466,7 @@ ledgerposting = do
|
|||||||
many1 spacenonewline
|
many1 spacenonewline
|
||||||
status <- ledgerstatus
|
status <- ledgerstatus
|
||||||
many spacenonewline
|
many spacenonewline
|
||||||
account <- transactionaccountname
|
account <- modifiedaccountname
|
||||||
let (ptype, account') = (accountNamePostingType account, unbracket account)
|
let (ptype, account') = (accountNamePostingType account, unbracket account)
|
||||||
amount <- postingamount
|
amount <- postingamount
|
||||||
many spacenonewline
|
many spacenonewline
|
||||||
@ -456,9 +475,19 @@ ledgerposting = do
|
|||||||
md <- ledgermetadata
|
md <- ledgermetadata
|
||||||
return (Posting status account' amount comment ptype md Nothing)
|
return (Posting status account' amount comment ptype md Nothing)
|
||||||
|
|
||||||
-- Prepend any parent account currently in effect.
|
-- Parse an account name, then apply any parent account prefix and/or account aliases currently in effect.
|
||||||
transactionaccountname :: GenParser Char JournalContext AccountName
|
modifiedaccountname :: GenParser Char JournalContext AccountName
|
||||||
transactionaccountname = liftM2 joinAccountNames getParentAccount ledgeraccountname
|
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
|
-- | 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
|
-- 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.
|
Utilities common to hledger journal readers.
|
||||||
-}
|
-}
|
||||||
@ -62,6 +63,15 @@ popParentAccount = do ctx0 <- getState
|
|||||||
getParentAccount :: GenParser tok JournalContext String
|
getParentAccount :: GenParser tok JournalContext String
|
||||||
getParentAccount = liftM (concatAccountNames . reverse . ctxAccount) getState
|
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.
|
-- | 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.
|
-- using the current directory from a parsec source position. ~username is not supported.
|
||||||
expandPath :: (MonadIO m) => SourcePos -> FilePath -> m FilePath
|
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" ~:
|
||||||
ledgerAccountNames ledger7 `is`
|
ledgerAccountNames ledger7 `is`
|
||||||
["assets","assets:cash","assets:checking","assets:saving","equity","equity:opening balances",
|
["assets","assets:cash","assets:checking","assets:saving","equity","equity:opening balances",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user