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.
$.locatename
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.
$.existsname
Like $.locate, but returns a True only if a matching variable was found.
~
Executed just prior to the deletion of the ensemble.
applyroutineargs
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.
disposalscript
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.
evalscript
Evaluate script in the namespace of the ensemble.
methodcmdname
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.
spawnname
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.
subcmdcmdname
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
asmethodspec
spec is a method specification of the form
argsobjvarsnsvarsbody
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:
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.