I always learn something from reading other people's code, but it is rare 
to learn so much as I have done from Vitalije's prototype read/write code.  
I am writing this post as part of my study.  I want to understand not only 
the code in isolation, but the big picture of how it is put together. 
Vitalije, please correct me if I have misstated anything.

This is an Engineering Notebook post.  It will be of interest only to Leo's 
devs and other hard-core programming types.

*The "it" arg means iterable*

I often use aList in my code.  The implication is that the list might be 
mutable, but it often isn't.

In Vitalije's code, the "it" argument means iterable (not iterator).  It is 
either a tuple or a generator.  Neither can change during execution.  This 
pattern would be right at home in any functional programming language.

*The write pipeline*

all_lines is the top-level write code.  At present, there is no outer-level 
call to it, though there are interior, recursive calls to it.  Here it is:

def all_lines(p, zero_level):

    it = body_lines(p)
    it = section_replacer(it, zero_level)
    it = others_replacer(it, zero_level)
    it = node_opener(it, zero_level)
    it = at_adder(it)
    it = at_docer(it)
    return it

In my study copy, I have labeled the stages of pipeline.  The children of 
all_lines have the following headlines:

- 1: body_lines
- 2: section_replacer
- 3: others_replacer
- 4: node_opener
- 5: at_adder
- 6: at_docer

All the generators above yield (p, w), where w is a line (string).  So to 
write the file, you would use this (I think):

    zero_level=root_p.level()
    with f as open(fn, 'w'):
        for p, w in all_lines(root_p, zero_level):
            f.write(w)

This is different from how I typically write pipelines.  It seems to "pull" 
the answer out of the last generator, rather than push intermediate answers 
from one stage to the next.

This pattern eliminates intermediate tuples, which helps the GC. That's 
great for production code, but it complicates debugging just a bit. This 
works:

     if trace:
         it = tuple(it)
         for p, w in it:
             g.trace(repr(w))

This would *not *work, because it "consumes" the generator, so that later 
stages would get nothing:

     if trace:
         for p, w in tuple(it)
             g.trace(repr(w))

*The read code*

Read code is always more difficult than write code, because parsing is 
required and there are choices in the code.

The present code doesn't even simulate creating nodes. Instead, it checks 
that the vnode for each gnx will have the expected body text.

This code is extremely clever. Like the write code, it "pulls" the result, 
but unlike the write code the read code pulls the result from pre-computed 
data structures.

check_all_files_read_ok is the driver code.  For each @file node, it calls 
analyze_lines to create the data structures:

def analyze_lines(lines):
    flines = tuple(enumerate(lines))
    node_data = dict((gnx, (i,lev,h,len(ind)))
        for i,ind,gnx,lev,h in node_start_lines(flines))
    node_starts = dict((y[0],x)
        for x,y in node_data.items())
    sect_data = dict((i, (j, len(ind), sref, after))
        for i,j,ind,sref,after in sect_refs(flines))
    at_oth_data = dict((st, (en, len(ind)))
        for st,en,ind in at_others_refs(flines))
    oth_ends = set(x[0] for x in at_oth_data.values())
    return flines, node_data, node_starts, sect_data, at_oth_data, oth_ends

All the iterables above are generators. The returned tuple is the 
"analytics" argument used throughout the code.

check_all_files_read_ok then calls either:

    body_lines_of_top_node(gnx, analytics)
or
    body_lines_of_node(gnx, analytics)

to compute the prototyped body text of the node whose gnx is given.

This is pretty much all I know ;-)  Happily, all the code is beautifully 
simple, so additional study should be straightforward.

Many important details remain implicit in the code. There is no guarantee 
that it is equivalent to Leo's present read/write code.

Edward

-- 
You received this message because you are subscribed to the Google Groups 
"leo-editor" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/leo-editor.
For more options, visit https://groups.google.com/d/optout.

Reply via email to