Skip to content

Commit

Permalink
Add include directive
Browse files Browse the repository at this point in the history
  • Loading branch information
mkobetic committed Dec 12, 2023
1 parent 5caa001 commit 9b106e7
Show file tree
Hide file tree
Showing 12 changed files with 197 additions and 93 deletions.
4 changes: 4 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
"type": "go",
"request": "launch",
"mode": "debug",
"env": {
"COIN_TESTS": "${workspaceFolder}/tests"
},
"cwd": "${workspaceFolder}",
"program": "${workspaceFolder}/cmd/coin",
"args": ["test", "-v", "${file}"],
}
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ test: test-go test-fixtures
test-go:
$(TEST) ./...

test-fixtures: export COIN_TESTS=./tests
test-fixtures:
find tests -name '*.test' -exec coin test '{}' \;

Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ For example the following expressions could match account `Assets:Investments:Br
and 'long notes' on separate lines following the transaction or posting line is possible
* tags are parsed out of notes, simple tag #key or value tags #key: some value, (value terminated by a comma or EOL) are supported

### Other types of ledger entries

* Include entry is supported and can be used to inject content of other files in place of the include entry

## Implementation Notes

* Amount is implemented as big.Int plus number of decimal places. Computations are truncated to the specified number of decimal places at every step.
Expand Down
2 changes: 0 additions & 2 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
### Features

* add support for tags
* include directive
* thousand separator in amounts
* check for account/cc numbers in transactions
* balance: last reconciled posting date
Expand Down
8 changes: 8 additions & 0 deletions coin.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,14 @@ func Load(r io.Reader, fn string) {
Transactions = append(Transactions, i)
case *Test:
Tests = append(Tests, i)
case *Include:
files, err := i.Files()
check.NoError(err, "Failed to resolve include %s", i.Path)
for _, f := range files {
// This won't catch nested loops, but should catch the easier to make errors.
check.If(f != fn, "Include loop detected %s", f)
LoadFile(f)
}
default:
fmt.Fprintf(os.Stderr, "Unknown entity %T", i)
os.Exit(1)
Expand Down
56 changes: 56 additions & 0 deletions include.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package coin

import (
"fmt"
"os"
"path/filepath"
"regexp"
)

// Include takes a path pattern that will be expanded into a list of files to include
// at the point when the include is encountered, i.e. the include files are loaded
// BEFORE the loading of the current files continues.
// The pattern is a glob pattern, e.g. "foo/*.coin" interpreted relative to the directory
// of the file containing the include statement.
// Absolute paths are interpreted relative to the directory from which the coin command was executed.
// Environment variables can be used in the pattern as well. They are expanded in the normal way (os.ExpandEnv).
type Include struct {
Path string

line uint
file string
}

var includeHead = regexp.MustCompile(`include\s+(.+)`)

func (p *Parser) parseInclude(fn string) (*Include, error) {
matches := includeHead.FindSubmatch(p.Bytes())
i := &Include{Path: string(matches[1]), line: p.lineNr, file: fn}
p.Scan()
return i, nil
}

func (i *Include) Location() string {
return fmt.Sprintf("%s:%d", i.file, i.line)
}

// Files returns list of file names matching the path to be included.
// Path resolution works as follows:
// - leading / is prepended with . which is the directory from which the coin command was executed;
// - otherwise the path is assumed to be relative to the directory of the file containing the include statement
// - environment variable references are also expanded in normal way (os.ExpandEnv)
// - if the path starts with an env var, it is left to be as it expands
//
// Finally the path is passed to filepath.Glob to expand wildcards.
func (i *Include) Files() ([]string, error) {
var resolved string
if i.Path[0] == '/' {
resolved = "." + i.Path
} else if i.Path[0] == '$' {
resolved = i.Path
} else {
resolved = filepath.Join(filepath.Dir(i.file), i.Path)
}
resolved = os.ExpandEnv(resolved)
return filepath.Glob(resolved)
}
2 changes: 2 additions & 0 deletions parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ func (p *Parser) Next(fn string) (Item, error) {
case bytes.ContainsAny(line[:1], ";#%|*"):
p.Scan()
return p.Next(fn)
case bytes.HasPrefix(line, []byte("include")):
return p.parseInclude(fn)
case bytes.HasPrefix(line, []byte("account")):
return p.parseAccount(fn)
case bytes.HasPrefix(line, []byte("commodity ")):
Expand Down
91 changes: 91 additions & 0 deletions tests/cmd/reg/basic.coin
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
commodity CAD
format 1.00 CAD

account Assets:Bank
account Income:Salary
account Expenses:Food
account Expenses:Rent

2010/01/15 ACME Inc
Bank 1000 CAD
Salary

2010/01/20 Freshco
Food 150 CAD
Bank

2010/01/28 Freshco
Food 100 CAD
Bank

2010/01/30 Housing Corp
Rent 500 CAD
Bank

2010/02/02 Freshco
Food 100 CAD
Bank

2010/02/15 ACME Inc
Bank 1000 CAD
Salary

2010/02/28 Housing Corp
Rent 500 CAD
Bank

2010/03/08 Freshco
Food 200 CAD
Bank

2010/03/15 ACME Inc
Bank 1000 CAD
Salary

2010/03/30 Housing Corp
Rent 500 CAD
Bank

2010/04/15 ACME Inc
Bank 1000 CAD
Salary

2010/04/30 Housing Corp
Rent 500 CAD
Bank

2010/05/05 Freshco
Food 300 CAD
Bank

2010/05/15 ACME Inc
Bank 1000 CAD
Salary

2010/05/30 Housing Corp
Rent 500 CAD
Bank

2010/06/15 ACME Inc
Bank 1000 CAD
Salary

2010/06/22 Freshco
Food 250 CAD
Bank

2010/06/30 Housing Corp
Rent 500 CAD
Bank

2010/07/03 Freshco
Food 300 CAD
Bank

2010/07/15 ACME Inc
Bank 1000 CAD
Salary

2010/07/30 Housing Corp
Rent 500 CAD
Bank
92 changes: 1 addition & 91 deletions tests/cmd/reg/basic.test
Original file line number Diff line number Diff line change
@@ -1,94 +1,4 @@
commodity CAD
format 1.00 CAD

account Assets:Bank
account Income:Salary
account Expenses:Food
account Expenses:Rent

2010/01/15 ACME Inc
Bank 1000 CAD
Salary

2010/01/20 Freshco
Food 150 CAD
Bank

2010/01/28 Freshco
Food 100 CAD
Bank

2010/01/30 Housing Corp
Rent 500 CAD
Bank

2010/02/02 Freshco
Food 100 CAD
Bank

2010/02/15 ACME Inc
Bank 1000 CAD
Salary

2010/02/28 Housing Corp
Rent 500 CAD
Bank

2010/03/08 Freshco
Food 200 CAD
Bank

2010/03/15 ACME Inc
Bank 1000 CAD
Salary

2010/03/30 Housing Corp
Rent 500 CAD
Bank

2010/04/15 ACME Inc
Bank 1000 CAD
Salary

2010/04/30 Housing Corp
Rent 500 CAD
Bank

2010/05/05 Freshco
Food 300 CAD
Bank

2010/05/15 ACME Inc
Bank 1000 CAD
Salary

2010/05/30 Housing Corp
Rent 500 CAD
Bank

2010/06/15 ACME Inc
Bank 1000 CAD
Salary

2010/06/22 Freshco
Food 250 CAD
Bank

2010/06/30 Housing Corp
Rent 500 CAD
Bank

2010/07/03 Freshco
Food 300 CAD
Bank

2010/07/15 ACME Inc
Bank 1000 CAD
Salary

2010/07/30 Housing Corp
Rent 500 CAD
Bank
include basic.coin

test register Food
Expenses:Food CAD
Expand Down
12 changes: 12 additions & 0 deletions tests/cmd/stat/include-absolute.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
; this assumes `coin test` is executed from the root of the repo

include /examples/yearly/commodities.coin
include /examples/yearly/accounts.coin
include /examples/yearly/20??.coin

test stats
Commodities: 1
Prices: 0
Accounts: 17
Transactions: 2558
end test
10 changes: 10 additions & 0 deletions tests/cmd/stat/include-env.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
; this assumes env var COIN_TESTS points at the tests directory

include $COIN_TESTS/cmd/reg/basic.coin

test stats
Commodities: 1
Prices: 0
Accounts: 9
Transactions: 21
end test
8 changes: 8 additions & 0 deletions tests/cmd/stat/include-relative.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
include ../reg/basic.coin

test stats
Commodities: 1
Prices: 0
Accounts: 9
Transactions: 21
end test

0 comments on commit 9b106e7

Please sign in to comment.