Hi all,
Thanks a lot for your work on plugins. Making this work shows the power
of Leo for many task and helps a lot to the newbies like me. I think
also that this mail is some kind of movie script for "Leo in practice"
series. You have a simple and important task that can be understand by
newbies in some way. May this doesn't shot the red button of Leo, but
surely helps a lot in showing its magic and is a good step towards
finding the way to show that button in practice.
Cheers,
Offray
El 12/11/10 06:10, Edward K. Ream escribió:
On Thu, Nov 11, 2010 at 8:36 PM, Edward K. Ream<[email protected]> wrote:
Here is a script I wrote this evening. I present it here to show
newbies that it's worth the trouble to learn how to use Leo :-)
The script itself does not, in itself, explain much of anything.
After posting the script, I recalled the words of John C Mather, who
won the Nobel Prize in physics in 2006 for the discovery of anisotropy
in the cosmic microwave background radiation. He was quoted in Nature
recently with this advice to young researches:
"Number 1: study reading and especially writing! And then, practice
public speaking. The ability to explain logically, intuitively and
*viscerally* [my emphasis] why something is true essential to planning
research strategy and obtaining funds for future work. There's really
no substitute for good communication. And it will be valuable wherever
life takes you."
Inspired by this excellent advice, let me try to explain my *visceral*
sensations of pleasure in writing this script. This pleasure comes
from many sources, and it is the pleasure itself that I want to
explain.
First, there is the pleasure of turning what what might be a tedious
task into an fun little programming task. Leo has a lot of plugins,
and there is an ongoing need to make sure all significant and
functional plugins get documented in the "Plugins" chapter of Leo's
Users Guide. I want to automate this task as much as possible.
Clearly, Leo itself can help with this project. A few days ago I
wrote another script that reported any .py files that appeared in the
leo/plugins directory but which did *not* have a corresponding @<file>
node in leoPlugins.leo. With the help of this script I was able to
ensure that leoPlugins.leo does in fact describe all plugins.
So the task becomes taking the docstrings from the plugins in
leoPlugins.leo and using them as the basis for the documentation in
Leo's Users Guide. But that documentation resides in LeoDocs.leo, so
the problem is one of copying docstrings from leoPlugins.leo to
LeoDocs.leo.
Pleasure! This is a straightforward problem! And it's a problem that
can not be *stated*, much less solved, in any other editor.
There are two happy "coincidences" that make such a project especially
easy and attractive. First, both docstrings and Leo's Users Guide use
restructured text (rST) as the markup language. This means that the
*docstrings* can serve as the primary documentation. If I want to
update the entry in the Users Guide, I can simply update the
docstring.
Pleasure! Selecting the plugin from the plugins menu shows the
*rendered* version of the rST docstring. Second, Therefore, improving
the docstring improves what the user sees when she is investigating
the plugin. And now that the docstring "generates" the Users Guide,
improving the docstring will improve the Users Guide as well. The
pleasure comes from the realization that I won't have to manually keep
things in sync.
The second "coincidence" is that the structure of the Plugins chapter
in the Users Guide mirrors the structure of leoPlugins.leo. This
isn't really a coincidence, it's by design. Thus, it will be *useful*
for the script to create nodes whose structure mirrors the structure
of leoPlugins.leo, because that structure will "carry over" to the
Users Guide! This was obvious to me because I know very well that
outline structure in LeoDocs.leo creates rST markup. Pleasure!
Let's recap so far. We have a straightforward problem that, when
solved, will reduce future tedium and will ensure that documentation
in the Users Guide will match the primary documentation in the
docstrings for the plugins. Seeing this possibility is yet another
pleasure.
But for me, the real pleasure came in writing the script itself. Not
all of this pleasure is easily described, and I am *not* going to
explain every line of the script. But here are at least some of the
sources of the pleasure.
1. Like almost all scripts that I write, it started as code in a
single node. As the script got larger, I added an @others directive
near the top and a call to the driver function, run, after that. run,
and all of its helpers, are defined in children of this node. So the
basic plan for all non-trivial scripts is::
'''docstring'''
@others
run()
In fact, this is how I started. But long experience has taught me
that non-trivial scripts should be encapsulated in a controller class.
In this case, the pattern became, fairly late in the process::
'''docstring'''
@others
controller(c).run()
Pleasure! Writing a script this way makes the presentation as clear
as possible. The child nodes of the top-level script nodes instantly
show me the overall structure of the script. This is important when
months or years later I want to know how the script works.
2. I wrote the script incrementally. At first, run simply printed the
docstring in the console. Only after the script was correctly finding
all docstrings in leoPlugins.leo did I turn my attention to creating a
corresponding outline in LeoDocs.leo.
At this step, there were two sources of pleasure. First is the
never-ending pleasure of using a language a simple and powerful as
Python. I just love every single aspect of Python. No other language
even comes close. I still remember the first 30 years of my
programming practice. All that time I was thinking of ways to improve
the programming language that I was using. No more. Python does
everything I have ever wanted, and a *lot* more.
The second source of pleasure was using simple snippets of Leonine
code. Newbies will know some of these from their initial study, but
others are a bit harder to find.
The easy stuff:
- p.b and p.h can get or set headline text.
- p.self_and_subtree() is an iterator returning p and all its
descendants in outline order.
- The Python s.find string function.
- p.insertAfter() creates a new node.
- p.doDelete() deletes the node p.
This is *almost* all there is to it. Pleasure!
Naturally, since I have been doing this a long time, I know of some
other quite helpful tools:
- g.findNodeAnywhere(c,pattern) searches for a node anywhere in c's outline.
- g.findNodeInTree(c,p,pattern) searches for a node only in p's tree.
I actually don't remember the args, typing completion reminds me.
- g.os_path_finalize_join(args) creates full paths to files. It is
like a combination of various os.path methods, but with the advantage
that it handles unicode file names correctly in Python 2.x (Python 3.x
doesn't need this help, but using the g.os_path_x methods allows Leo
to have a common code base for both version of Leo. Pleasure!
- ok,frame = g.openWithFileName(args) opens an outline and returns its
frame. I get the commander like this::
new_c = frame.c
In other words, I remember a bit about the "official" ivars that Leo provides.
3. We are now in a position to understand the script in detail.
- The openPlugins method opens leoPlugins.leo from leoDocs.leo and
returns the commander for leoPlugins.leo. It uses
g.os_path_finalize_join and g.openWithFileName.
- The getDocString method searches the body text of p and its
descendants looking for the first docstring. It uses
p.self_and_subtree, s.find and a Python trick I use frequently: using
a for loop to eliminate duplicate code. The code itself is elegant
enough to give me a lot of pleasure.
- The run method is actually quite simple::
A. It opens leoPlugins.leo.
B. It creates a node called 'get-docstrings-output' as the root of a
tree that will contain all the docstrings.
C. It traverses the tree in leoPlugins.leo looking for docstrings. For
each found docstring, it creates a node under the
'get-docstrings-output' node.
There is a bit more going on, but not much. The main point is that it
uses only the simple tools I have already described. It was
straightforward to create, improve and debug. Pleasure!
So there you have it. At each stage I did something easy, and the
result was an extremely valuable script. If that isn't a solid basis
for pleasure I don't know what is.
Edward
--
You received this message because you are subscribed to the Google Groups
"leo-editor" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/leo-editor?hl=en.