Added description of --dc, internal Ledger Architecture, remove ! and @ from command directives
This commit is contained in:
parent
429cfc5c80
commit
61e369b04b
1 changed files with 557 additions and 75 deletions
632
doc/ledger3.texi
632
doc/ledger3.texi
|
|
@ -45,7 +45,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
@titlepage
|
||||
@title Ledger: Command-Line Accounting
|
||||
@subtitle For Version 3.0 of Ledger
|
||||
@subtitle Draft Manual Time-stamp: <2011-12-16 21:23 (cpearls)>
|
||||
@author John Wiegley
|
||||
@end titlepage
|
||||
|
||||
|
|
@ -77,7 +76,7 @@ twinkling in their father's CRT.
|
|||
* Budgeting and Forecasting::
|
||||
* Value Expressions::
|
||||
* Format Strings::
|
||||
* Journal File Format::
|
||||
* Ledger for Developers::
|
||||
* Extending with Python::
|
||||
* Major Changes from version 2.6::
|
||||
* Example Data File::
|
||||
|
|
@ -538,6 +537,7 @@ cannot display any currency symbols other than dollar signs ($).
|
|||
@item @code{-p STR} @tab @code{--period} @tab Set report period to STR
|
||||
@item @code{ } @tab @code{--period-sort} @tab Sort postings within each period
|
||||
@item @code{-C} @tab @code{--cleared} @tab Display only cleared postings
|
||||
@item @code{} @tab @code{--dc} @tab Display register or balance in debit/credit format
|
||||
@item @code{-U} @tab @code{--uncleared} @tab Display only uncleared postings
|
||||
@item @code{-R} @tab @code{--real} @tab Display only real postings
|
||||
@item @code{-L} @tab @code{--actual} @tab Displays only actual postings, not automated
|
||||
|
|
@ -1375,6 +1375,7 @@ posting.
|
|||
* Commenting on your journal::
|
||||
* Currency and Commodities::
|
||||
* Advanced Transactions::
|
||||
* Keeping it Consistent::
|
||||
* File Format::
|
||||
* Archiving Previous Years ::
|
||||
* Using Emacs::
|
||||
|
|
@ -1604,6 +1605,7 @@ since we haven't told ledger to convert commodities.
|
|||
* Naming Commodities::
|
||||
* Buying and Selling Stock::
|
||||
* Fixing Lot Prices::
|
||||
* Complete control over commodity pricing::
|
||||
@end menu
|
||||
|
||||
@node Naming Commodities, Buying and Selling Stock, Currency and Commodities, Currency and Commodities
|
||||
|
|
@ -1655,7 +1657,7 @@ The @{$30.00@} is a lot price. You can also use a lot date,
|
|||
[2004/05/01], or both, in case you have several lots of the same
|
||||
price/date and your taxation model is based on longest-held-first.
|
||||
|
||||
@node Fixing Lot Prices, , Buying and Selling Stock, Currency and Commodities
|
||||
@node Fixing Lot Prices, Complete control over commodity pricing, Buying and Selling Stock, Currency and Commodities
|
||||
@subsection Fixing Lot Prices
|
||||
@cindex fixing lot prices
|
||||
@cindex consumable commodity pricing
|
||||
|
|
@ -1709,10 +1711,11 @@ a balance posting in this case to Equity:Capital Losses to reflect the
|
|||
11 cent difference, which is then balanced by Assets:Checking because
|
||||
its amount is null.
|
||||
|
||||
@node Complete control over commodity pricing, , Fixing Lot Prices, Currency and Commodities
|
||||
@subsection Complete control over commodity pricing
|
||||
|
||||
|
||||
|
||||
@node Advanced Transactions, File Format, Currency and Commodities, Keeping a Journal
|
||||
@node Advanced Transactions, Keeping it Consistent, Currency and Commodities, Keeping a Journal
|
||||
@section Advanced Transactions
|
||||
@menu
|
||||
* Transaction Notes and Tags::
|
||||
|
|
@ -2180,8 +2183,39 @@ $ ledger balance --lot-prices Assets:Broker
|
|||
1 ACME @{$100.00@} Assets:Broker
|
||||
@end smallexample
|
||||
|
||||
@node Keeping it Consistent, File Format, Advanced Transactions, Keeping a Journal
|
||||
@section Keeping it Consistent
|
||||
|
||||
@node File Format, Archiving Previous Years , Advanced Transactions, Keeping a Journal
|
||||
Sometimes Ledger's flexibility can lead to difficulties. Using a
|
||||
freeform text editor to enter transactions makes it easy to keep the
|
||||
data, but also easy to enter accounts or payees inconsistently or with
|
||||
spelling errors.
|
||||
|
||||
In order to combat inconsistency you can define allowable accounts and
|
||||
or payees. For simplicity, create a separate text file and enter define
|
||||
accounts a payees like
|
||||
@smallexample
|
||||
account Expenses
|
||||
account Expenses:Utilities
|
||||
...
|
||||
@end smallexample
|
||||
Using the @samp{--strict} option will cause Ledger to complain if any accounts are not previously defined:
|
||||
@smallexample
|
||||
15:27:39 ~/ledger (next) > ledger bal --strict
|
||||
Warning: "FinanceData/Master.dat", line 6: Unknown account 'Liabilities:Tithe Owed'
|
||||
Warning: "FinanceData/Master.dat", line 8: Unknown account 'Liabilities:Tithe Owed'
|
||||
Warning: "FinanceData/Master.dat", line 15: Unknown account 'Allocation:Equities:Domestic'
|
||||
@end smallexample
|
||||
|
||||
If you have a large Ledger register already created use the @samp{accounts} command to get started:
|
||||
@smallexample
|
||||
ledger accounts >> Accounts.dat
|
||||
@end smallexample
|
||||
|
||||
@noindent You will have to edit this file to add the @samp{account} directive.
|
||||
|
||||
|
||||
@node File Format, Archiving Previous Years , Keeping it Consistent, Keeping a Journal
|
||||
@section File Format for Users
|
||||
@menu
|
||||
* File Format Intro::
|
||||
|
|
@ -2272,13 +2306,11 @@ Ledger.
|
|||
@subsection Command Directives
|
||||
|
||||
@table @code
|
||||
@item ! @@
|
||||
A line beginning with an exclamation mark or an @@ sign denotes a
|
||||
command directive. It must be immediately followed by a command word.
|
||||
The supported commands are:
|
||||
@item beginning of line
|
||||
Command directives must occur at the beginning of a line. Use of ! and
|
||||
@@ is deprecated.
|
||||
|
||||
|
||||
@item @@account
|
||||
@item account
|
||||
@c instance_t::master_account_directive
|
||||
Sets the root for all accounts following the directive. Ledger supports
|
||||
a hierarchical tree of accounts. It may be convenient to keep two
|
||||
|
|
@ -2290,7 +2322,7 @@ groups of transaction without manually editing them using the account
|
|||
directive. For example:
|
||||
@smallexample
|
||||
|
||||
@@account Personal
|
||||
account Personal
|
||||
2011/11/15 Supermarket
|
||||
Expenses:Groceries
|
||||
Assets:Checking
|
||||
|
|
@ -2299,16 +2331,16 @@ directive. For example:
|
|||
|
||||
Would result in all postings going into
|
||||
@code{Personal:Expenses:Groceries} and @code{Personal:Assets:hecking}
|
||||
until and @code{@@end account} directive was found.
|
||||
until and @code{end account} directive was found.
|
||||
|
||||
@item @@alias
|
||||
@item alias
|
||||
@c instance_t::alias_directive
|
||||
Define an alias for an account name. If you have a deeply nested tree
|
||||
of accounts, it may be convenient to define an alias, for example:
|
||||
@smallexample
|
||||
|
||||
@@alias Dining=Expenses:Entertainment:Dining
|
||||
@@alias Checking=Assets:Credit Union:Joint Checking Account
|
||||
alias Dining=Expenses:Entertainment:Dining
|
||||
alias Checking=Assets:Credit Union:Joint Checking Account
|
||||
|
||||
2011/11/28 YummyPalace
|
||||
Dining $10.00
|
||||
|
|
@ -2317,32 +2349,32 @@ of accounts, it may be convenient to define an alias, for example:
|
|||
@end smallexample
|
||||
|
||||
The aliases are only in effect for transactions read in after the alias
|
||||
is defined and are effected by @code{@@account} directives that precede
|
||||
is defined and are effected by @code{account} directives that precede
|
||||
them.
|
||||
@item @@assert
|
||||
@item assert
|
||||
@c instance_t::assert_directive
|
||||
An assertion can throw an error if a condition is not met during Ledger's run.
|
||||
|
||||
@smallexample
|
||||
|
||||
@@assert <VALUE EXPRESSION BOOLEAN RESULT>
|
||||
assert <VALUE EXPRESSION BOOLEAN RESULT>
|
||||
|
||||
@end smallexample
|
||||
|
||||
|
||||
@item @@bucket
|
||||
@item bucket
|
||||
@c instance_t::default_account_directive
|
||||
Defines the default account to use for balancing transactions.
|
||||
Normally, each transaction has at least two postings, which must balance
|
||||
to zero. Ledger allows you to leave one posting with no amount and
|
||||
automatically calculate balance the transaction in the posting. The
|
||||
@code{@@bucket} allows you to fill in all postings and automatically
|
||||
@code{bucket} allows you to fill in all postings and automatically
|
||||
generate an additional posting to the bucket account balancing the
|
||||
transaction. The following example set the @code{Assets:Checking} as
|
||||
the bucket:
|
||||
@smallexample
|
||||
|
||||
@@bucket Assets:Checking
|
||||
bucket Assets:Checking
|
||||
2011/01/25 Tom's Used Cars
|
||||
Expenses:Auto $ 5,500.00
|
||||
|
||||
|
|
@ -2354,13 +2386,13 @@ the bucket:
|
|||
|
||||
@end smallexample
|
||||
|
||||
@item @@capture
|
||||
@item capture
|
||||
@c instance_t::account_mapping_directive
|
||||
Directs Ledger to replace any account matching a regex with the given
|
||||
account. For example:
|
||||
|
||||
@smallexample
|
||||
@@capture Expenses:Deductible:Medical Medical
|
||||
capture Expenses:Deductible:Medical Medical
|
||||
@end smallexample
|
||||
|
||||
Would cause any posting with @code{Medical} in it's name to be replaced with
|
||||
|
|
@ -2370,23 +2402,23 @@ Would cause any posting with @code{Medical} in it's name to be replaced with
|
|||
Ledger will display the mapped payees in @code{print} and
|
||||
@code{register} reports.
|
||||
|
||||
@item @@check
|
||||
@item check
|
||||
@c instance_t::check_directive in textual.cc
|
||||
A check can issue a warning if a condition is not met during Ledger's run.
|
||||
|
||||
@smallexample
|
||||
|
||||
@@check <VALUE EXPRESSION BOOLEAN RESULT>
|
||||
check <VALUE EXPRESSION BOOLEAN RESULT>
|
||||
|
||||
@end smallexample
|
||||
@item @@comment
|
||||
@item comment
|
||||
@c instance_t::comment_directive in textual.cc
|
||||
Start a block comment, closed by @code{@@end comment}.
|
||||
@item @@define
|
||||
Start a block comment, closed by @code{end comment}.
|
||||
@item define
|
||||
@c instance_t::define_directive in textual.cc
|
||||
Allows you to define value expression for future use. For example:
|
||||
@smallexample
|
||||
@@define var_name=$100
|
||||
define var_name=$100
|
||||
|
||||
2011/12/01 Test
|
||||
Expenses (var_name*4)
|
||||
|
|
@ -2394,20 +2426,20 @@ Allows you to define value expression for future use. For example:
|
|||
@end smallexample
|
||||
|
||||
The posting will have a cost of $400.
|
||||
@item @@end
|
||||
@item end
|
||||
@c instance_t::end_directive in textual.cc
|
||||
Closes block commands like @code{@@tag} or @code{@@comment}.
|
||||
@item @@expr
|
||||
Closes block commands like @code{tag} or @code{comment}.
|
||||
@item expr
|
||||
@c instance_t::expr_directive in textual.cc
|
||||
|
||||
@item @@fixed
|
||||
@item fixed
|
||||
@c instance_t::fixed_directive in textual.cc
|
||||
|
||||
@item @@include
|
||||
@item include
|
||||
@c instance_t::include_directive in textual.cc
|
||||
Include the stated file as if it were part of the current file.
|
||||
|
||||
@item @@payee
|
||||
@item payee
|
||||
@c instance_t::payee_mapping_directive in textual.cc
|
||||
Directs Ledger to replace any payee matching a regex with the given
|
||||
payee. You may download transactions from your bank that you want to be
|
||||
|
|
@ -2416,19 +2448,19 @@ near me is only one character different than the payee if I buy gasoline
|
|||
at the grocery story. I can enter payee mappings that make this very clear:
|
||||
|
||||
@smallexample
|
||||
@@payee Supermarket Gas Supermarket 4
|
||||
@@payee Supermarket Groceries Supermarket 1
|
||||
payee Supermarket Gas Supermarket 4
|
||||
payee Supermarket Groceries Supermarket 1
|
||||
@end smallexample
|
||||
|
||||
Ledger will display the mapped payees in @code{print} and
|
||||
@code{register} reports.
|
||||
|
||||
@item @@tag
|
||||
@item tag
|
||||
@c instance_t::tag_directive in textual.cc
|
||||
Allows you to designate a block of transactions and assign the same tag to all. Tags can have values and may be nested.
|
||||
@smallexample
|
||||
@@tag hastag
|
||||
@@tag nestedtag: true
|
||||
tag hastag
|
||||
tag nestedtag: true
|
||||
2011/01/25 Tom's Used Cars
|
||||
Expenses:Auto $ 5,500.00
|
||||
; :nobudget:
|
||||
|
|
@ -2438,12 +2470,12 @@ Allows you to designate a block of transactions and assign the same tag to all.
|
|||
Expenses:Books $20.00
|
||||
Liabilities:MasterCard
|
||||
|
||||
@@end tag nestedtag
|
||||
end tag nestedtag
|
||||
|
||||
2011/12/01 Sale
|
||||
Assets:Checking:Business $ 30.00
|
||||
Income:Sales
|
||||
@@end tag hastag
|
||||
end tag hastag
|
||||
@end smallexample
|
||||
|
||||
@noindent is the equivalent of
|
||||
|
|
@ -2468,18 +2500,18 @@ Allows you to designate a block of transactions and assign the same tag to all.
|
|||
Income:Sales
|
||||
@end smallexample
|
||||
|
||||
Note that anything following "@code{@@end tag}" is ignored. placing the
|
||||
Note that anything following "@code{end tag}" is ignored. placing the
|
||||
name of the tag that is being closed is a simple way to keep track.
|
||||
|
||||
@item @@test
|
||||
@item test
|
||||
@c instance_t::comment_directive in textual.cc
|
||||
This is a synonym for @code{@@comment} and must be closed by and @code{@@end} tag.
|
||||
This is a synonym for @code{comment} and must be closed by and @code{end} tag.
|
||||
|
||||
@item @@year
|
||||
@item year
|
||||
@c instance_t::year_directive in textual.cc
|
||||
Denotes the year used for all subsequent transactions that give a date
|
||||
without a year. The year should appear immediately after the Y, for
|
||||
example: @samp{@@year 2004}. This is useful at the beginning of a file, to
|
||||
example: @samp{year 2004}. This is useful at the beginning of a file, to
|
||||
specify the year for that file. If all transactions specify a year,
|
||||
however, this command has no effect.
|
||||
|
||||
|
|
@ -2491,9 +2523,9 @@ alone, for backwards compatibility with older Ledger versions.
|
|||
|
||||
@table @code
|
||||
@item A
|
||||
See @code{@@bucket}
|
||||
See @code{bucket}
|
||||
@item Y
|
||||
See @code{@@year}
|
||||
See @code{year}
|
||||
|
||||
|
||||
@item N SYMBOL
|
||||
|
|
@ -2891,7 +2923,7 @@ there are none. The second looks for any account with ``Bo'', which is
|
|||
If you want to know exactly how much you have spent in a particular
|
||||
account on a particular payee, the following are equivalent:
|
||||
@smallexample
|
||||
> ledger balance Auto:Fuel and @@Chevron
|
||||
> ledger balance Auto:Fuel and Chevron
|
||||
> ledger balance --limit "(account=~/Fuel/) & (payee=~/Chev/)"
|
||||
@end smallexample
|
||||
@noindent will show you the amount expended on gasoline at Chevron. The second
|
||||
|
|
@ -3062,7 +3094,7 @@ current allocation? Using the balance command and some tricky formatting!
|
|||
ledger bal Allocation --current --format "\
|
||||
%-17((depth_spacer)+(partial_account))\
|
||||
%10(percent(market(display_total), market(parent.total)))\
|
||||
%16(market(display_total))\n"
|
||||
%16(market(display_total))\n%/"
|
||||
@end smallexample
|
||||
|
||||
Which yields:
|
||||
|
|
@ -3074,6 +3106,7 @@ Allocation 100.00% $100000.00
|
|||
Domestic 95.31% $58196.29
|
||||
Global 4.69% $2863.71
|
||||
@end smallexample
|
||||
|
||||
Let's look at the Ledger invocation a bit closer. The command above is
|
||||
split into lines for clarity. The first line is very vanilla Ledger
|
||||
asking for the current balances of the account in the ``Allocation''
|
||||
|
|
@ -3088,9 +3121,10 @@ print the partial account name indented by its depth in the tree. The
|
|||
third line is where we calculate and display the percentages. The
|
||||
@code{display_total} command give the values of the total calculated for
|
||||
the account in this line. The @code{parent.total} command gives the
|
||||
total for the next level up in the tree. @code{percent} format their
|
||||
total for the next level up in the tree. @code{percent} formats their
|
||||
ratio as a percentage. The fourth line tells ledger to display the
|
||||
current market value of the the line.
|
||||
current market value of the the line. The last two characters ``%/''
|
||||
tell Ledger what to do for the last line, in this case, nothing.
|
||||
|
||||
@cindex plotting
|
||||
@cindex GNUplot
|
||||
|
|
@ -3870,9 +3904,9 @@ backwards compatibility with Ledger 2.X.
|
|||
@node payees, , entry and xact, Reports about your Journals
|
||||
@subsection payees
|
||||
The @command{payees} reports all of the unique payees in the journal. To
|
||||
filter the payees displayed you must use the @@ prefix:
|
||||
filter the payees displayed you must use the prefix:
|
||||
@smallexample
|
||||
macbook-2:$ ledger payees '@@Tar.+t'
|
||||
macbook-2:$ ledger payees 'Tar.+t'
|
||||
El Dorade Restaraunt
|
||||
My Big Fat Greek Restaraunt
|
||||
Target
|
||||
|
|
@ -4440,6 +4474,57 @@ specifies the width, in characters, of the date column in the register report.
|
|||
@option{--datetime-format}
|
||||
ASK JOHN
|
||||
|
||||
@option{--dc} Display register or balance in debit/credit format
|
||||
If you use @samp{--dc} with either the register (reg) or balance (bal) commands, you
|
||||
will now get extra columns. The register goes from this:
|
||||
@smallexample
|
||||
12-Mar-10 Employer Assets:Cash $100 $100
|
||||
Income:Employer $-100 0
|
||||
12-Mar-10 KFC Expenses:Food $20 $20
|
||||
Assets:Cash $-20 0
|
||||
12-Mar-10 KFC - Rebate Assets:Cash $5 $5
|
||||
Expenses:Food $-5 0
|
||||
12-Mar-10 KFC - Food & Reb.. Expenses:Food $20 $20
|
||||
Expenses:Food $-5 $15
|
||||
Assets:Cash $-15 0
|
||||
@end smallexample
|
||||
@noindent To this:
|
||||
@smallexample
|
||||
12-Mar-10 Employer Assets:Cash $100 0 $100
|
||||
In:Employer 0 $100 0
|
||||
12-Mar-10 KFC Expens:Food $20 0 $20
|
||||
Assets:Cash 0 $20 0
|
||||
12-Mar-10 KFC - Rebate Assets:Cash $5 0 $5
|
||||
Expens:Food 0 $5 0
|
||||
12-Mar-10 KFC - Food &.. Expens:Food $20 0 $20
|
||||
Expens:Food 0 $5 $15
|
||||
Assets:Cash 0 $15 0
|
||||
@end smallexample
|
||||
|
||||
@noindent Where the first column is debits, the second is credits, and the third is the
|
||||
running total. Only the running total may contain negative values.
|
||||
|
||||
For the balance report without @samp{--dc}:
|
||||
|
||||
@smallexample
|
||||
$70 Assets:Cash
|
||||
$30 Expenses:Food
|
||||
$-100 Income:Employer
|
||||
--------------------
|
||||
0
|
||||
@end smallexample
|
||||
|
||||
@noindent And with @samp{--dc} it becomes this:
|
||||
|
||||
@smallexample
|
||||
$105 $35 $70 Assets:Cash
|
||||
$40 $10 $30 Expenses:Food
|
||||
0 $100 $-100 Income:Employer
|
||||
--------------------------------------------
|
||||
$145 $145 0
|
||||
@end smallexample
|
||||
|
||||
|
||||
@option{--depth <INT>} limit the depth of the account tree. In a balance
|
||||
report, for example, a @code{--depth 2} statement will print balances
|
||||
only for account with two levels, i.e. @code{Expenses:Entertainment} but
|
||||
|
|
@ -5209,7 +5294,24 @@ balance against itself, and against any AAPL if @samp{--lots} is not
|
|||
specified. But if you do specify @samp{--lot-prices}, for example, then
|
||||
it will balance against that specific price for AAPL.
|
||||
|
||||
Normally when you use @samp{-X <commodity>} to request that amounts be reported in a
|
||||
specific commodity, Ledger uses these values:
|
||||
@itemize
|
||||
|
||||
@item Register Report
|
||||
For the register report, use the value of that commodity on the date of
|
||||
the posting being reported, with a <Revalued> posting added at the end of
|
||||
today's value is different from the value of the last posting.
|
||||
|
||||
@item Balance Report
|
||||
For the balance report, use the value of that commodity as of today.
|
||||
@end itemize
|
||||
|
||||
You can now specify -H to ask that all valuations for any amount be done
|
||||
relative to the date that amount was encountered.
|
||||
|
||||
You can also now use -X (and -H) in conjunction with -B and -I, to see
|
||||
valuation reports of just your basis costs or lot prices.
|
||||
@node Environment Variables, , Commodity Reporting, Detailed Options Description
|
||||
@subsection Environment variables
|
||||
|
||||
|
|
@ -5683,7 +5785,7 @@ Useful specifying a date in plain terms. For example, you could say
|
|||
@end table
|
||||
|
||||
|
||||
@node Format Strings, Journal File Format, Value Expressions, Top
|
||||
@node Format Strings, Ledger for Developers, Value Expressions, Top
|
||||
@chapter Format Strings
|
||||
|
||||
@menu
|
||||
|
|
@ -6103,9 +6205,240 @@ Additional date format parameters which can be used :
|
|||
@option{%F} yields @code{%Y-%m-%d 2010-02-10}
|
||||
|
||||
|
||||
@node Ledger for Developers, Extending with Python, Format Strings, Top
|
||||
@chapter Ledger for Developers
|
||||
|
||||
@node Journal File Format, Extending with Python, Format Strings, Top
|
||||
@chapter Journal File Format for Developers
|
||||
@menu
|
||||
* Internal Design::
|
||||
* Journal File Format::
|
||||
@end menu
|
||||
|
||||
@node Internal Design, Journal File Format, Ledger for Developers, Ledger for Developers
|
||||
@section Internal Design
|
||||
Ledger is developed as a tiered set of functionality, where lower tiers
|
||||
know nothing about the higher tiers. In fact, multiple libraries are
|
||||
built during the development the process, and link unit tests to these
|
||||
libraries, so that it is a link error for a lower tier to violate this
|
||||
modularity.
|
||||
|
||||
Those tiers are:
|
||||
|
||||
@itemize
|
||||
@item Utility code
|
||||
|
||||
There's lots of general utility in Ledger for doing time parsing, using
|
||||
Boost.Regex, error handling, etc. It's all done in a way that can be
|
||||
reused in other projects as needed.
|
||||
|
||||
@item Commoditized Amounts (amount_t, commodity_t and friends)
|
||||
|
||||
An numerical abstraction combining multi-precision rational numbers (via
|
||||
GMP) with commodities. These structures can be manipulated like regular
|
||||
numbers in either C++ or Python (as Amount objects).
|
||||
|
||||
@item Commodity Pool
|
||||
|
||||
Commodities are all owned by a commodity pool, so that future parsing of
|
||||
amounts can link to the same commodity and established a consistent price
|
||||
history and record of formatting details.
|
||||
|
||||
@item Balances
|
||||
|
||||
Adds the concept of multiple amounts with varying commodities. Supports
|
||||
simple arithmetic, and multiplication and division with non-commoditized
|
||||
values.
|
||||
|
||||
@item Price history
|
||||
|
||||
Amounts have prices, and these are kept in a data graph which the amount
|
||||
code itself is only dimly aware of (there's three points of access so an
|
||||
amount can query its revalued price on a given date).
|
||||
|
||||
@item Values
|
||||
|
||||
Often the higher layers in Ledger don't care if something is an amount or a
|
||||
balance, they just want to add stuff to it or print it. For this, I
|
||||
created a type-erasure class, value_t/Value, into which many things can be
|
||||
stuffed and then operated on. They can contain amounts, balances, dates,
|
||||
strings, etc. If you try to apply an operation between two values that
|
||||
makes no sense (like dividing an amount by a balance), an error occurs at
|
||||
runtime, rather than at compile-time (as would happen if you actually tried
|
||||
to divide an amount_t by a balance_t).
|
||||
|
||||
This is the core data type for the value expression language.
|
||||
|
||||
|
||||
|
||||
@item Value expressions
|
||||
|
||||
The next layer up adds functions and operators around the Value concept.
|
||||
This lets you apply transformations and tests to Values at runtime without
|
||||
having to bake it into C++. The set of functions available is defined by
|
||||
each object type in Ledger (posts, accounts, transactions, etc.), though
|
||||
the core engine knows nothing about these. At its base, it only knows how
|
||||
to apply operators to values, and how to pass them to and receive them from
|
||||
functions.
|
||||
|
||||
@item Query expressions
|
||||
|
||||
Expressions can be onerous to type at the command-line, so there's a
|
||||
shorthand for reporting called "query expressions". These add no
|
||||
functionality of there own, but are purely translated from the input string
|
||||
(cash) down to the corresponding value expression (account =~ /cash/).
|
||||
This is a convenience layer.
|
||||
|
||||
@item Format strings
|
||||
|
||||
Format strings let you interpolate value expressions into string, with the
|
||||
requirement that any interpolated value have a string representation.
|
||||
Really all this does is calculate the value expression in the current
|
||||
report context, call the resulting value's "to_string()" method, and stuffs
|
||||
the result into the output string. It also provides printf-like behavior,
|
||||
such as min/max width, right/left justification, etc.
|
||||
|
||||
@item Journal items
|
||||
|
||||
Next is a base type shared by anything that can appear in a journal: an
|
||||
item_t. It contains details common to all such parsed entities, like what
|
||||
file and line it was found on, etc.
|
||||
|
||||
@item Journal posts
|
||||
|
||||
The most numerous object found in a Journal, postings are a type of item
|
||||
that contain an account, an amount, a cost, and metadata. There are some
|
||||
other complications, like the account can be marked virtual, the amount
|
||||
could be an expression, etc.
|
||||
|
||||
@item Journal transactions
|
||||
|
||||
Postings are owned by transactions, always. This subclass of item_t knows
|
||||
about the date, the payee, etc. If a date or metadata tag is requested
|
||||
from a posting and it doesn't have that information, the transaction is
|
||||
queried to see if it can provide it.
|
||||
|
||||
@item Journal accounts
|
||||
|
||||
Postings are also shared by accounts, though the actual memory is managed
|
||||
by the transaction. Each account knows all the postings within it, but
|
||||
contains relatively little information of its own.
|
||||
|
||||
@item The Journal object
|
||||
|
||||
Finally, all transactions with their postings, and all accounts, are owned
|
||||
by a journal_t object. This is the go-to object for querying ad reporting
|
||||
on your data.
|
||||
|
||||
@item Textual journal parser
|
||||
|
||||
There is a textual parser, wholly contained in textual.cc, which knows how
|
||||
to parse text into journal objects, which then get "finalized" and added to
|
||||
the journal. Finalization is the step that enforces the double-entry
|
||||
guarantee.
|
||||
|
||||
@item Iterators
|
||||
|
||||
Every journal object is "iterable", and these iterators are defined in
|
||||
iterators.h and iterators.cc. This iteration logic is kept out of the
|
||||
basic journal objects themselves for the sake of modularity.
|
||||
|
||||
@item Comparators
|
||||
|
||||
Another abstraction isolated to its own layer, this class encapsulating the
|
||||
comparison of journal objects, based on whatever value expression the user
|
||||
passed to --sort.
|
||||
|
||||
@item Temporaries
|
||||
|
||||
Many reports bring pseudo-journal objects into existence, like postings
|
||||
which report totals in a "<Total>" account. These objects are created and
|
||||
managed by a temporaries_t object, which gets used in many places by the
|
||||
reporting filters.
|
||||
|
||||
@item Option handling
|
||||
|
||||
There is an option handling subsystem used by many of the layers further
|
||||
down. It makes it relatively easy for me to add new options, and to have
|
||||
those option settings immediately accessible to value expressions.
|
||||
|
||||
@item Session objects
|
||||
|
||||
Every journal object is owned by a session, with the session providing
|
||||
support for that object. In GUI terms, this is the Controller object for
|
||||
the journal Data object, where every document window would be a separate
|
||||
session. They are all owned by the global scope.
|
||||
|
||||
@item Report objects
|
||||
|
||||
Every time you create report output, a report object is created to
|
||||
determine what you want to see. In the Ledger REPL, a new report object is
|
||||
created every time a command is executed. In CLI mode, only one report
|
||||
object ever comes into being, as Ledger immediately exits after displaying
|
||||
the results.
|
||||
|
||||
@item Reporting filters
|
||||
|
||||
The way Ledger generates data is this: it asks the session for the current
|
||||
journal, and then creates an iterator applied to that journal. The kind of
|
||||
iterator depends on the type of report.
|
||||
|
||||
This iterator is then walked, and every object yielded from the iterator is
|
||||
passed to an "item handler", whose type is directly related to the type of
|
||||
the iterator.
|
||||
|
||||
There are many, many item handlers, which can be chained together. Each
|
||||
one receives an item (post, account, xact, etc.), performs some action on
|
||||
it, and then passes it down to the next handler in the chain. There are
|
||||
filters which compute the running totals; that queue and sort all the input
|
||||
items before playing them back out in a new order; that filter out items
|
||||
which fail to match a predicate, etc. Almost every reporting feature in
|
||||
Ledger is related to one or more filters. Looking at filters.h, I see over
|
||||
25 of them defined currently.
|
||||
|
||||
@item The filter chain
|
||||
|
||||
How filters get wired up, and in what order, is a complex process based on
|
||||
all the various options specified by the user. This is the job of the
|
||||
chain logic, found entirely in chain.cc. It took a really long time to get
|
||||
this logic exactly write, which is why I haven't exposed this layer to the
|
||||
Python bridge yet.
|
||||
|
||||
@item Output modules
|
||||
|
||||
Although filters are great and all, in the end you want to see stuff. This
|
||||
is the job of special "leaf" filters call output modules. They are
|
||||
implemented just like a regular filter, but they don't have a "next" filter
|
||||
to pass the time on down to. Instead, they are the end of the line and
|
||||
must do something with the item that results in the user seeing something
|
||||
on their screen or in a file.
|
||||
|
||||
@item Select queries
|
||||
|
||||
Select queries know a lot about everything, even though they implement
|
||||
their logic by implementing the user's query in terms of all the other
|
||||
features thus presented. Select queries have no functionality of their
|
||||
own, they are simple a shorthand to provide access to much of Ledger's
|
||||
functionality via a cleaner, more consistent syntax.
|
||||
|
||||
@item The Global Scope
|
||||
|
||||
There is a master object which owns every other objects, and this is
|
||||
Ledger's global scope. It creates the other objects, provides REPL
|
||||
behavior for the command-line utility, etc. In GUI terms, this is the
|
||||
Application object.
|
||||
|
||||
@item The Main Driver
|
||||
|
||||
This creates the global scope object, performs error reporting, and handles
|
||||
command-line options which must precede even the creation of the global
|
||||
scope, such as --debug.
|
||||
@end itemize
|
||||
|
||||
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,
|
||||
which options the report and session scopes define, etc.
|
||||
|
||||
@node Journal File Format, , Internal Design, Ledger for Developers
|
||||
@section Journal File Format for Developers
|
||||
|
||||
This chapter offers a complete description of the journal data format,
|
||||
suitable for implementers in other languages to follow. For users,
|
||||
|
|
@ -6155,26 +6488,20 @@ amount of the first posting is typically positive. Consider:
|
|||
@menu
|
||||
* Comments and meta-data::
|
||||
* Specifying Amounts::
|
||||
* Posting costs::
|
||||
* Primary commodities::
|
||||
@end menu
|
||||
|
||||
@node Comments and meta-data, Specifying Amounts, Journal File Format, Journal File Format
|
||||
@section Comments and meta-data
|
||||
@menu
|
||||
* Comments::
|
||||
* Meta-data::
|
||||
@end menu
|
||||
@subsection Comments and meta-data
|
||||
|
||||
@node Comments, Meta-data, Comments and meta-data, Comments and meta-data
|
||||
@subsection Comments
|
||||
Comments are generally started using a ';'. However, in order to
|
||||
increase compatibility with other text manipulation programs and methods
|
||||
three additional comment characters are valid if used at the beginning
|
||||
of a line: @code{#}, @code{|}, and @code{*}.
|
||||
@node Meta-data, , Comments, Comments and meta-data
|
||||
@subsection Matador
|
||||
|
||||
@node Specifying Amounts, , Comments and meta-data, Journal File Format
|
||||
@section Specifying Amounts
|
||||
@node Specifying Amounts, Posting costs, Comments and meta-data, Journal File Format
|
||||
@subsection Specifying Amounts
|
||||
@cindex amounts
|
||||
The heart of a journal is the amounts it records, and this fact is
|
||||
reflected in the diversity of amount expressions allowed. All of them
|
||||
|
|
@ -6191,7 +6518,7 @@ spaces between the end of the post and the beginning of the amount
|
|||
@end menu
|
||||
|
||||
@node Integer Amounts, Commoditized Amounts, Specifying Amounts, Specifying Amounts
|
||||
@subsection Integer Amounts
|
||||
@subsubsection Integer Amounts
|
||||
|
||||
In the simplest form, bare decimal numbers are accepted:
|
||||
|
||||
|
|
@ -6245,7 +6572,7 @@ always look to their commodity to know what precision they should
|
|||
round to, and so use @dfn{commodity precision}.
|
||||
|
||||
@node Commoditized Amounts, , Integer Amounts, Specifying Amounts
|
||||
@subsection Commoditized Amounts
|
||||
@subsubsection Commoditized Amounts
|
||||
|
||||
A @dfn{commoditized amount} is an integer amount which has an
|
||||
associated commodity. This commodity can appear before or after the
|
||||
|
|
@ -6292,7 +6619,8 @@ does not change how other amounts in that commodity will be displayed.
|
|||
|
||||
An example of this is found in cost expressions, covered next.
|
||||
|
||||
@section Posting costs
|
||||
@node Posting costs, Primary commodities, Specifying Amounts, Journal File Format
|
||||
@subsection Posting costs
|
||||
|
||||
You have seen how to specify either a commoditized or an integer
|
||||
amount for a posting. But what if the amount you paid for something
|
||||
|
|
@ -6342,6 +6670,7 @@ postings are involved:
|
|||
Here the implied cost is @samp{$57.00}, which is entered into the null
|
||||
posting automatically so that the transaction balances.
|
||||
|
||||
@node Primary commodities, , Posting costs, Journal File Format
|
||||
@subsection Primary commodities
|
||||
|
||||
In every transaction involving more than one commodity, there is
|
||||
|
|
@ -6374,8 +6703,161 @@ considered a primary. In fact, when Ledger goes about ensures that
|
|||
all transactions balance to zero, it only ever asks this of primary
|
||||
commodities.
|
||||
|
||||
@node Extending with Python, Major Changes from version 2.6, Journal File Format, Top
|
||||
@node Extending with Python, Major Changes from version 2.6, Ledger for Developers, 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
|
||||
`@samp{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 Major Changes from version 2.6, Example Data File, Extending with Python, Top
|
||||
@chapter Major Changes from version 2.6
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue