[EMAIL PROTECTED] writes:
 > 
 > Robert Merkel <[EMAIL PROTECTED]> wrote:
 > >I've mostly completed the data-collection part of the transaction
 > >reports code, and am now figuring out how to implement the formatted
 > >data output. 
 > >
 > >I'm going over your mail of a few weeks ago, attempting to figure
 > >out how to actually implement this code.
 > 
 > Preface this with one comment: the word "thunk" is not necessarily
 > well-used throughout this posting.  I would speculate that the
 > "financial reporting language" should be gone over once or twice
 > more, fairly carefully, and that which falls out of it as *useful*
 > should be rather more carefully specified so that we have, rather
 > than some "ramblings," an actual design that can evolve without
 > necessarily breaking.
 > 
 > your suggestion of adding a "report-date" function is a good example
 > of the sort of thing that should be added in to the design before
 > things get out of hand.  
 > - Page numbers would be another sensible addition; 

Yes.
 > - Checksums might be another; 

Could you explain what you mean here?
 > - Running balances still another (e.g. - each line or each header/footer
 >   contains a running total);

Definitely.
 > - Keeping room for a data-only output form for archival shouldn't
 >   be too problematic

Yep.
 > - Are any of the ideas *violently* incompatible with the notion of
 >   generating TeX (or LaTeX) and thereby having typeset accounts?

I've been thinking about this from a LaTeX perspective, and I'm fairly
confident that the kind of thing we're talking about could be
implemented by using the "tabularx" package.

 > - Is there *violent* inherent incompatibility with the Postscript display
 >   model or with GNOME Print/GNOME Canvas?
I'm not an expert on PostScript, but as I understand it PostScript 
is so flexible that it should be able to cope with anything we can
fling at it.

GNOME print is designed to offer line-by-line layout, so at this stage
I don't see that we're doing anything that will make our lives difficult.
 > - Graphical images, anyone?
 > 

I could well see a need for this, but I'm not keen to include it in
the initial design (for the purposes of having SOMETHING running 
in the not-too-distant future).  So, yes, I'd make provision for
inserting graphics.

Another one that has occurred to me is the need to have horizontal
lines below certain columns of certain rows of text.  Indeed, 
it would be nice to be able to specify a variety of types of line -
solid, dashed, double etc.

 > Not all may need to be "formally specified" from the beginning,
 > but if there are such things that it might make sense to add in
 > later, it's a good idea to think ahead so that the design doesn't
 > make later extensions impossible without making violent changes to
 > the design.
 > 
Agreed.
 > In effect, any "violent" changes should take place now, when there's
 > not functionality to throw away.
 > 
 > For instance, it would be seriously annoying to build up some
 > functionality, and shortly thereafter determine that since we left *no*
 > room for the insertion of graphical objects, it is necessary to create
 > a new reporting scheme from scratch because we forgot that some folks
 > might want to have graphical images embedded in the headers of reports...
 > I may be personally dubious of the merits of such, but it'll doubtless
 > be incredibly important to someone.
 > 
 > e.g. - While a graphical G/L may be of negative value [consider that
 > this *forces* you to print in graphical mode, and there's considerable
 > CPU cost to rendering a 50 page report when graphical images get added
 > in...] someone might decide use the reporting system to create invoices,
 > and downright *NEED* pretty graphics.
 > 
 > I guess what I'm suggesting is that at this point, code should be
 > written to establish the feasibility of techniques, not for full use.
 > There needs to be a bit more design effort before trying to go all
 > the way with the code.
 > 
Agreed.  Once we have agreed on a preliminary design, I'll try and
design and then implement a HTML renderer for the parts needed 
for the existing reports.

That way, hopefully, most of the remaining warts  can be spotted
before we get too much further.

<snip>

 > >2) What should these functions return?  At this stage, they have to 
 > >   return some kind of data structure which would probably be a vector
 > >   containing 
 > >   i.   the type (ie string, value, total, or date)
 > >   ii.  the "value"
 > >   iii. the linkname
 > >   iv.  the column
 > >   v.   the style
 > >
 > >   Do I understand this correctly?
 > 
 > Nope.  They return nothing; they function as side-effects.
 > 
 > They're more analagous to a file port, which consumes its input,
 > sending the input to the appropriate place.
 > 

How do they know where to send stuff - and what to send?

Could you outline an implementation of a fairly simple case to show
me what's going on here?


 > For report-value, the "collector thunk" would be a function that grabs
 > the value and adds it in to a total.
 > 
 > For report-total, it passes in the "input-collector-thunk," and gets,
 > from that, the total being reported, and then passes on that total to
 > the output-collector-thunk.
 > 
 > (define (create-non-spreadsheet-total-thunk)
 >    (let*  
 >        ((value 0)  ;;; This is the total that things add to
 >         (adder-function 
 >              (lambda (x) (set! value (+ value x))))
 >         (report-value (lambda () value))
 >      (dispatcher (lambda (method newval)
 >                    (cond
 >                      ((eq? method 'add)
 >                       (adder-function newval))
 >                      ((eq? method 'report)
 >                       (report-value))
 >                      (else
 >                       'error)))))
 >      dispatcher))
 > 
 > This thus defines:
 > a) A slot for a value, which starts at 0,
 > b) An "adder" function, which adds the value "newval" in, and
 > c) A "report-value" function, which returns the total.
 > 
 > The "thunk definer" gets used thus:
 > > (define total-thunk (create-non-spreadsheet-total-thunk))
 > > (total-thunk 'add 25)
 > > (total-thunk 'add 25)
 > > (total-thunk 'add -15)
 > > (total-thunk 'add 2.5)
 > > (total-thunk 'report #f)
 > 37.5 
 > 
 > This is the "simple" case, where all we're doing is to add values in
 > to a total.
 > 
 > With the spreadsheet format, it wouldn't be values that get passed in,
 > but rather cell identifiers, and (total-thunk 'report #f) would pass
 > back the *formula.*
 > 
 > Something like:
 > (define (create-spreadsheet-total-thunk)
 >    (let*  
 >        ((ilist '())  
 >         (adder-function 
 >              (lambda (x) (set! ilist (cons x ilist))))
 >         (report-value (lambda () ilist))
 >      (dispatcher (lambda (method newval)
 >                    (cond
 >                      ((eq? method 'add)
 >                       (adder-function newval))
 >                      ((eq? method 'report)
 >                       (report-value))
 >                      (else
 >                       'error)))))
 >      dispatcher))
 > 
 > Which is used thus:
 > > (define ssthunk (create-spreadsheet-total-thunk))
 > > (ssthunk 'add "C1")
 > > (ssthunk 'add "C2")
 > > (ssthunk 'add "C3")
 > > (ssthunk 'add "C4")
 > > (ssthunk 'report #f)
 > ("C4" "C3" "C2" "C1")
 > 
OK, this is neater than what I suggested, but same idea applies - we
have a pair of functions, but invoked like method calls on the one
object.

 > The last step returns a list of cells in this case, just to keep
 > exposition simple; but there might be some more useful behaviour, like
 > actually assembling this into:
 > "<formula>=C1+C2+C3+C4</formula>"
 > or, in a more intelligent implementation, figuring out that these run
 > together, and turning this into:
 > "<formula>=SUM(C1:C4)</formula>"
 > 
 > An *really* cool thing to do would be some equivalent to Lotus 123
 > "named regions," and generate:
 > <namedregion>
 >   <name>REGION4</name>
 >   <celllist>
 >    <cell>C1</cell>
 >    <cell>C2</cell>
 >    <cell>C3</cell>
 >    <cell>C4</cell>
 >   </celllist>
 > </namedregion>
 > as well as
 > <formula>=SUM(REGION4)</formula>
 > 
 > although that may be taking things a step further than we need go just
 > now...  I ought to fiddle with Gnumeric to see how it manages this
 > sort of thing...
 > 
Agreed, this sort of thing will be *very* cool.  While I'm not
interested in implementing it right now, I certainly want to be able
to do it in the future.

However, this means that the type of collector-thunk is dependent 
on the output format of the report.  Therefore, you would need
to pass a "collector-thunk generator" as an argument to the report
generation code so that a HTML collector-thunk was generated when 
a HTML report was needed, and a Gnumeric formula collector-thunk
was generated when a Gnumeric-exported report was wanted etc.
This would also mean that the report would essentially have to be
rerun when a different output format was generated (instead of 
being able to reprocess the generated report to a different 
final output format).  This is not ideal.

Can you suggest a way around this?


 > >;;; You pass a list of the thunks established above into (report-line)
 > >;;; which combines them into a single line.
 > >;;; (define (report-line report-port . list-of-thunks))
 > >;;;
 > >
 > >1)report-line actually performs the formatting (then sends it to the
 > >appropriate physical port), doesn't it?  
 > 
 > Close.  I'd have report-line forward responsibility to dispatch
 > functions, suggested below...
 > 
 > >Would it make sense here for the report-port data structure to
 > >contain a renderer function that does the transformation of the thunk
 > >list into a string that can then be fed to the physical report port?
 > 
 > report-line should be implemented as a dispatcher that forwards the
 > output to one of:
 >  - report-line-text
 >  - report-line-html
 >  - report-line-gnumeric
 > as needed.
 > 
 > Those dispatch functions would forward the output to the "physical
 > port."
 > 
 > Thus, report-line whould be defined thus:
 > (define (report-line report-port . list-of-thunks)
 >   (cond
 >    ((is-report-port-html? report-port)
 >     (report-line-html report-port list-of-thunks))
 >    ((is-report-port-text? report-port)
 >     (report-line-text report-port list-of-thunks))
 >    ((is-report-port-gnumeric? report-port)
 >     (report-line-gnumeric report-port list-of-thunks))
 >    (else
 >     'error)))

I was going to try to be a little cuter to allow new report output
formats to be registered dynamically.  Do you agree that this would
be worthwhile?

<large snip>

 > >;;; style:
 > >(define style-structure 
 > >  (make-record-type 
 > >   "style"
 > >   '(alignment fontinfo color)))
 > >
 > >I still have concerns that allowing ourselves more than a fixed set
 > >of styles that we can implement in all output forms is just going
 > >to make life too hard.
 > >
 > >Can you suggest how your method might be implemented in a portable fashion? 
 > 
 > If we go with a pure "lowest common denominator," then we're left
 > looking at raw text as the output form.  And that is *NOT* going to
 > fly.
 > 
 > - On a monochrome monitor, or a laserprinter, there won't be color.
 >   But spreadsheets can cope with it nicely.
 > 
 > - Any paper-oriented output form will forcibly need to have
 >   headers/footers, and will worry about "pages."  HTML and spreadsheets
 >   won't.
 > 
 > - Devices will vary as to what fonts they support.
 > 
 > If we have an acceptable way of degrading output gracefully on
 > less-than-expressive media, that allows us to have the styles be
 > pretty smart.

My concern is that font information varies greatly according to output
format, and coming up with an acceptable translator for 
a highly specific style specification is a quite complex task.  Also,
available fonts vary *extremely* widely between output methods.

In addition, I'm not convinced the output formatting of a style 
should necessarily be embedded in the report.  Consider where
all reports need to be in a certain "corporate style".  If we define
what a style should look like in every document it's going to be a
nightmare to maintain consistency.

Again, what I'd propose is a limited set of styles that are guaranteed
to be supported by *all* output methods.  The fonts, colours, etc used
for these fixed styles for a specific output method would presumably
be both globally and locally configurable.  If a specific report
requires a custom style, they should specify output-method specific
font information for any output methods that they intend to support,
and should specify another style to default to if an unsupported
output method is attempted - kind of like an object hierachy, in fact.

something like

;; (define custom-style default-style render-info)

Where default-style is the name of an already-defined style, 
and render info is something like:

( '(html .(*some html rendering info*)) '(text . (*text rendering
info*)))


Whilst this method places a greater burden on people who write reports
(if they use custom styles) and output formatters (as they have to
provide font information for the default styles), I would be
comfortable implementing such a method.

However, if you could broadly outline an implementation for your
method (or point to an example of a similar method that's been 
implemented in another context) I would be happy to go with it.
While I'm not very familiar with CSS, it at least has the comfort of a
common font model, something we are not blessed with in this case.

Anyway, I think we are getting closer.  If you could clear up
my confusion and examine the remaining concerns, it won't be 
too long before we have a good, implementable, design.

-- 
---------------------------------------------------------------------------
Robert Merkel                                               [EMAIL PROTECTED]

Humanity has advanced, when it has advanced, not because it has been sober, 
responsible, and cautious, but because it has been playful, rebellious, and 
immature.
                -- Tom Robbins
---------------------------------------------------------------------------

--
Gnucash Developer's List 
To unsubscribe send empty email to: [EMAIL PROTECTED]

Reply via email to