Version 11 of ycl shelf

Updated 2016-02-21 08:37:04 by pooryorick

ycl shelf, by PYK, is a simple yet effective dynamic object system similar in some ways to a prototype-based object system.

Description

Are you confused/bored/annoyed by class-based object systems? Then shelf might be the system for you!

shelf provides the functionality needed to work with namespace ensembles as objects in a dynamic object system. In this documentation, p'shelf'' signifies the namespace ensemble that is the handle for the object. The ensemble map defines the interface, and commands can be added to the map such that the name of the shelf is automatically passed to the command when called through the ensemble. The map is not limited to such commands, and indeed a new shelf contains in its map commands that don't take the name of the shelf as an argument. A shelf isn't offended in the slightest if the name of the ensemble is passed in some other position, or not at all.

When a shelf is deleted, the associated namespace is also deleted, and vice-versa.

The code footprint of shelf is quite small, and that's partially because components of it have been refactored into other components of ycl. ycl dupensemble provides the ability to produce new namespaces based on a shelf, and ycl var provides commands such as $, $.exists, and $.locate for reading variables up the hierarchy of shelves that form the basis of the current shelf.

When a new shelf is cloned or spawned from a shelf, the commands of the original shelf are available through the interface of the new shelf. When a shelf is cloned, the commands and variables in the namespace of the original shelf are actually copied into the cloned shelf.

A shelf has a basis command that can be used to directly access commands and variables in the shelf that forms its basis.

shelf does not currently utilize TclOO, but it certainly might in the future.

Interface

A shelf has the following subcommands:

$ name
Returns the value of the first variable named name in the hierarchy of shelves that form the basis of the shelf.
$.locate name
Returns the fully-qualified name of the first variable named name in the hierarchy of shelves that form the basis of the shelf, or an error if a matching variable is not found.
$.exists name
Like $.locate, but returns a True only if a matching variable was found.
~
Executed just prior to the deletion of the ensemble.
apply routine args
like apply, but the first argument to the routine is the name of the shelf, and the routine is evaluated in the namespace of the shelf.
basis
The name of the shelf a shelf was cloned or spawned from, or, for a new shelf, the empty string.
clone
Like spawn, except that commands and variables in the namespace of the original shelf are actually copied into the new shelf, after the manner of ycl ns dupensemble.
disposal script
Arranges for script to be evaluated in the global namespace when the ensemble is deleted. This command is currently additive. with no way to delete any already-registered scripts, except by using trace directly. It isn't anticipated that a more flexible mechanism would be needed, but it could be added at some point.
eval script
Evaluate script in the namespace of the ensemble.
method cmdname
Register a command as a method of the ensemble by adding it to the map and arranging for the fully-qualified name of the ensemble to be passed as the first argument to the command. method does not transform the command in any way, but it must already exist.
namespace
Returns the name of the namespace associated with the shelf.
spawn name
Create a new shelf that has the same interface as the original shelf. If name is the empty string, automatically select an appropriate name. Returns the name of the new shelf. The namespace ensemble of the current shelf is copied to the new shelf, and occurrences in the map command prefixes of the fully-qualified name of the the current shelf are replaced with the name of the new shelf.
subcmd cmdname
Like method, but doesn't arrange for the name of the ensemble to be passed as the first argument to the command, it is not necessary for the command to first exist, and if the command name is not absolute, is resolved at invocation time relative to the namespace of the shelf.

Utilities

asmethod spec
spec is a method specification of the form
args objvars nsvars body
Where args and body are the standard arguments to proc. objvars, is a list of names of variables that belong to the shelf, and nsvars is a list of names of variables in the namespace of the command. asmethod transforms body such that variables objvars and nsvars are linked in the local scope of the procedure to the appropriate variables. This allows the procedure body to be written in an a manner that is agnostic to the particular object system in use, since it need only concern itself with local variables. Other object systems may use the same spec, linking the local variables as appropriate for that system.
shelf uses this internally, so an example, although a bit convoluted at the moment (the refactoring is in progress), can be found here
glass
Configure a shelf such that any command in its associated namespace is automatically exposed as a subcommand of the shelf.
shelf
Create a new shelf.

Example

shelf swallow 
swallow $ airspeed 9 
proc fly _ {
    upvar 0 [$_ $.locate airspeed] airspeed
    puts "$_ is flying at a speed of $airspeed!"
}
swallow method fly 
swallow fly

swallow spawn european
european $ airspeed 11
european $ airspeed ;# -> 11
european fly

Ensemble Methods

A namespace ensemble, or nested namespace ensembles can be used as methods of a shelf. The trick is to use the -parameters switch of a namespace ensemble. Here's an example:

package require {ycl shelf}
namespace import [yclprefix]::shelf::shelf

shelf {heart of gold}

namespace eval generate {
    namespace ensemble create -parameters _
    namespace export *

    namespace eval infinite {
        namespace ensemble create -parameters _
        namespace export *

        proc improbability _ {
            puts [list $_ probability approaching infinity!]
        }
    }
}
{heart of gold} subcmd generate generate [namespace which {heart of gold}]


{heart of gold} generate infinite improbability

In the example above, the shelf is passed explicitly to the namespace ensemble command, generate, and the -parameters feature of namespace ensembles takes care of passing the shelf along until it reaches the target method, improbability. Note also that the target command, generate, is resolved relative to the namespace of the shelf at the time it is invoked.