Whenever I notice I've made a data entry error, I try to write an
assertion so that I'll catch any similar error in future.
I recently accidentally wrote something like this:
2024/12/01 * Payment
Assets:Credit:Mastercard $10
Assets:Credit:Mastercard
That's a perfectly valid transaction, but obviously not what I intended!
I guess I want to say "all transactions should have at least 2 different
accounts", so how would you encode that into an assertion?
The obvious solution is post.any(account != post.account), but that
won't work because account will be re-evaluated each time. I thought
maybe you can save it outside the any(), like:
"saved=account; post.any(account != saved)"
But that won't work either... it will memoize the assignment and
re-evaluate that too. I did find a solution, you define an expression
and then use that within the any(). This is the final version I ended up
with:
; There should be at least two accounts or commodities per post.
= expr "lambda(_c,_n)=any(account != _n or commodity != _c);!all(lambda(commodity, account)))"
assert has_tag('verified')
This means that if there are not two accounts in a post, *or* you're
exchanging commodities within the same account, then raise an error
unless you tagged it :verified:... it looks like this:
$ ledger bal
While applying automated transaction from "assert.ldg", lines 40-41:
> = expr "lambda(_c,_n)=any(account != _n or commodity != _c);!all(lambda(commodity, account)))"
> assert has_tag('verified')
While extending transaction from "test.ldg", lines 631-633:
> 2024/12/01 * Payment
> Assets:Credit:Mastercard $10
> Assets:Credit:Mastercard
Error: Transaction assertion failed: has_tag("verified")
I dunno, just thought it was an unusual enough solution to mention :)
Tavis.
--
_o) $ lynx
lock.cmpxchg8b.com
/\\ _o) _o) $ finger
tav...@sdf.org
_\_V _( ) _( ) @taviso