Commit65b1d973Recorded25 Mar 2026Repositorysigil-ledger
Fix == strict balance assertion parsing and correct README API examples
Message
split-balance-assertion was only skipping one character past the = sign, so == assertions left the second = in the amount string. Now detects == and skips both characters. Also fixes README to use actual API names (journal-transaction, not make-journal-transaction) and correct function signatures for the report module.
Added tests for == assertions, cost+assertion combos, and -$50/$-50 negative amount formats.
Changed
README.md | 21 ++++++++-------------
src/sigil/ledger.sgl | 8 ++++++--
test/test-ledger.sgl | 39 ++++++++++++++++++++++++++++++++++++++-
3 files changed, 52 insertions(+), 16 deletions(-)Diff
README.mdmodified
@@ -20,21 +20,19 @@ A Sigil library for reading, writing, and querying [hledger](https://hledger.org
20
(define txns (read-journal "/path/to/finances.journal")) 21
22
;; Create a new transaction−23
(define txn (make-journal-transaction+23
(define txn (journal-transaction 24
date: "2026-03-25" 25
status: "*" 26
description: "Coffee Shop" 27
postings: (list−28
(make-journal-posting+28
(journal-posting 29
account: "expenses:food:coffee"−30
amount: (make-journal-amount quantity: 4.50 commodity: "EUR"))−31
(make-journal-posting+30
amount: (journal-amount quantity: 4.50 commodity: "EUR"))+31
(journal-posting 32
account: "assets:wise:eur")))) 33
−34
;; Append to journal with dedup−35
(append-transactions "/path/to/finances.journal"−36
(list txn)−37
dedup-tag: "ref")+34
;; Append new transactions to journal+35
(append-transactions "/path/to/finances.journal" (list txn)) 36
``` 37
38
### Reports via hledger CLI@@ -43,13 +41,10 @@ A Sigil library for reading, writing, and querying [hledger](https://hledger.org
41
(import (sigil ledger report)) 42
43
;; Run a balance report−46
(define bal (hledger-balance journal: "/path/to/finances.journal"−47
args: '("--tree" "assets")))+44
(hledger-balance "/path/to/finances.journal" "assets" tree: #t) 45
46
;; Income statement for a period−50
(define is (hledger-income-statement−51
journal: "/path/to/finances.journal"−52
args: '("--period" "2026-03")))+47
(hledger-income-statement "/path/to/finances.journal" period: "2026-03") 48
``` 49
50
## Journal Format Supportsrc/sigil/ledger.sglmodified
@@ -503,11 +503,15 @@
503
(amount (parse-amount-string amount-str))) 504
(list account amount cost assertion))) 505
−506
;; Split off balance assertion (= amount) from end+506
;; Split off balance assertion (= or == amount) from end 507
(define (split-balance-assertion text) 508
(let ((eq-pos (find-assertion-equals text))) 509
(if eq-pos−510
(let ((assertion-str (string-trim (substring text (+ eq-pos 1) (string-length text)))))+510
;; Determine if this is == (strict) or = (normal) and skip accordingly+511
(let* ((skip (if (and (< (+ eq-pos 1) (string-length text))+512
(char=? (string-ref text (+ eq-pos 1)) #\=))+513
2 1))+514
(assertion-str (string-trim (substring text (+ eq-pos skip) (string-length text))))) 515
(cons (string-trim (substring text 0 eq-pos)) 516
(parse-amount-string assertion-str))) 517
(cons text #f))))test/test-ledger.sglmodified
@@ -248,6 +248,20 @@
248
(posting (car (journal-transaction-postings (car txns))))) 249
(assert-equal -500.0 (journal-amount-quantity (journal-posting-amount posting))))) 250
+251
(test "parse negative left-symbol -$50"+252
(let* ((text "2026-03-15 * Test\n expenses:food -$50.00\n assets:checking\n")+253
(txns (parse-journal text))+254
(posting (car (journal-transaction-postings (car txns)))))+255
(assert-equal -50.0 (journal-amount-quantity (journal-posting-amount posting)))+256
(assert-equal "$" (journal-amount-commodity (journal-posting-amount posting)))))+257
+258
(test "parse internal negative $-50"+259
(let* ((text "2026-03-15 * Test\n expenses:food $-50.00\n assets:checking\n")+260
(txns (parse-journal text))+261
(posting (car (journal-transaction-postings (car txns)))))+262
(assert-equal -50.0 (journal-amount-quantity (journal-posting-amount posting)))+263
(assert-equal "$" (journal-amount-commodity (journal-posting-amount posting)))))+264
265
(test "parse inferred amount posting" 266
(let* ((text "2026-03-15 * Test\n expenses:food $50.00\n assets:checking\n") 267
(txns (parse-journal text))@@ -301,7 +315,30 @@
315
(bal (journal-posting-balance-assertion posting))) 316
(assert-true (journal-amount? bal)) 317
(assert-equal 5000.0 (journal-amount-quantity bal))−304
(assert-equal "$" (journal-amount-commodity bal)))))+318
(assert-equal "$" (journal-amount-commodity bal))))+319
+320
(test "parse strict balance assertion (==)"+321
(let* ((text "2026-03-15 * Verify\n assets:checking $0 == $5000.00\n income:salary\n")+322
(txns (parse-journal text))+323
(posting (car (journal-transaction-postings (car txns))))+324
(bal (journal-posting-balance-assertion posting)))+325
(assert-true (journal-amount? bal))+326
(assert-equal 5000.0 (journal-amount-quantity bal))+327
(assert-equal "$" (journal-amount-commodity bal))))+328
+329
(test "parse cost with balance assertion"+330
(let* ((text "2026-03-15 * Test\n assets:wise:eur 100.00 EUR @ 1.08 USD = 200.00 EUR\n assets:wise:usd\n")+331
(txns (parse-journal text))+332
(posting (car (journal-transaction-postings (car txns))))+333
(cost (journal-posting-cost posting))+334
(bal (journal-posting-balance-assertion posting)))+335
(assert-true (journal-cost? cost))+336
(assert-equal 'per-unit (journal-cost-type cost))+337
(assert-true (journal-amount? bal))+338
(assert-equal "EUR" (journal-amount-commodity bal))+339
;; Verify quantity parses correctly (use = for numeric comparison+340
;; since exact/inexact integers may not be equal? to each other)+341
(assert-true (= 200 (journal-amount-quantity bal)))))) 342
343
;; ========== Round-trip Tests ========== 344