--alias command-line option
This commit is contained in:
parent
30b7448f45
commit
957c349780
18
MANUAL.md
18
MANUAL.md
@ -439,7 +439,8 @@ Included files are also affected, eg:
|
|||||||
### Account aliases
|
### Account aliases
|
||||||
|
|
||||||
You can define account aliases to rewrite certain account names (and their subaccounts).
|
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.
|
The format is `alias ORIG = ALIAS`, where ORIG and ALIAS are full account names.
|
||||||
|
To forget all aliases defined to this point, use `end aliases`.
|
||||||
|
|
||||||
Here's an example: say a sole proprietor has a personal.journal:
|
Here's an example: say a sole proprietor has a personal.journal:
|
||||||
|
|
||||||
@ -475,6 +476,21 @@ giving:
|
|||||||
expenses:office supplies $1
|
expenses:office supplies $1
|
||||||
assets:business checking $-1
|
assets:business checking $-1
|
||||||
|
|
||||||
|
You can also specify aliases on the command line. This could be useful to
|
||||||
|
rewrite account names when sharing a report with someone else, such as
|
||||||
|
your accountant:
|
||||||
|
|
||||||
|
$ hledger --alias 'my earning=income:business'
|
||||||
|
|
||||||
|
Command-line alias options are applied after any alias directives in the
|
||||||
|
journal. At most one alias directive and one alias option will be applied
|
||||||
|
to each account name.
|
||||||
|
|
||||||
|
Aliases tend to be a little more reliable than post-processing with sed or
|
||||||
|
similar, as they know about account name syntax, posting type indicators
|
||||||
|
etc. Note aliases only change the displayed names, not the account
|
||||||
|
hierarchy - aliasing two accounts to the same name does not merge them
|
||||||
|
into one account.
|
||||||
|
|
||||||
## Core commands
|
## Core commands
|
||||||
|
|
||||||
|
|||||||
@ -242,6 +242,13 @@ journalSelectingDate ActualDate j = j
|
|||||||
journalSelectingDate EffectiveDate j =
|
journalSelectingDate EffectiveDate j =
|
||||||
j{jtxns=map (journalTransactionWithDate EffectiveDate) $ jtxns j}
|
j{jtxns=map (journalTransactionWithDate EffectiveDate) $ jtxns j}
|
||||||
|
|
||||||
|
-- | Apply additional account aliases (eg from the command-line) to all postings in a journal.
|
||||||
|
journalApplyAliases :: [(AccountName,AccountName)] -> Journal -> Journal
|
||||||
|
journalApplyAliases aliases j@Journal{jtxns=ts} = j{jtxns=map fixtransaction ts}
|
||||||
|
where
|
||||||
|
fixtransaction t@Transaction{tpostings=ps} = t{tpostings=map fixposting ps}
|
||||||
|
fixposting p@Posting{paccount=a} = p{paccount=accountNameApplyAliases aliases a}
|
||||||
|
|
||||||
-- | Do post-parse processing on a journal, to make it ready for use.
|
-- | Do post-parse processing on a journal, to make it ready for use.
|
||||||
journalFinalise :: ClockTime -> LocalTime -> FilePath -> String -> JournalContext -> Journal -> Either String Journal
|
journalFinalise :: ClockTime -> LocalTime -> FilePath -> String -> JournalContext -> Journal -> Either String Journal
|
||||||
journalFinalise tclock tlocal path txt ctx j@Journal{files=fs} =
|
journalFinalise tclock tlocal path txt ctx j@Journal{files=fs} =
|
||||||
|
|||||||
@ -99,7 +99,7 @@ postingsDateSpan [] = DateSpan Nothing Nothing
|
|||||||
postingsDateSpan ps = DateSpan (Just $ postingDate $ head ps') (Just $ addDays 1 $ postingDate $ last ps')
|
postingsDateSpan ps = DateSpan (Just $ postingDate $ head ps') (Just $ addDays 1 $ postingDate $ last ps')
|
||||||
where ps' = sortBy (comparing postingDate) ps
|
where ps' = sortBy (comparing postingDate) ps
|
||||||
|
|
||||||
-- balanced/non-balanced posting indicators
|
-- AccountName stuff that depends on PostingType
|
||||||
|
|
||||||
accountNamePostingType :: AccountName -> PostingType
|
accountNamePostingType :: AccountName -> PostingType
|
||||||
accountNamePostingType a
|
accountNamePostingType a
|
||||||
@ -131,6 +131,15 @@ concatAccountNames :: [AccountName] -> AccountName
|
|||||||
concatAccountNames as = accountNameWithPostingType t $ intercalate ":" $ map accountNameWithoutPostingType as
|
concatAccountNames as = accountNameWithPostingType t $ intercalate ":" $ map accountNameWithoutPostingType as
|
||||||
where t = headDef RegularPosting $ filter (/= RegularPosting) $ map accountNamePostingType as
|
where t = headDef RegularPosting $ filter (/= RegularPosting) $ map accountNamePostingType as
|
||||||
|
|
||||||
|
-- | Rewrite an account name using the first applicable alias from the given list, if any.
|
||||||
|
accountNameApplyAliases :: [(AccountName,AccountName)] -> AccountName -> AccountName
|
||||||
|
accountNameApplyAliases aliases a = withorigtype
|
||||||
|
where
|
||||||
|
(a',t) = (accountNameWithoutPostingType a, accountNamePostingType a)
|
||||||
|
firstmatchingalias = headDef Nothing $ map Just $ filter (\(orig,_) -> orig == a' || orig `isAccountNamePrefixOf` a') aliases
|
||||||
|
rewritten = maybe a' (\(orig,alias) -> alias++drop (length orig) a') firstmatchingalias
|
||||||
|
withorigtype = accountNameWithPostingType t rewritten
|
||||||
|
|
||||||
tests_Hledger_Data_Posting = TestList [
|
tests_Hledger_Data_Posting = TestList [
|
||||||
|
|
||||||
"accountNamePostingType" ~: do
|
"accountNamePostingType" ~: do
|
||||||
|
|||||||
@ -482,12 +482,7 @@ modifiedaccountname = do
|
|||||||
prefix <- getParentAccount
|
prefix <- getParentAccount
|
||||||
let prefixed = prefix `joinAccountNames` a
|
let prefixed = prefix `joinAccountNames` a
|
||||||
aliases <- getAccountAliases
|
aliases <- getAccountAliases
|
||||||
let t = accountNamePostingType prefixed
|
return $ accountNameApplyAliases aliases 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
|
||||||
|
|||||||
@ -62,6 +62,7 @@ options_cli :: [OptDescr Opt]
|
|||||||
options_cli = [
|
options_cli = [
|
||||||
Option "f" ["file"] (ReqArg File "FILE") "use a different journal/timelog file; - means stdin"
|
Option "f" ["file"] (ReqArg File "FILE") "use a different journal/timelog file; - means stdin"
|
||||||
,Option "" ["no-new-accounts"] (NoArg NoNewAccts) "don't allow to create new accounts"
|
,Option "" ["no-new-accounts"] (NoArg NoNewAccts) "don't allow to create new accounts"
|
||||||
|
,Option "" ["alias"] (ReqArg Alias "ACCT=ALIAS") "display ACCT's name as ALIAS instead"
|
||||||
,Option "b" ["begin"] (ReqArg Begin "DATE") "report on transactions on or after this date"
|
,Option "b" ["begin"] (ReqArg Begin "DATE") "report on transactions on or after this date"
|
||||||
,Option "e" ["end"] (ReqArg End "DATE") "report on transactions before this date"
|
,Option "e" ["end"] (ReqArg End "DATE") "report on transactions before this date"
|
||||||
,Option "p" ["period"] (ReqArg Period "EXPR") ("report on transactions during the specified period\n" ++
|
,Option "p" ["period"] (ReqArg Period "EXPR") ("report on transactions during the specified period\n" ++
|
||||||
@ -96,6 +97,7 @@ options_cli = [
|
|||||||
data Opt =
|
data Opt =
|
||||||
File {value::String}
|
File {value::String}
|
||||||
| NoNewAccts
|
| NoNewAccts
|
||||||
|
| Alias {value::String}
|
||||||
| Begin {value::String}
|
| Begin {value::String}
|
||||||
| End {value::String}
|
| End {value::String}
|
||||||
| Period {value::String}
|
| Period {value::String}
|
||||||
@ -306,6 +308,18 @@ journalFilePathFromOpts opts = do
|
|||||||
f <- if istimequery then myTimelogPath else myJournalPath
|
f <- if istimequery then myTimelogPath else myJournalPath
|
||||||
return $ last $ f : optValuesForConstructor File opts
|
return $ last $ f : optValuesForConstructor File opts
|
||||||
|
|
||||||
|
aliasesFromOpts :: [Opt] -> [(AccountName,AccountName)]
|
||||||
|
aliasesFromOpts opts = map parseAlias $ optValuesForConstructor Alias opts
|
||||||
|
where
|
||||||
|
-- similar to ledgerAlias
|
||||||
|
parseAlias :: String -> (AccountName,AccountName)
|
||||||
|
parseAlias s = (accountNameWithoutPostingType $ strip orig
|
||||||
|
,accountNameWithoutPostingType $ strip alias')
|
||||||
|
where
|
||||||
|
(orig, alias) = break (=='=') s
|
||||||
|
alias' = case alias of ('=':rest) -> rest
|
||||||
|
_ -> orig
|
||||||
|
|
||||||
-- | Gather filter pattern arguments into a list of account patterns and a
|
-- | Gather filter pattern arguments into a list of account patterns and a
|
||||||
-- list of description patterns. We interpret pattern arguments as
|
-- list of description patterns. We interpret pattern arguments as
|
||||||
-- follows: those prefixed with "desc:" are description patterns, all
|
-- follows: those prefixed with "desc:" are description patterns, all
|
||||||
|
|||||||
@ -38,7 +38,7 @@ import System.Time (ClockTime, getClockTime, diffClockTimes, TimeDiff(TimeDiff))
|
|||||||
import Test.HUnit
|
import Test.HUnit
|
||||||
import Text.Printf
|
import Text.Printf
|
||||||
|
|
||||||
import Hledger.Cli.Options (Opt(..),journalFilePathFromOpts,whichDateFromOpts)
|
import Hledger.Cli.Options
|
||||||
import Hledger.Data
|
import Hledger.Data
|
||||||
import Hledger.Read
|
import Hledger.Read
|
||||||
import Hledger.Utils
|
import Hledger.Utils
|
||||||
@ -51,7 +51,8 @@ withJournalDo opts args _ cmd = do
|
|||||||
-- We kludgily read the file before parsing to grab the full text, unless
|
-- We kludgily read the file before parsing to grab the full text, unless
|
||||||
-- it's stdin, or it doesn't exist and we are adding. We read it strictly
|
-- it's stdin, or it doesn't exist and we are adding. We read it strictly
|
||||||
-- to let the add command work.
|
-- to let the add command work.
|
||||||
journalFilePathFromOpts opts >>= readJournalFile Nothing >>= either error' (cmd opts args)
|
journalFilePathFromOpts opts >>= readJournalFile Nothing >>=
|
||||||
|
either error' (cmd opts args . journalApplyAliases (aliasesFromOpts opts))
|
||||||
|
|
||||||
-- -- | Get a journal from the given string and options, or throw an error.
|
-- -- | Get a journal from the given string and options, or throw an error.
|
||||||
-- readJournalWithOpts :: [Opt] -> String -> IO Journal
|
-- readJournalWithOpts :: [Opt] -> String -> IO Journal
|
||||||
|
|||||||
49
tests/aliases.test
Normal file
49
tests/aliases.test
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
# alias-related tests
|
||||||
|
|
||||||
|
# 1. command-line --alias option. Note multiple applicable aliases, but
|
||||||
|
# only one is applied per account name. Spaces are allowed if quoted.
|
||||||
|
bin/hledger -f- print --alias 'a a=A' --alias b=B
|
||||||
|
<<<
|
||||||
|
2011/01/01
|
||||||
|
a a 1
|
||||||
|
c
|
||||||
|
|
||||||
|
>>>
|
||||||
|
2011/01/01
|
||||||
|
A 1
|
||||||
|
c -1
|
||||||
|
|
||||||
|
>>>=0
|
||||||
|
|
||||||
|
# 2. alias directive, and an account with unbalanced posting indicators.
|
||||||
|
bin/hledger -f- print
|
||||||
|
<<<
|
||||||
|
alias b=B
|
||||||
|
|
||||||
|
2011/01/01
|
||||||
|
(b) 1
|
||||||
|
|
||||||
|
>>>
|
||||||
|
2011/01/01
|
||||||
|
(B) 1
|
||||||
|
|
||||||
|
>>>=0
|
||||||
|
|
||||||
|
# 3. --alias options run after alias directives. Subaccounts are also
|
||||||
|
# matched and rewritten. Accounts with an internal part matching the alias
|
||||||
|
# are ignored.
|
||||||
|
bin/hledger -f- print --alias a=A --alias B=C
|
||||||
|
<<<
|
||||||
|
alias a=B
|
||||||
|
|
||||||
|
2011/01/01
|
||||||
|
[a:x] 1
|
||||||
|
[x:a:x]
|
||||||
|
|
||||||
|
>>>
|
||||||
|
2011/01/01
|
||||||
|
[C:x] 1
|
||||||
|
[x:a:x] -1
|
||||||
|
|
||||||
|
>>>2
|
||||||
|
>>>=0
|
||||||
Loading…
Reference in New Issue
Block a user