216 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			216 lines
		
	
	
		
			9.1 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| # Code
 | |
| 
 | |
| <div class=pagetoc>
 | |
| <!-- toc -->
 | |
| </div>
 | |
| 
 | |
| hledger is a suite of applications, tools and libraries.
 | |
| The main hledger code repository is [github.com/simonmichael/hledger](https://github.com/simonmichael/hledger)
 | |
| (shortcut url `code.hledger.org`).
 | |
| There are also various hledger addons maintained as separate projects with their own repos.
 | |
| 
 | |
| ## hledger packages
 | |
| 
 | |
| Within the main repo, there are a number of separate cabal packages,
 | |
| making it easier to pick and choose parts of hledger to install or to package.
 | |
| They are:
 | |
| 
 | |
| ### hledger-lib
 | |
| 
 | |
| [package](https://hackage.haskell.org/package/hledger-lib),
 | |
| [code](https://github.com/simonmichael/hledger/tree/master/hledger-lib)
 | |
| 
 | |
| Core data models, parsing, standard reports, and utilities.
 | |
| Most data types are defined in [Hledger.Data.Types](https://hackage.haskell.org/package/hledger-lib/docs/Hledger-Data-Types.html),
 | |
| while functions that operate on them are defined in Hledger.Data.TYPENAME.
 | |
| Under [Hledger.Read](https://github.com/simonmichael/hledger/tree/master/hledger-lib/Hledger/Read.hs)
 | |
| are parsers for the supported input formats.
 | |
| Data files are parsed into a
 | |
| [Journal](https://hackage.haskell.org/package/hledger-lib/docs/Hledger-Data-Types.html#t:Journal),
 | |
| which contains a list of
 | |
| [Transactions](https://hackage.haskell.org/package/hledger-lib/docs/Hledger-Data-Types.html#t:Transaction),
 | |
| each containing multiple
 | |
| [Postings](https://hackage.haskell.org/package/hledger-lib/docs/Hledger-Data-Types.html#t:Posting)
 | |
| of some
 | |
| [MixedAmount](https://hackage.haskell.org/package/hledger-lib/docs/Hledger-Data-Types.html#t:MixedAmount)
 | |
| (multiple
 | |
| single-[CommoditySymbol](https://hackage.haskell.org/package/hledger-lib/docs/Hledger-Data-Types.html#t:CommoditySymbol)
 | |
| [Amounts](https://hackage.haskell.org/package/hledger-lib/docs/Hledger-Data-Types.html#t:Amount))
 | |
| to some
 | |
| [AccountName](https://hackage.haskell.org/package/hledger-lib/docs/Hledger-Data-Types.html#t:AccountName).
 | |
| When needed, the Journal is further processed to derive a
 | |
| [Ledger](https://hackage.haskell.org/package/hledger-lib/docs/Hledger-Data-Types.html#t:Ledger),
 | |
| which contains summed 
 | |
| [Accounts](https://hackage.haskell.org/package/hledger-lib/docs/Hledger-Data-Types.html#t:Account).
 | |
| In [Hledger.Reports](https://hackage.haskell.org/package/hledger-lib/docs/Hledger-Reports.html)
 | |
| there are standard reports, which extract useful data from the Journal or Ledger.
 | |
| 
 | |
| Here's a diagram of the main data model:
 | |
| 
 | |
| <a href="https://hledger.org/images/data-model.png" class="highslide" onclick="return hs.expand(this)">
 | |
| <img src="https://hledger.org/images/data-model.png" alt="diagram" title="main data types" style="max-width:100%;">
 | |
| </a>
 | |
| 
 | |
| <!-- generated by plantuml from:
 | |
| <uml>
 | |
| hide empty members
 | |
| hide circle
 | |
| skinparam packageStyle Rect
 | |
| 
 | |
| Ledger *-- Journal
 | |
| Ledger *-- "*" Account
 | |
| note top of Ledger: A Journal and all its accounts with their balances.\nUsed for balance report
 | |
| note top of Journal: A journal file and parsed transactions & directives.\nUsed for print & register reports
 | |
| note bottom of Account: An account's name, balance (inclusive &\nexclusive), parent and child accounts
 | |
| Account o-- "*" Account :subaccounts, parent
 | |
| Journal o-- File
 | |
| File o-- "*" File :include
 | |
| Journal *-- "*" MarketPrice
 | |
| Journal *-- "*" Transaction
 | |
| MarketPrice -- Date
 | |
| MarketPrice -- Amount
 | |
| Transaction -- Date
 | |
| Transaction *-- "*" Posting
 | |
| Transaction o-- "*" Tag
 | |
| Posting o- "*" Tag
 | |
| Posting -- "0..1" Date
 | |
| Account -- AccountName
 | |
| Posting -- AccountName
 | |
| Account -- "2" MixedAmount
 | |
| Posting -- MixedAmount
 | |
| MixedAmount *-- "*" Amount
 | |
| Amount -- CommoditySymbol
 | |
| Amount -- Quantity
 | |
| Amount -- AmountPrice
 | |
| Amount -- AmountStyle
 | |
| </uml>
 | |
| -->
 | |
| 
 | |
| ### hledger
 | |
| 
 | |
| [package](https://hackage.haskell.org/package/hledger),
 | |
| [code](https://github.com/simonmichael/hledger/tree/master/hledger),
 | |
| [manual](https://hledger.org/hledger.html)
 | |
| 
 | |
| hledger's command line interface, and command line options and utilities for other hledger tools.
 | |
| 
 | |
| Try tracing the execution of a hledger command:
 | |
| 
 | |
| 1. [Hledger.Cli.Main:main](https://github.com/simonmichael/hledger/blob/master/hledger/Hledger/Cli/Main.hs#L302)
 | |
| parses the command line to select a command, then
 | |
| 2. gives it to
 | |
| [Hledger.Cli.Utils:withJournalDo](https://github.com/simonmichael/hledger/blob/master/hledger/Hledger/Cli/Utils.hs#L73),
 | |
| which runs it after doing all the initial parsing.
 | |
| 3. Parsing code is under
 | |
| [hledger-lib:Hledger.Read](https://github.com/simonmichael/hledger/tree/master/hledger-lib/Hledger/Read.hs),
 | |
| eg [Hledger.Read.JournalReader](https://github.com/simonmichael/hledger/tree/master/hledger-lib/Hledger/Read/JournalReader.hs).
 | |
| 4. Commands extract useful information from the parsed data model using
 | |
| [hledger-lib:Hledger.Reports](https://github.com/simonmichael/hledger/tree/master/hledger-lib/Hledger/Reports),
 | |
| and
 | |
| 5. render in plain text for console output (or another output format, like CSV).
 | |
| 6. Everything uses the data types and utilities from
 | |
| [hledger-lib:Hledger.Data](https://github.com/simonmichael/hledger/tree/master/hledger-lib/Hledger/Data)
 | |
| and [hledger-lib:Hledger.Utils](https://github.com/simonmichael/hledger/blob/master/hledger-lib/Hledger/Utils.hs).
 | |
| 
 | |
| ### hledger-ui
 | |
| 
 | |
| [package](https://hackage.haskell.org/package/hledger-ui),
 | |
| [code](https://github.com/simonmichael/hledger/tree/master/hledger-ui),
 | |
| [manual](https://hledger.org/hledger-ui.html)
 | |
| 
 | |
| A terminal interface.
 | |
| 
 | |
| ### hledger-web
 | |
| 
 | |
| [package](https://hackage.haskell.org/package/hledger-web),
 | |
| [code](https://github.com/simonmichael/hledger/tree/master/hledger-web),
 | |
| [manual](https://hledger.org/hledger-web.html)
 | |
| 
 | |
| A web interface.
 | |
| hledger-web starts a web server built with the yesod framework,
 | |
| and (by default) opens a web browser view on it.
 | |
| It reads the journal file(s) at startup and again whenever they change.
 | |
| It can also write (append) new transactions to the journal file.
 | |
| 
 | |
| There are two main views, which can be filtered with
 | |
| [queries](https://hledger.org/hledger.html#queries):
 | |
| 
 | |
| - [/journal](https://demo.hledger.org/journal), showing general journal entries (like `hledger print`)
 | |
| 
 | |
| - [/register](https://demo.hledger.org/register?q=inacct:Expenses:Food),
 | |
|   showing transactions affecting an account (slightly different from
 | |
|   hledger's [register](https://hledger.org/hledger.html#register) command, which shows postings).
 | |
| 
 | |
| There is also:
 | |
| 
 | |
| - a sidebar (toggled by pressing `s`) showing the chart of accounts (like `hledger balance`)
 | |
| - an [add form](https://demo.hledger.org/journal?add=1) for adding new transactions (press `a`)
 | |
| - a help dialog showing quick help and keybindings (press `h` or click ?)
 | |
| 
 | |
| Most of the action is in
 | |
| 
 | |
| - [config/routes](https://github.com/simonmichael/hledger/tree/master/hledger-web/config/routes)
 | |
| - [templates/default-layout-wrapper.hamlet](https://github.com/simonmichael/hledger/tree/master/hledger-web/templates/default-layout-wrapper.hamlet)
 | |
| - [Foundation](https://github.com/simonmichael/hledger/tree/master/hledger-web/Foundation.hs)
 | |
| - [Handler.*](https://github.com/simonmichael/hledger/tree/master/hledger-web/Handler)
 | |
| - [static/hledger.js](https://github.com/simonmichael/hledger/tree/master/hledger-web/static/hledger.js)
 | |
| - [static/hledger.css](https://github.com/simonmichael/hledger/tree/master/hledger-web/static/hledger.css)
 | |
| 
 | |
| Handler module and function names end with R, like the yesod-generated route type they deal with.
 | |
| 
 | |
| Dynamically generated page content is mostly inline hamlet.
 | |
| Lucius/Julius files and widgets generally are not used, except for the default layout.
 | |
| 
 | |
| Here are some ways to run it during development:
 | |
| 
 | |
| - `yesod devel`: runs in developer mode, rebuilds automatically when config, template, static or haskell files change
 | |
| (but only files in the hledger-web package):
 | |
| ```shell
 | |
| $ (cd hledger-web; yesod devel)
 | |
| ```
 | |
| 
 | |
| - [yesod-fast-devel](https://hackage.haskell.org/package/yesod-fast-devel)
 | |
|   may be a good alternative, also reloads the browser page
 | |
| 
 | |
| - `stack ghci`: runs the server in developer mode from GHCI.
 | |
| Changes to static files like hledger.js will be visible on page reload;
 | |
| to see other changes, restart it as shown.
 | |
| ```shell
 | |
| $ (cd hledger-web; stack ghci hledger-web)
 | |
| hledger-web> :main --serve   # restart: ctrl-c, :r, enter, ctrl-p, ctrl-p, enter
 | |
| ```
 | |
| 
 | |
| - `make ghci-web`: runs the server in developer mode from GHCI, also
 | |
| interprets the hledger-lib and hledger packages so that :reload picks
 | |
| up changes in those packages too:
 | |
| ```shell
 | |
| $ make ghci-web
 | |
| ghci> :main --serve
 | |
| ```
 | |
| (This rule also creates symbolic links to hledger-web's `config`, `messages`, `static` and `templates`
 | |
| directories, needed in developer mode, so it can run from the top directory. This may not work on Windows.)
 | |
| 
 | |
| ## Quality
 | |
| 
 | |
| Relevant tools include:
 | |
| 
 | |
| - unit tests (HUnit, make unittest)
 | |
| - functional tests (shelltestrunner, make functest)
 | |
| - performance tests (simplebench, make bench)
 | |
| - documentation tests (make haddocktest + manual)
 | |
| - ui tests (manual)
 | |
| - installation tests (manual)
 | |
| - code reviews
 | |
| 
 | |
| ## Code review
 | |
| 
 | |
| - Code review party 2014/7/21-25:
 | |
|   [discussion](https://thread.gmane.org/gmane.comp.finance.ledger.hledger/1070)<!-- missing ,
 | |
|   [log](https://hledger.org/static/irc-20140725-code-review.html) -->
 | |
| - Dev sprint/party 2015/10/10:
 | |
|   [discussion](https://thread.gmane.org/gmane.comp.finance.ledger.hledger/1254)<!-- ircbrowse down ,
 | |
|   [pre-chat](https://ircbrowse.net/day/hledger/2015/10/10),
 | |
|   [log](https://ircbrowse.net/day/hledger/2015/10/11) -->
 | |
| 
 | |
| 
 |