Updated developer section
This commit is contained in:
parent
0f3fef427f
commit
37ea7f9b1f
1 changed files with 385 additions and 335 deletions
720
doc/ledger3.texi
720
doc/ledger3.texi
|
|
@ -77,8 +77,8 @@ twinkling in their father's CRT.
|
||||||
* Budgeting and Forecasting::
|
* Budgeting and Forecasting::
|
||||||
* Value Expressions::
|
* Value Expressions::
|
||||||
* Format Strings::
|
* Format Strings::
|
||||||
* Ledger for Developers::
|
|
||||||
* Extending with Python::
|
* Extending with Python::
|
||||||
|
* Ledger for Developers::
|
||||||
* Major Changes from version 2.6::
|
* Major Changes from version 2.6::
|
||||||
* Example Data File::
|
* Example Data File::
|
||||||
* Miscellaneous Notes::
|
* Miscellaneous Notes::
|
||||||
|
|
@ -4093,7 +4093,6 @@ of the balance.
|
||||||
* Primary Financial Reports:: Reports in other formats:: Reports about
|
* Primary Financial Reports:: Reports in other formats:: Reports about
|
||||||
* Reports in other Formats::
|
* Reports in other Formats::
|
||||||
* Reports about your Journals::
|
* Reports about your Journals::
|
||||||
* Developer Commands::
|
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@node Primary Financial Reports, Reports in other Formats, Reporting Commands, Reporting Commands
|
@node Primary Financial Reports, Reports in other Formats, Reporting Commands, Reporting Commands
|
||||||
|
|
@ -4774,7 +4773,7 @@ by Ledger. This is useful for generating and tidying up pricedb
|
||||||
database files.
|
database files.
|
||||||
|
|
||||||
|
|
||||||
@node Reports about your Journals, Developer Commands, Reports in other Formats, Reporting Commands
|
@node Reports about your Journals, , Reports in other Formats, Reporting Commands
|
||||||
@section Reports about your Journals
|
@section Reports about your Journals
|
||||||
|
|
||||||
@menu
|
@menu
|
||||||
|
|
@ -4879,199 +4878,6 @@ macbook-2:$
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@node Developer Commands, , Reports about your Journals, Reporting Commands
|
|
||||||
@section Developer Commands
|
|
||||||
@menu
|
|
||||||
* echo::
|
|
||||||
* reload::
|
|
||||||
* source::
|
|
||||||
* Debug Options::
|
|
||||||
* Pre-commands::
|
|
||||||
@end menu
|
|
||||||
|
|
||||||
@node echo, reload, Developer Commands, Developer Commands
|
|
||||||
@subsection @command{echo}
|
|
||||||
This command simply echos its argument back to the output.
|
|
||||||
|
|
||||||
|
|
||||||
@node reload, source, echo, Developer Commands
|
|
||||||
@subsection @command{reload}
|
|
||||||
Forces ledger to reload any journal files. This function exists to
|
|
||||||
support external programs controlling a running ledger process and does
|
|
||||||
nothing for a command line user.
|
|
||||||
|
|
||||||
@node source, Debug Options, reload, Developer Commands
|
|
||||||
@subsection @command{source}
|
|
||||||
The @code{source} command take a journal file as an argument and parses
|
|
||||||
it checking for errors, no other reports are generated, and no other
|
|
||||||
arguments are necessary. Ledger will return success if no errors are
|
|
||||||
found.
|
|
||||||
|
|
||||||
@node Debug Options, Pre-commands, source, Developer Commands
|
|
||||||
@subsection Debug Options
|
|
||||||
|
|
||||||
These options are primarily for Ledger developers, but may be of some
|
|
||||||
use to a user trying something new.
|
|
||||||
|
|
||||||
@table @code
|
|
||||||
@item --args-only
|
|
||||||
ignore init
|
|
||||||
files and environment variables for the ledger run.
|
|
||||||
|
|
||||||
@item --verify
|
|
||||||
enable additional assertions during run-time. This causes a significant
|
|
||||||
slowdown. When combined with @code{--debug} ledger will produce
|
|
||||||
memory trace information.
|
|
||||||
|
|
||||||
@item --debug "argument"
|
|
||||||
If Ledger has been built with debug options this will provide extra data
|
|
||||||
during the run. The following are the available arguments to debug:
|
|
||||||
|
|
||||||
@multitable @columnfractions .32 .43 .27
|
|
||||||
@item @code{account.display} @tab @code{expr.calc.when} @tab @code{org.next_amount}
|
|
||||||
@item @code{accounts.sorted} @tab @code{expr.compile} @tab @code{org.next_total}
|
|
||||||
@item @code{amount.convert} @tab @code{filters.changed_value} @tab @code{parser.error}
|
|
||||||
@item @code{amount.is_zero} @tab @code{filters.changed_value.rounding} @tab @code{pool.commodities}
|
|
||||||
@item @code{amount.parse} @tab @code{filters.collapse} @tab @code{post.assign}
|
|
||||||
@item @code{amount.price} @tab @code{filters.forecast} @tab @code{python.init}
|
|
||||||
@item @code{amount.truncate} @tab @code{filters.revalued} @tab @code{python.interp}
|
|
||||||
@item @code{amount.unround} @tab @code{format.abbrev} @tab @code{query.mask}
|
|
||||||
@item @code{amounts.commodities} @tab @code{format.expr} @tab @code{report.predicate}
|
|
||||||
@item @code{amounts.refs} @tab @code{generate.post} @tab @code{scope.symbols}
|
|
||||||
@item @code{archive.journal} @tab @code{generate.post.string} @tab @code{textual.include}
|
|
||||||
@item @code{auto.columns} @tab @code{item.meta} @tab @code{textual.parse}
|
|
||||||
@item @code{budget.generate} @tab @code{ledger.read} @tab @code{timelog}
|
|
||||||
@item @code{commodity.annotated.strip} @tab @code{ledger.validate} @tab @code{times.epoch}
|
|
||||||
@item @code{commodity.annotations} @tab @code{lookup} @tab @code{times.interval}
|
|
||||||
@item @code{commodity.compare} @tab @code{lookup.account} @tab @code{times.parse}
|
|
||||||
@item @code{commodity.download} @tab @code{mask.match} @tab @code{value.sort}
|
|
||||||
@item @code{commodity.prices.add} @tab @code{memory.counts} @tab @code{value.storage.refcount}
|
|
||||||
@item @code{commodity.prices.find} @tab @code{memory.counts.live} @tab @code{xact.extend}
|
|
||||||
@item @code{convert.csv} @tab @code{memory.debug} @tab @code{xact.extend.cleared}
|
|
||||||
@item @code{csv.mappings} @tab @code{op.cons} @tab @code{xact.extend.fail}
|
|
||||||
@item @code{csv.parse} @tab @code{op.memory} @tab @code{xact.finalize}
|
|
||||||
@item @code{draft.xact} @tab @code{option.args}
|
|
||||||
@item @code{expr.calc} @tab @code{option.names}
|
|
||||||
@end multitable
|
|
||||||
|
|
||||||
@item --trace INTEGER_TRACE_LEVEL
|
|
||||||
Enable tracing. The integer specifies the level of trace desired:
|
|
||||||
@multitable @columnfractions .3 .7
|
|
||||||
@item @code{LOG_OFF} @tab 0
|
|
||||||
@item @code{LOG_CRIT} @tab 1
|
|
||||||
@item @code{LOG_FATAL} @tab 2
|
|
||||||
@item @code{LOG_ASSERT} @tab 3
|
|
||||||
@item @code{LOG_ERROR} @tab 4
|
|
||||||
@item @code{LOG_VERIFY} @tab 5
|
|
||||||
@item @code{LOG_WARN} @tab 6
|
|
||||||
@item @code{LOG_INFO} @tab 7
|
|
||||||
@item @code{LOG_EXCEPT} @tab 8
|
|
||||||
@item @code{LOG_DEBUG} @tab 9
|
|
||||||
@item @code{LOG_TRACE} @tab 10
|
|
||||||
@item @code{LOG_ALL} @tab 11
|
|
||||||
@end multitable
|
|
||||||
|
|
||||||
@item --verbose
|
|
||||||
Print detailed information on the execution of Ledger.
|
|
||||||
|
|
||||||
@item --version
|
|
||||||
Print version information and exit.
|
|
||||||
@end table
|
|
||||||
|
|
||||||
@node Pre-commands, , Debug Options, Developer Commands
|
|
||||||
@subsection Pre-Commands
|
|
||||||
Pre-commands are useful when you aren't sure how a command or option
|
|
||||||
will work.
|
|
||||||
@table @code
|
|
||||||
@item args
|
|
||||||
evaluate the given arguments against the following model transaction:
|
|
||||||
@smallexample
|
|
||||||
2004/05/27 Book Store
|
|
||||||
; This note applies to all postings. :SecondTag:
|
|
||||||
Expenses:Books 20 BOOK @@ $10
|
|
||||||
; Metadata: Some Value
|
|
||||||
; Typed:: $100 + $200
|
|
||||||
; :ExampleTag:
|
|
||||||
; Here follows a note describing the posting.
|
|
||||||
Liabilities:MasterCard $-200.00
|
|
||||||
@end smallexample
|
|
||||||
@item eval
|
|
||||||
evaluate the given value expression against the model transaction
|
|
||||||
@item expr "LIMIT EXPRESSION"
|
|
||||||
Print details of how ledger parses the given limit expression and apply
|
|
||||||
it against a model transaction.
|
|
||||||
@item format "FORMATTING"
|
|
||||||
Print details of how ledger uses the given formatting description and
|
|
||||||
apply it against a model transaction.
|
|
||||||
@item generate
|
|
||||||
Randomly generates syntactically valid Ledger data from a seed. Used by the
|
|
||||||
GenerateTests harness for development testing
|
|
||||||
@item parse <VALUE EXPR>
|
|
||||||
Print details of how ledger uses the given value expression description
|
|
||||||
and apply it against a model transaction.
|
|
||||||
@item period
|
|
||||||
evaluate the given period and report how Ledger interprets it:
|
|
||||||
@smallexample
|
|
||||||
20:22:21 ~/ledger (next)> ledger period "this year"
|
|
||||||
--- Period expression tokens ---
|
|
||||||
TOK_THIS: this
|
|
||||||
TOK_YEAR: year
|
|
||||||
END_REACHED: <EOF>
|
|
||||||
|
|
||||||
--- Before stabilization ---
|
|
||||||
range: in year 2011
|
|
||||||
|
|
||||||
--- After stabilization ---
|
|
||||||
range: in year 2011
|
|
||||||
start: 11-Jan-01
|
|
||||||
finish: 12-Jan-01
|
|
||||||
|
|
||||||
--- Sample dates in range (max. 20) ---
|
|
||||||
1: 11-Jan-01
|
|
||||||
@end smallexample
|
|
||||||
@item query
|
|
||||||
evaluate the given query and report how Ledger interprets it against the
|
|
||||||
model transaction:
|
|
||||||
|
|
||||||
@smallexample
|
|
||||||
20:25:42 ~/ledger (next)> ledger query "/Book/"
|
|
||||||
--- Input arguments ---
|
|
||||||
("/Book/")
|
|
||||||
|
|
||||||
--- Context is first posting of the following transaction ---
|
|
||||||
2004/05/27 Book Store
|
|
||||||
; This note applies to all postings. :SecondTag:
|
|
||||||
Expenses:Books 20 BOOK @@ $10
|
|
||||||
; Metadata: Some Value
|
|
||||||
; Typed:: $100 + $200
|
|
||||||
; :ExampleTag:
|
|
||||||
; Here follows a note describing the posting.
|
|
||||||
Liabilities:MasterCard $-200.00
|
|
||||||
|
|
||||||
--- Input expression ---
|
|
||||||
(account =~ /Book/)
|
|
||||||
|
|
||||||
--- Text as parsed ---
|
|
||||||
(account =~ /Book/)
|
|
||||||
|
|
||||||
--- Expression tree ---
|
|
||||||
0x7fd639c0da40 O_MATCH (1)
|
|
||||||
0x7fd639c10170 IDENT: account (1)
|
|
||||||
0x7fd639c10780 VALUE: /Book/ (1)
|
|
||||||
|
|
||||||
--- Compiled tree ---
|
|
||||||
0x7fd639c10520 O_MATCH (1)
|
|
||||||
0x7fd639c0d6c0 IDENT: account (1)
|
|
||||||
0x7fd639c0d680 FUNCTION (1)
|
|
||||||
0x7fd639c10780 VALUE: /Book/ (1)
|
|
||||||
|
|
||||||
--- Calculated value ---
|
|
||||||
true
|
|
||||||
@end smallexample
|
|
||||||
@item template
|
|
||||||
Shows the insertion template that a @code{draft} or @code{xact} sub-command generates.
|
|
||||||
This is a debugging command.
|
|
||||||
@end table
|
|
||||||
|
|
||||||
@node Command-line Syntax, Budgeting and Forecasting, Reporting Commands, Top
|
@node Command-line Syntax, Budgeting and Forecasting, Reporting Commands, Top
|
||||||
@chapter Command-line Syntax
|
@chapter Command-line Syntax
|
||||||
|
|
@ -7241,7 +7047,7 @@ Useful specifying a date in plain terms. For example, you could say
|
||||||
@item @code{value_date } @tab @code{} @tab
|
@item @code{value_date } @tab @code{} @tab
|
||||||
@end multitable
|
@end multitable
|
||||||
|
|
||||||
@node Format Strings, Ledger for Developers, Value Expressions, Top
|
@node Format Strings, Extending with Python, Value Expressions, Top
|
||||||
@chapter Format Strings
|
@chapter Format Strings
|
||||||
|
|
||||||
@menu
|
@menu
|
||||||
|
|
@ -7667,15 +7473,172 @@ line number in @code{filename} where posting's entry for posting ends, abbreviat
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@node Extending with Python, Ledger for Developers, Format Strings, Top
|
||||||
|
@chapter Extending with Python
|
||||||
|
Python can be used to extend your Ledger
|
||||||
|
experience. But first, a word must be said about Ledger's data model, so that
|
||||||
|
other things make sense later.
|
||||||
|
|
||||||
|
@menu
|
||||||
|
* Basic data traversal::
|
||||||
|
* Raw vs. Cooked::
|
||||||
|
* Queries::
|
||||||
|
* Embedded Python::
|
||||||
|
* Amounts::
|
||||||
|
@end menu
|
||||||
|
|
||||||
|
@node Basic data traversal, Raw vs. Cooked, Extending with Python, Extending with Python
|
||||||
|
@section Basic data traversal
|
||||||
|
|
||||||
|
Every interaction with Ledger happens in the context of a Session. Even if
|
||||||
|
you don't create a session manually, one is created for you by the top-level
|
||||||
|
interface functions. The Session is where objects live like the Commodity's
|
||||||
|
that Amount's refer to.
|
||||||
|
|
||||||
|
The make a Session useful, you must read a Journal into it, using the function
|
||||||
|
`@code{read_journal}`. This reads Ledger data from the given file, populates a
|
||||||
|
Journal object within the current Session, and returns a reference to that
|
||||||
|
Journal object.
|
||||||
|
|
||||||
|
Within the Journal live all the Transaction's, Posting's, and other objects
|
||||||
|
related to your data. There are also AutomatedTransaction's and
|
||||||
|
PeriodicTransaction's, etc.
|
||||||
|
|
||||||
|
Here is how you would traverse all the postings in your data file:
|
||||||
|
@smallexample
|
||||||
|
|
||||||
|
import ledger
|
||||||
|
|
||||||
|
for xact in ledger.read_journal("sample.dat").xacts:
|
||||||
|
for post in xact.posts:
|
||||||
|
print "Transferring %s to/from %s" % (post.amount, post.account)
|
||||||
|
@end smallexample
|
||||||
|
|
||||||
|
@node Raw vs. Cooked, Queries, Basic data traversal, Extending with Python
|
||||||
|
@section Raw vs. Cooked
|
||||||
|
|
||||||
|
Ledger data exists in one of two forms: raw and cooked. Raw objects are what
|
||||||
|
you get from a traversal like the above, and represent exactly what was seen
|
||||||
|
in the data file. Consider this journal:
|
||||||
|
|
||||||
|
@smallexample
|
||||||
|
= true
|
||||||
|
(Assets:Cash) $100
|
||||||
|
|
||||||
|
2012-03-01 KFC
|
||||||
|
Expenses:Food $100
|
||||||
|
Assets:Credit
|
||||||
|
@end smallexample
|
||||||
|
|
||||||
|
|
||||||
|
In this case, the @emph{raw} regular transaction in this file is:
|
||||||
|
|
||||||
|
@smallexample
|
||||||
|
2012-03-01 KFC
|
||||||
|
Expenses:Food $100
|
||||||
|
Assets:Credit
|
||||||
|
@end smallexample
|
||||||
|
|
||||||
|
While the @emph{cooked} form is:
|
||||||
|
|
||||||
|
@smallexample
|
||||||
|
2012-03-01 KFC
|
||||||
|
Expenses:Food $100
|
||||||
|
Assets:Credit $-100
|
||||||
|
(Assets:Cash) $100
|
||||||
|
@end smallexample
|
||||||
|
|
||||||
|
So the easy way to think about raw vs. cooked is that raw is the unprocessed
|
||||||
|
data, and cooked has had all considerations applied.
|
||||||
|
|
||||||
|
When you traverse a Journal by iterating its transactions, you are generally
|
||||||
|
looking at raw data. In order to look at cooked data, you must generate a
|
||||||
|
report of some kind by querying the journal:
|
||||||
|
|
||||||
|
@smallexample
|
||||||
|
for post in ledger.read_journal("sample.dat").query("food"):
|
||||||
|
print "Transferring %s to/from %s" % (post.amount, post.account)
|
||||||
|
@end smallexample
|
||||||
|
|
||||||
|
The reason why queries iterate over postings instead of transactions is that
|
||||||
|
queries often return only a ``slice'' of the transactions they apply to. You
|
||||||
|
can always get at a matching posting's transaction by looking at its "xact"
|
||||||
|
member:
|
||||||
|
|
||||||
|
@smallexample
|
||||||
|
last_xact = None
|
||||||
|
for post in ledger.read_journal("sample.dat").query(""):
|
||||||
|
if post.xact != last_xact:
|
||||||
|
for post in post.xact.posts:
|
||||||
|
print "Transferring %s to/from %s" % (post.amount,
|
||||||
|
post.account)
|
||||||
|
last_xact = post.xact
|
||||||
|
@end smallexample
|
||||||
|
|
||||||
|
This query ends up reporting every cooked posting in the Journal, but does it
|
||||||
|
transaction-wise. It relies on the fact that an unsorted report returns
|
||||||
|
postings in the exact order they were parsed from the journal file.
|
||||||
|
|
||||||
|
@node Queries, Embedded Python, Raw vs. Cooked, Extending with Python
|
||||||
|
@section Queries
|
||||||
|
|
||||||
|
The Journal.query() method accepts every argument you can specify on the
|
||||||
|
command-line, including --options.
|
||||||
|
|
||||||
|
Since a query ``cooks'' the journal it applies to, only one query may be active
|
||||||
|
for that journal at a given time. Once the query object is gone (after the
|
||||||
|
for loop), then the data reverts back to its raw state.
|
||||||
|
|
||||||
|
@node Embedded Python, Amounts, Queries, Extending with Python
|
||||||
|
@section Embedded Python
|
||||||
|
|
||||||
|
Can you embed Python into your data files using the 'python' directive:
|
||||||
|
|
||||||
|
@smallexample
|
||||||
|
python
|
||||||
|
import so
|
||||||
|
def check_path(path_value):
|
||||||
|
print "%s => %s" % (str(path_value), os.path.isfile(str(path_value)))
|
||||||
|
return os.path.isfile(str(path_value))
|
||||||
|
|
||||||
|
tag PATH
|
||||||
|
assert check_path(value)
|
||||||
|
|
||||||
|
2012-02-29 KFC
|
||||||
|
; PATH: somebogusfile.dat
|
||||||
|
Expenses:Food $20
|
||||||
|
Assets:Cash
|
||||||
|
@end smallexample
|
||||||
|
|
||||||
|
Any Python functions you define this way become immediately available as
|
||||||
|
valexpr functions.
|
||||||
|
|
||||||
|
@node Amounts, , Embedded Python, Extending with Python
|
||||||
|
@section Amounts
|
||||||
|
|
||||||
|
When numbers come from Ledger, like post.amount, the type of the value is
|
||||||
|
Amount. It can be used just like an ordinary number, except that addition
|
||||||
|
and subtraction are restricted to amounts with the same commodity. If you
|
||||||
|
need to create sums of multiple commodities, use a Balance. For example:
|
||||||
|
|
||||||
|
@smallexample
|
||||||
|
total = Balance()
|
||||||
|
for post in ledger.read_journal("sample.dat").query(""):
|
||||||
|
total += post.amount
|
||||||
|
print total
|
||||||
|
@end smallexample
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@node Ledger for Developers, Extending with Python, Format Strings, Top
|
|
||||||
|
@node Ledger for Developers, Major Changes from version 2.6, Extending with Python, Top
|
||||||
@chapter Ledger for Developers
|
@chapter Ledger for Developers
|
||||||
|
|
||||||
@menu
|
@menu
|
||||||
* Internal Design::
|
* Internal Design::
|
||||||
* Journal File Format::
|
* Journal File Format::
|
||||||
|
* Developer Commands::
|
||||||
|
* Ledger Development Environment::
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@node Internal Design, Journal File Format, Ledger for Developers, Ledger for Developers
|
@node Internal Design, Journal File Format, Ledger for Developers, Ledger for Developers
|
||||||
|
|
@ -7902,7 +7865,7 @@ And that's Ledger in a nutshell. All the rest are details, such as which
|
||||||
value expressions each journal item exposes, how many filters currently exist,
|
value expressions each journal item exposes, how many filters currently exist,
|
||||||
which options the report and session scopes define, etc.
|
which options the report and session scopes define, etc.
|
||||||
|
|
||||||
@node Journal File Format, , Internal Design, Ledger for Developers
|
@node Journal File Format, Developer Commands, Internal Design, Ledger for Developers
|
||||||
@section Journal File Format for Developers
|
@section Journal File Format for Developers
|
||||||
|
|
||||||
This chapter offers a complete description of the journal data format,
|
This chapter offers a complete description of the journal data format,
|
||||||
|
|
@ -8168,163 +8131,250 @@ considered a primary. In fact, when Ledger goes about ensures that
|
||||||
all transactions balance to zero, it only ever asks this of primary
|
all transactions balance to zero, it only ever asks this of primary
|
||||||
commodities.
|
commodities.
|
||||||
|
|
||||||
@node Extending with Python, Major Changes from version 2.6, Ledger for Developers, Top
|
@node Developer Commands, Ledger Development Environment, Journal File Format, Ledger for Developers
|
||||||
@chapter Extending with Python
|
@section Developer Commands
|
||||||
Python can be used to extend your Ledger
|
|
||||||
experience. But first, a word must be said about Ledger's data model, so that
|
|
||||||
other things make sense later.
|
|
||||||
|
|
||||||
@menu
|
@menu
|
||||||
* Basic data traversal::
|
* echo::
|
||||||
* Raw vs. Cooked::
|
* reload::
|
||||||
* Queries::
|
* source::
|
||||||
* Embedded Python::
|
* Debug Options::
|
||||||
* Amounts::
|
* Pre-commands::
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@node Basic data traversal, Raw vs. Cooked, Extending with Python, Extending with Python
|
@node echo, reload, Developer Commands, Developer Commands
|
||||||
@section Basic data traversal
|
@subsection @command{echo}
|
||||||
|
This command simply echos its argument back to the output.
|
||||||
|
|
||||||
Every interaction with Ledger happens in the context of a Session. Even if
|
|
||||||
you don't create a session manually, one is created for you by the top-level
|
|
||||||
interface functions. The Session is where objects live like the Commodity's
|
|
||||||
that Amount's refer to.
|
|
||||||
|
|
||||||
The make a Session useful, you must read a Journal into it, using the function
|
@node reload, source, echo, Developer Commands
|
||||||
`@code{read_journal}`. This reads Ledger data from the given file, populates a
|
@subsection @command{reload}
|
||||||
Journal object within the current Session, and returns a reference to that
|
Forces ledger to reload any journal files. This function exists to
|
||||||
Journal object.
|
support external programs controlling a running ledger process and does
|
||||||
|
nothing for a command line user.
|
||||||
|
|
||||||
Within the Journal live all the Transaction's, Posting's, and other objects
|
@node source, Debug Options, reload, Developer Commands
|
||||||
related to your data. There are also AutomatedTransaction's and
|
@subsection @command{source}
|
||||||
PeriodicTransaction's, etc.
|
The @code{source} command take a journal file as an argument and parses
|
||||||
|
it checking for errors, no other reports are generated, and no other
|
||||||
|
arguments are necessary. Ledger will return success if no errors are
|
||||||
|
found.
|
||||||
|
|
||||||
Here is how you would traverse all the postings in your data file:
|
@node Debug Options, Pre-commands, source, Developer Commands
|
||||||
|
@subsection Debug Options
|
||||||
|
|
||||||
|
These options are primarily for Ledger developers, but may be of some
|
||||||
|
use to a user trying something new.
|
||||||
|
|
||||||
|
@table @code
|
||||||
|
@item --args-only
|
||||||
|
ignore init
|
||||||
|
files and environment variables for the ledger run.
|
||||||
|
|
||||||
|
@item --verify
|
||||||
|
enable additional assertions during run-time. This causes a significant
|
||||||
|
slowdown. When combined with @code{--debug} ledger will produce
|
||||||
|
memory trace information.
|
||||||
|
|
||||||
|
@item --debug "argument"
|
||||||
|
If Ledger has been built with debug options this will provide extra data
|
||||||
|
during the run. The following are the available arguments to debug:
|
||||||
|
|
||||||
|
@multitable @columnfractions .32 .43 .27
|
||||||
|
@item @code{account.display} @tab @code{expr.calc.when} @tab @code{org.next_amount}
|
||||||
|
@item @code{accounts.sorted} @tab @code{expr.compile} @tab @code{org.next_total}
|
||||||
|
@item @code{amount.convert} @tab @code{filters.changed_value} @tab @code{parser.error}
|
||||||
|
@item @code{amount.is_zero} @tab @code{filters.changed_value.rounding} @tab @code{pool.commodities}
|
||||||
|
@item @code{amount.parse} @tab @code{filters.collapse} @tab @code{post.assign}
|
||||||
|
@item @code{amount.price} @tab @code{filters.forecast} @tab @code{python.init}
|
||||||
|
@item @code{amount.truncate} @tab @code{filters.revalued} @tab @code{python.interp}
|
||||||
|
@item @code{amount.unround} @tab @code{format.abbrev} @tab @code{query.mask}
|
||||||
|
@item @code{amounts.commodities} @tab @code{format.expr} @tab @code{report.predicate}
|
||||||
|
@item @code{amounts.refs} @tab @code{generate.post} @tab @code{scope.symbols}
|
||||||
|
@item @code{archive.journal} @tab @code{generate.post.string} @tab @code{textual.include}
|
||||||
|
@item @code{auto.columns} @tab @code{item.meta} @tab @code{textual.parse}
|
||||||
|
@item @code{budget.generate} @tab @code{ledger.read} @tab @code{timelog}
|
||||||
|
@item @code{commodity.annotated.strip} @tab @code{ledger.validate} @tab @code{times.epoch}
|
||||||
|
@item @code{commodity.annotations} @tab @code{lookup} @tab @code{times.interval}
|
||||||
|
@item @code{commodity.compare} @tab @code{lookup.account} @tab @code{times.parse}
|
||||||
|
@item @code{commodity.download} @tab @code{mask.match} @tab @code{value.sort}
|
||||||
|
@item @code{commodity.prices.add} @tab @code{memory.counts} @tab @code{value.storage.refcount}
|
||||||
|
@item @code{commodity.prices.find} @tab @code{memory.counts.live} @tab @code{xact.extend}
|
||||||
|
@item @code{convert.csv} @tab @code{memory.debug} @tab @code{xact.extend.cleared}
|
||||||
|
@item @code{csv.mappings} @tab @code{op.cons} @tab @code{xact.extend.fail}
|
||||||
|
@item @code{csv.parse} @tab @code{op.memory} @tab @code{xact.finalize}
|
||||||
|
@item @code{draft.xact} @tab @code{option.args}
|
||||||
|
@item @code{expr.calc} @tab @code{option.names}
|
||||||
|
@end multitable
|
||||||
|
|
||||||
|
@item --trace INTEGER_TRACE_LEVEL
|
||||||
|
Enable tracing. The integer specifies the level of trace desired:
|
||||||
|
@multitable @columnfractions .3 .7
|
||||||
|
@item @code{LOG_OFF} @tab 0
|
||||||
|
@item @code{LOG_CRIT} @tab 1
|
||||||
|
@item @code{LOG_FATAL} @tab 2
|
||||||
|
@item @code{LOG_ASSERT} @tab 3
|
||||||
|
@item @code{LOG_ERROR} @tab 4
|
||||||
|
@item @code{LOG_VERIFY} @tab 5
|
||||||
|
@item @code{LOG_WARN} @tab 6
|
||||||
|
@item @code{LOG_INFO} @tab 7
|
||||||
|
@item @code{LOG_EXCEPT} @tab 8
|
||||||
|
@item @code{LOG_DEBUG} @tab 9
|
||||||
|
@item @code{LOG_TRACE} @tab 10
|
||||||
|
@item @code{LOG_ALL} @tab 11
|
||||||
|
@end multitable
|
||||||
|
|
||||||
|
@item --verbose
|
||||||
|
Print detailed information on the execution of Ledger.
|
||||||
|
|
||||||
|
@item --version
|
||||||
|
Print version information and exit.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@node Pre-commands, , Debug Options, Developer Commands
|
||||||
|
@subsection Pre-Commands
|
||||||
|
Pre-commands are useful when you aren't sure how a command or option
|
||||||
|
will work.
|
||||||
|
@table @code
|
||||||
|
@item args
|
||||||
|
evaluate the given arguments against the following model transaction:
|
||||||
@smallexample
|
@smallexample
|
||||||
|
2004/05/27 Book Store
|
||||||
import ledger
|
; This note applies to all postings. :SecondTag:
|
||||||
|
Expenses:Books 20 BOOK @@ $10
|
||||||
for xact in ledger.read_journal("sample.dat").xacts:
|
; Metadata: Some Value
|
||||||
for post in xact.posts:
|
; Typed:: $100 + $200
|
||||||
print "Transferring %s to/from %s" % (post.amount, post.account)
|
; :ExampleTag:
|
||||||
|
; Here follows a note describing the posting.
|
||||||
|
Liabilities:MasterCard $-200.00
|
||||||
@end smallexample
|
@end smallexample
|
||||||
|
@item eval
|
||||||
|
evaluate the given value expression against the model transaction
|
||||||
|
@item expr "LIMIT EXPRESSION"
|
||||||
|
Print details of how ledger parses the given limit expression and apply
|
||||||
|
it against a model transaction.
|
||||||
|
@item format "FORMATTING"
|
||||||
|
Print details of how ledger uses the given formatting description and
|
||||||
|
apply it against a model transaction.
|
||||||
|
@item generate
|
||||||
|
Randomly generates syntactically valid Ledger data from a seed. Used by the
|
||||||
|
GenerateTests harness for development testing
|
||||||
|
@item parse <VALUE EXPR>
|
||||||
|
Print details of how ledger uses the given value expression description
|
||||||
|
and apply it against a model transaction.
|
||||||
|
@item period
|
||||||
|
evaluate the given period and report how Ledger interprets it:
|
||||||
|
@smallexample
|
||||||
|
20:22:21 ~/ledger (next)> ledger period "this year"
|
||||||
|
--- Period expression tokens ---
|
||||||
|
TOK_THIS: this
|
||||||
|
TOK_YEAR: year
|
||||||
|
END_REACHED: <EOF>
|
||||||
|
|
||||||
@node Raw vs. Cooked, Queries, Basic data traversal, Extending with Python
|
--- Before stabilization ---
|
||||||
@section Raw vs. Cooked
|
range: in year 2011
|
||||||
|
|
||||||
Ledger data exists in one of two forms: raw and cooked. Raw objects are what
|
--- After stabilization ---
|
||||||
you get from a traversal like the above, and represent exactly what was seen
|
range: in year 2011
|
||||||
in the data file. Consider this journal:
|
start: 11-Jan-01
|
||||||
|
finish: 12-Jan-01
|
||||||
|
|
||||||
|
--- Sample dates in range (max. 20) ---
|
||||||
|
1: 11-Jan-01
|
||||||
|
@end smallexample
|
||||||
|
@item query
|
||||||
|
evaluate the given query and report how Ledger interprets it against the
|
||||||
|
model transaction:
|
||||||
|
|
||||||
@smallexample
|
@smallexample
|
||||||
= true
|
20:25:42 ~/ledger (next)> ledger query "/Book/"
|
||||||
(Assets:Cash) $100
|
--- Input arguments ---
|
||||||
|
("/Book/")
|
||||||
|
|
||||||
2012-03-01 KFC
|
--- Context is first posting of the following transaction ---
|
||||||
Expenses:Food $100
|
2004/05/27 Book Store
|
||||||
Assets:Credit
|
; This note applies to all postings. :SecondTag:
|
||||||
|
Expenses:Books 20 BOOK @@ $10
|
||||||
|
; Metadata: Some Value
|
||||||
|
; Typed:: $100 + $200
|
||||||
|
; :ExampleTag:
|
||||||
|
; Here follows a note describing the posting.
|
||||||
|
Liabilities:MasterCard $-200.00
|
||||||
|
|
||||||
|
--- Input expression ---
|
||||||
|
(account =~ /Book/)
|
||||||
|
|
||||||
|
--- Text as parsed ---
|
||||||
|
(account =~ /Book/)
|
||||||
|
|
||||||
|
--- Expression tree ---
|
||||||
|
0x7fd639c0da40 O_MATCH (1)
|
||||||
|
0x7fd639c10170 IDENT: account (1)
|
||||||
|
0x7fd639c10780 VALUE: /Book/ (1)
|
||||||
|
|
||||||
|
--- Compiled tree ---
|
||||||
|
0x7fd639c10520 O_MATCH (1)
|
||||||
|
0x7fd639c0d6c0 IDENT: account (1)
|
||||||
|
0x7fd639c0d680 FUNCTION (1)
|
||||||
|
0x7fd639c10780 VALUE: /Book/ (1)
|
||||||
|
|
||||||
|
--- Calculated value ---
|
||||||
|
true
|
||||||
@end smallexample
|
@end smallexample
|
||||||
|
@item template
|
||||||
|
Shows the insertion template that a @code{draft} or @code{xact} sub-command generates.
|
||||||
|
This is a debugging command.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@node Ledger Development Environment, , Developer Commands, Ledger for Developers
|
||||||
|
@section Ledger Development Environment
|
||||||
|
|
||||||
|
@menu
|
||||||
|
* acrep build configuration tool::
|
||||||
|
* Testing Framework::
|
||||||
|
@end menu
|
||||||
|
|
||||||
|
@node acrep build configuration tool, Testing Framework, Ledger Development Environment, Ledger Development Environment
|
||||||
|
@subsection @code{acprep} build configuration tool
|
||||||
|
|
||||||
|
@node Testing Framework, , acrep build configuration tool, Ledger Development Environment
|
||||||
|
@subsection Testing Framework
|
||||||
|
Ledger source ships with a farily complete set of tests to verify that
|
||||||
|
all is well, and no old errors have been resurfaced. Tests are run
|
||||||
|
individually with @code{ctest}. All tests can be run using @code{make
|
||||||
|
check} or @code{ninja check} depending on which build tool you prefer.
|
||||||
|
|
||||||
|
Once built, the ledger executable resides under the @file{build}
|
||||||
|
subdirectory in the source tree. Tests are built and stored in the test
|
||||||
|
subdirectory for the build. For example,
|
||||||
|
@file{~/ledger/build/ledger/opt/test}.
|
||||||
|
|
||||||
|
@menu
|
||||||
|
* Running Tests::
|
||||||
|
* Writing Tests::
|
||||||
|
@end menu
|
||||||
|
|
||||||
|
|
||||||
In this case, the @emph{raw} regular transaction in this file is:
|
@node Running Tests, Writing Tests, Testing Framework, Testing Framework
|
||||||
|
@subsubsection Running Tests
|
||||||
|
|
||||||
@smallexample
|
The complete test sweet can be run from the build directory using the
|
||||||
2012-03-01 KFC
|
check option for the build tool you use. For example, @code{make
|
||||||
Expenses:Food $100
|
check}. The entire test suit tast around a minute for the optimized
|
||||||
Assets:Credit
|
built and many times longer for the debug version. While developing and
|
||||||
@end smallexample
|
debugging, running individual tests can save a great deal of time.
|
||||||
|
|
||||||
While the @emph{cooked} form is:
|
Individual tests can be run fron the @file{test} subdirectory of the
|
||||||
|
build location. To execute a single test use @code{ctest -V -R regex},
|
||||||
|
where the regex mathes the name of the test you want to build.
|
||||||
|
|
||||||
@smallexample
|
There are nearly 300 tests stored under the @file{test} sudirectoro
|
||||||
2012-03-01 KFC
|
tmain source distribution. They are broken into two broad categories,
|
||||||
Expenses:Food $100
|
baseline and regression. To run the @file{5FBF2ED8} test, for example,
|
||||||
Assets:Credit $-100
|
issue @code{ctest -V -R "5FB"}.
|
||||||
(Assets:Cash) $100
|
@node Writing Tests, , Running Tests, Testing Framework
|
||||||
@end smallexample
|
@subsubsection Writing Tests
|
||||||
|
|
||||||
So the easy way to think about raw vs. cooked is that raw is the unprocessed
|
@node Major Changes from version 2.6, Example Data File, Ledger for Developers, Top
|
||||||
data, and cooked has had all considerations applied.
|
|
||||||
|
|
||||||
When you traverse a Journal by iterating its transactions, you are generally
|
|
||||||
looking at raw data. In order to look at cooked data, you must generate a
|
|
||||||
report of some kind by querying the journal:
|
|
||||||
|
|
||||||
@smallexample
|
|
||||||
for post in ledger.read_journal("sample.dat").query("food"):
|
|
||||||
print "Transferring %s to/from %s" % (post.amount, post.account)
|
|
||||||
@end smallexample
|
|
||||||
|
|
||||||
The reason why queries iterate over postings instead of transactions is that
|
|
||||||
queries often return only a ``slice'' of the transactions they apply to. You
|
|
||||||
can always get at a matching posting's transaction by looking at its "xact"
|
|
||||||
member:
|
|
||||||
|
|
||||||
@smallexample
|
|
||||||
last_xact = None
|
|
||||||
for post in ledger.read_journal("sample.dat").query(""):
|
|
||||||
if post.xact != last_xact:
|
|
||||||
for post in post.xact.posts:
|
|
||||||
print "Transferring %s to/from %s" % (post.amount,
|
|
||||||
post.account)
|
|
||||||
last_xact = post.xact
|
|
||||||
@end smallexample
|
|
||||||
|
|
||||||
This query ends up reporting every cooked posting in the Journal, but does it
|
|
||||||
transaction-wise. It relies on the fact that an unsorted report returns
|
|
||||||
postings in the exact order they were parsed from the journal file.
|
|
||||||
|
|
||||||
@node Queries, Embedded Python, Raw vs. Cooked, Extending with Python
|
|
||||||
@section Queries
|
|
||||||
|
|
||||||
The Journal.query() method accepts every argument you can specify on the
|
|
||||||
command-line, including --options.
|
|
||||||
|
|
||||||
Since a query ``cooks'' the journal it applies to, only one query may be active
|
|
||||||
for that journal at a given time. Once the query object is gone (after the
|
|
||||||
for loop), then the data reverts back to its raw state.
|
|
||||||
|
|
||||||
@node Embedded Python, Amounts, Queries, Extending with Python
|
|
||||||
@section Embedded Python
|
|
||||||
|
|
||||||
Can you embed Python into your data files using the 'python' directive:
|
|
||||||
|
|
||||||
@smallexample
|
|
||||||
python
|
|
||||||
import so
|
|
||||||
def check_path(path_value):
|
|
||||||
print "%s => %s" % (str(path_value), os.path.isfile(str(path_value)))
|
|
||||||
return os.path.isfile(str(path_value))
|
|
||||||
|
|
||||||
tag PATH
|
|
||||||
assert check_path(value)
|
|
||||||
|
|
||||||
2012-02-29 KFC
|
|
||||||
; PATH: somebogusfile.dat
|
|
||||||
Expenses:Food $20
|
|
||||||
Assets:Cash
|
|
||||||
@end smallexample
|
|
||||||
|
|
||||||
Any Python functions you define this way become immediately available as
|
|
||||||
valexpr functions.
|
|
||||||
|
|
||||||
@node Amounts, , Embedded Python, Extending with Python
|
|
||||||
@section Amounts
|
|
||||||
|
|
||||||
When numbers come from Ledger, like post.amount, the type of the value is
|
|
||||||
Amount. It can be used just like an ordinary number, except that addition
|
|
||||||
and subtraction are restricted to amounts with the same commodity. If you
|
|
||||||
need to create sums of multiple commodities, use a Balance. For example:
|
|
||||||
|
|
||||||
@smallexample
|
|
||||||
total = Balance()
|
|
||||||
for post in ledger.read_journal("sample.dat").query(""):
|
|
||||||
total += post.amount
|
|
||||||
print total
|
|
||||||
@end smallexample
|
|
||||||
|
|
||||||
|
|
||||||
@node Major Changes from version 2.6, Example Data File, Extending with Python, Top
|
|
||||||
@chapter Major Changes from version 2.6
|
@chapter Major Changes from version 2.6
|
||||||
|
|
||||||
@itemize
|
@itemize
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue