A long asked-for feature, pre-declarations, has now arrived!
This feature comes with some breaking changes, even damaging backwards
compatibility with 2.x. I believe it is worth it for the gain in consistency.
------------------------------------------------------------------------------
# BREAKING CHANGES
## 'account' directive
In 2.x, you could enclose a group of transactions within a parent account:
account My Master
...
end account
This is now done with "apply account" instead of "account":
apply account My Master
...
end apply
You can also use "end apply account", and Ledger will verify that it matches
an enclosing "apply account".
## 'tag' directive
In 3.x, you could apply a tag to a group of transactions:
tag Foo: Bar
...
end tag
This is now done with "apply tag" instead of "tag":
apply tag Foo: Bar
...
end apply tag
------------------------------------------------------------------------------
# NEW DIRECTIVES
There are four all new directives:
account
payee
commodity
tag
## New 'account' directive
You can now pre-declare account names. This only has effect if --strict or
--pedantic is used (see below).
account Expenses:Food
account Expenses:Gas
### Account sub-directives
The 'account' directive supports several optional sub-directives, if they
immediately follow the account directive and if they begin with whitespace:
account Expenses:Food
note This account is all about the chicken!
alias food
payee ^(KFC|Popeyes)$
check commodity == "$"
assert commodity == "$"
eval print("Hello!")
default
The 'note' sub-directive associates a textual note with the account. This can
be accessed later using the 'note' valexpr function in any account context.
The 'alias' sub-directive, which can occur multiple times, allows the alias to
be used in place of the full account name anywhere that account names are
allowed.
The 'payee' sub-directive, which can occur multiple times, provides regexps
that identify the account if that payee is encountered and an account within
its transaction ends in the name "Unknown". Example:
2012-02-27 KFC
Expenses:Unknown $10.00 ; Read now as "Expenses:Food"
Assets:Cash
The 'check' and 'assert' directives warn or error (respectively) if the given
value expression evaluates to false within the context of any posting.
The 'eval' directive evaluates the value expression in the context of the
account at the time of definition. At the moment this has little value.
The 'default' directive specifies that this account should be used as the
"balancing account" for any future transactions that contain only a single
posting.
## New 'payee' directive
You can now pre-declare payee names. This only has effect if --check-payees
is used in addition to --strict or --pedantic (see below).
payee KFC
payee Payless
### Payee sub-directives
The 'payee' directive supports one optional sub-directive, if it immediately
follows the payee directive and if it begins with whitespace:
payee KFC
alias KENTUCKY FRIED CHICKEN
The 'alias' directive provides a regexp which, if it matches a parsed payee,
the declared payee name is substituted:
2012-02-27 KENTUCKY FRIED CHICKEN ; will be read as being 'KFC'
...
## New 'commodity' directive
You can now pre-declare commodity names. This only has effect if --strict or
--pedantic is used (see below).
commodity $
commodity CAD
### Commodity sub-directives
The 'commodity' directive supports several optional sub-directives, if they
immediately follow the commodity directive and if they begin with whitespace:
commodity $
note American Dollars
format $1,000.00
nomarket
default
The 'note' sub-directive associates a textual note with the commodity. At
present this has no value other than documentation.
The 'format' directive gives you a way to tell Ledger how to format this
commodity. In future using this directive will disable Ledger's observation
of other ways that commodity is used, and will provide the "canonical"
representation.
The 'nomarket' directive states that the commodity's price should never be
auto-downloaded.
The 'default' directive marks this as the "default" commodity, in contexts
where that applies (the same as the current 'D' directive).
## New 'tag' directive
You can now pre-declare tag names. This only has effect if --strict or
--pedantic is used (see below).
tag Receipt
tag CSV
### Tag sub-directives
The 'tag' directive supports two optional sub-directives, if they immediately
follow the tag directive and if they begin with whitespace:
tag Receipt
check value =~ /pattern/
assert value != "foobar"
The 'check' and 'assert' directives warn or error (respectively) if the given
value expression evaluates to false within the context of any use of the
related tag. In such a context, "value" is bound to the value of the tag
(which may not be a string if typed-metadata is used!). Such checks or
assertions are not called if no value is given.
------------------------------------------------------------------------------
# "KNOWN" ENTITIES
Normally, an account/payee/commodity/tag is considered "known" to Ledger if
it:
1. Occurs within a predeclaration, using the directives above.
2. Occurs within a cleared or pending posting or transaction.
Otherwise, if the account/payee/commodity/tag is first encountered in an
uncleared posting or transaction, it is considered "unknown".
By default, this distinction has no meaning whatsoever, and is not maintained
for the sake of speed. It only has meaning if --strict or --pedantic is used
(see next section).
------------------------------------------------------------------------------
# NEW OPTIONS
## --explicit
When --explicit is given, *only* predeclarations establish the "known-ness" of
parsed entities. I.e., if you didn't predeclare it, you don't expect to ever
see it.
## --strict
With --strict, referring to unknown entities causes a warning.
## --pedantic
With --pedantic, referring to unknown entities causes an error.
## --check-payees
By default, even with --strict or --pedantic, payees are not checked for
known-ness because it is quite typical that new payees are used in uncleared
transactions, or without declaring them. The --check-payees option enables
--strict and --pedantic checking for payees as well.
------------------------------------------------------------------------------
# EXAMPLE
Here's a real example from the baseline tests. Remember that options can be
specified directly within your Ledger file!
--explicit
--pedantic
commodity $
format $1,000.00
account Assets:Cash
assert abs(amount) <= 20
check commodity == '$'
account Expenses:Food
alias food
payee KFC
2012-02-27 KFC
Expenses:Unknown $20.00
Assets:Cash
2012-02-28 KFC
food $20.00
Assets:Cash
test reg --strict
12-Feb-27 KFC Expenses:Food $20.00
$20.00
Assets:Cash $-20.00
0
12-Feb-28 KFC Expenses:Food $20.00
$20.00
Assets:Cash $-20.00
0
end test