Now we come to an extraordinary consequence of the Leo way. We said above that the execute-script command executes the script in body text in the context of the c, g and p variables. But p is not necessarily the node containing the script! You can define a script in one node, create a minibuffer command associated with that script. You then select another node of the outline and apply the command to the outline. Thus, you can apply any script in any Leo node to any part of an outline. We call this bringing scripts to data.

You can associate key-bindings with any script, and you can create script buttons in Leo's icon area that will execute a script on the presently selected outline. By the way, script buttons are dynamic. If you change the script button's script, the new script will be used the next time you push the script button (or execute the corresponding minibuffer command, or press the key bound to the script button).

There is another aspect of the Leo way (that is, another change of perspective), that makes Leo's data amazingly flexible. This second change in attitude is this:

We can consider that a headline describe a node's data.

That is, a node (it's body text, user data, and internal data managed by Leo) is the data. The headline is the node's metadata. Because nodes are true Python objects, this association of data with metadata is secure. It can not be broken by editing text, say.

But headlines can be much more than a simple, human-readable description. Scripts can assign types to nodes (and their descendants). By convention (it's only a convention, it is not built into Leo) headlines that start with '@' have special meaning to scripts, including Leo's own predefined commands.

For example, Leo's core (the standard part of Leo that is available to all plugins), creates support for @test nodes. The headline is @test <test name>. The body text is any Python script. As always, when executing the script Leo predefines the c, g and p variables. You can, in fact, use the execute-script command on @test nodes. Nothing special will happen.

However, you can run the run-unit-tests-locally (Alt-4) command on a (part of) an outline containing one or more @test nodes. This command converts all @test nodes to subclasses of Python's Unittest.TestCase? class, and runs the result. (To see the results, you would typically run Leo from a console.)

This is extraordinarily convenient. You don't have to type (or look at) the blah-blah-blah that wraps most typical unit tests. For example, in an @test node, a single assert statement can make up a complete unit test.

Furthermore, scripts in @test nodes can use outline nodes as data for the unit tests. Most of Leo's unit tests are in the file leo/test/unitTest.leo. Many of these tests are associated with data trees, like 'input', 'output' and 'work'. The unit test applies an operation to the data in the input tree using the work tree as a scratch area. The unit test then simply asserts that the expected output in the output tree matches the actual result in the work tree. Nothing could be simpler, or more flexible.

Earlier, I said that scripts can assign types to nodes. The "type" is simply the start of the headline, like @test, @url, @picture etc. Scripts create the meaning of types. There is nothing magic about this. What a node type means is completely determined by the script that handles such nodes. Thus, node types are completely flexible and extensible. Leo has many predefined node types, the most important being @auto, @file, @thin and @shadow.