On Wed, Jun 4, 2014 at 4:23 AM, Jostein Berntsen <[email protected]> wrote:
> > On Wednesday, June 4, 2014 7:32:22 AM UTC+2, Martin Blais wrote: > >> On Mon, Jun 2, 2014 at 8:55 PM, Martin Blais <[email protected]> wrote: >> >>> Why don't you build a tool for printing out the result of these >>> rule-based modifications? Do you think that would be useful? Is it >>> possible? I see a lot of questions like: "Why doesn't my rule such and such >>> work? I see unexpected results in the register." If Ledger had a command to >>> "expand everything, and print the expanded results," all of these questions >>> would be easily answered by inspecting what it's doing, no? Is that easy to >>> implement? >>> >>> Just an idea. I'm building something exactly like that for Beancount, to >>> help in debugging plugins, which are essentially functions that transform a >>> list of entries in arbitrary ways, into a new, modified list of entries. >>> One should be able to diff the files and round-trip between data-structure >>> to text and back. >>> >> >> Actually, I just completed support for round-trips tonight (I had been >> writing comparison code lately in order to make it easier to write tests by >> writing a list of expected transactions in the input syntax itself, so it >> was a-propos). This means that Beancount can now read a complete ledger >> file, spit it back out in text, and re-reading that output generates the >> same data structures in memory. Writing that re-read structure out again to >> a second file also shows no file diff against the first output to text, >> it's identical. I tested this on my gigantic personal ledger of 8 years, >> and it passes clean. >> >> I'll add a new report type called "print" shortly, which will just spit >> out the data structure it read in memory back to text, after running all >> the transformations (e.g. automatically setting the amounts on postings, >> processing the tag directives, adding price entries for postings at a >> price, and whatever else the plugins do). This should be a nice debugging >> tool in the future, as it reflects what it does, e.g., what was >> automatically generated by the syntax shortcuts. >> >> > This sounds like a great feature. Can you give an example on how it works? > Sure. I attached an example input file (input.beancount). Run it like this: bean-query input.beancount print This says: "parse input.beancount and produce the 'print' report". You should see output like print.beancount (also in attachment). I'm still improving it; for transactions with non-trivial balances, I want to spit out comments next to each posting that explicitly state which amounts are used in the balance calculation. Also, price entries that are currently implicitly derived from positions with prices (e.g., @ ...) will be generated instead as explicit price entries being inserted in the flow of entries, by a stage that runs after parsing. I manually edited the output to give you an idea of what that will look like (attachment: print-future.beancount, diff it with print.beancount). Much of the Beancount operations can be expressed as transformations that accept 3 arguments: (a list of entries/directives records, a list of errors, and a map of options), and output the same tuple, but with entries and errors modified (you can generates new entries or modify existing ones). It's a functional approach, using mostly immutable data, which makes it very easy to understand. As I'm teasing more and more of the complexity out of it, I'm discovering that I can even do much of the processing using these stages: https://hg.furius.ca/public/beancount/file/ece44b933ec8/src/python/beancount/loader.py#l62 I'm basically 1) parsing, 2) running transformations, and 3) checking some invariants. Reports are generated from the resulting list of directives. Filtering (e.g. year=2014) is simply another stage that lets through a subset of the entries - all the reports work on a filtered list of entries too. User "plugins" are simply functions that accept the three inputs and output a modified version of those (you can do anything you want, as long as some basic invariants are maintained). So basically, the "print" report just spits out the list of entries after the transformations and validation. If you're working on some idea for a transformation, say, adding support for forecasting entries: https://hg.furius.ca/public/beancount/file/ece44b933ec8/src/python/beancount/plugins/forecast.py#l32 you can now write a simple input file and use "bean-query input.beancount print" to see what your transformation actually does, great for debugging. Comparison routines that compare two lists of entries are available from the testing support libraries, and because of the round-trip capability, you can now just inspect the output, and if it's right, cut-n-paste the input and output text into a unit test to specify a list of expected entries from a transformation (!). Makes writing unit tests a breeze (which was my goal when I started down that path recently). I did not set out for the printer to have this round-trip capability... it was just teased out as a result of how I designed the data structures and processing: functional operations with no state that accept and output immutable data structures with everything on them public (okay okay, so Python doesn't provide a language-level guarantee of immutability, but in practice I use these tuples as such, so using a few conventions they're practically read-only, I get all the benefits of it, it doesn't matter). This was an unexpected development, which is why I'm excited with it. -- --- You received this message because you are subscribed to the Google Groups "Ledger" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
input.beancount
Description: Binary data
print-future.beancount
Description: Binary data
print.beancount
Description: Binary data
