clay(3tcl) | Clay Framework | clay(3tcl) |
clay - A minimalist framework for large scale OO Projects
package require Tcl 8.6
package require uuid
package require oo::dialect
proc clay::PROC name arglist body ?ninja ?
proc clay::_ancestors resultvar class
proc clay::ancestors ?args?
proc clay::args_to_dict ?args?
proc clay::args_to_options ?args?
proc clay::dynamic_arguments ensemble method arglist ?args?
proc clay::dynamic_wrongargs_message arglist
proc clay::is_dict d
proc clay::is_null value
proc clay::leaf ?args?
proc clay::K a b
proc clay::noop ?args?
proc clay::cleanup
proc clay::object_create objname ?class ?
proc clay::object_rename object newname
proc clay::object_destroy ?args?
proc clay::path ?args?
proc clay::putb ?map? text
proc clay::script_path
proc clay::NSNormalize qualname
proc clay::uuid_generate ?args?
proc clay::uuid::generate_tcl_machinfo
proc clay::uuid::tostring uuid
proc clay::uuid::fromstring uuid
proc clay::uuid::equal left right
proc clay::uuid cmd ?args?
proc clay::tree::sanitize dict
proc clay::tree::_sanitizeb path varname dict
proc clay::tree::storage rawpath
proc clay::tree::dictset varname ?args?
proc clay::tree::dictmerge varname ?args?
proc clay::tree::merge ?args?
proc dictargs::proc name argspec body
proc dictargs::method name argspec body
proc clay::dialect::Push class
proc clay::dialect::Peek
proc clay::dialect::Pop
proc clay::dialect::create name ?parent ?
proc clay::dialect::NSNormalize namespace qualname
proc clay::dialect::DefineThunk target ?args?
proc clay::dialect::Canonical namespace NSpace class
proc clay::dialect::Define namespace class ?args?
proc clay::dialect::Aliases namespace ?args?
proc clay::dialect::SuperClass namespace ?args?
proc clay::dynamic_methods class
proc clay::dynamic_methods_class thisclass
proc clay::define::Array name ?values ?
proc clay::define::Delegate name info
proc clay::define::constructor arglist rawbody
proc clay::define::Class_Method name arglist body
proc clay::define::class_method name arglist body
proc clay::define::clay ?args?
proc clay::define::destructor rawbody
proc clay::define::Dict name ?values ?
proc clay::define::Option name ?args?
proc clay::define::Method name argstyle argspec body
proc clay::define::Option_Class name ?args?
proc clay::define::Variable name ?default ?
proc clay::ensemble_methodbody ensemble einfo
proc clay::define::Ensemble rawmethod ?args?
proc clay::event::cancel self ?task *?
proc clay::event::generate self event ?args?
proc clay::event::nextid
proc clay::event::Notification_list self event ?stackvar ?
proc clay::event::notify rcpt sender event eventinfo
proc clay::event::process self handle script
proc clay::event::schedule self handle interval script
proc clay::event::subscribe self who event
proc clay::event::unsubscribe self ?args?
proc clay::singleton name script
method clay ancestors
method clay dump
method clay find path ?path...?
method clay get path ?path...?
method clay GET path ?path...?
method clay merge dict ?dict...?
method clay replace dictionary
method clay search path ?path...?
method clay set path ?path...? value
method clay ancestors
method clay cache path value
method clay cget field
method clay delegate ?stub? ?object?
method clay dump
method clay ensemble_map
method clay eval script
method clay evolve
method clay exists path ?path...?
method clay flush
method clay forward method object
method clay get path ?path...?
method clay leaf path ?path...?
method clay merge dict ?dict...?
method clay mixin class ?class...?
method clay mixinmap ?stub? ?classes?
method clay provenance path ?path...?
method clay replace dictionary
method clay search path valuevar isleafvar
method clay source filename
method clay set path ?path...? value
method InitializePublic
Clay introduces a method ensemble to both oo::class and oo::object called clay. This ensemble handles all of the high level interactions within the framework. Clay stores structured data. Clan manages method delegation. Clay has facilities to manage the complex interactions that come about with mixins.
The central concept is that inside of every object and class (which are actually objects too) is a dict called clay. What is stored in that dict is left to the imagination. But because this dict is exposed via a public method, we can share structured data between object, classes, and mixins.
Clay uses a standardized set of method interactions and introspection that TclOO already provides to perform on-the-fly searches. On-the-fly searches mean that the data is never stale, and we avoid many of the sorts of collisions that would arise when objects start mixing in other classes during operation.
The clay methods for both classes and objects have a get and a set method. For objects, get will search through the local clay dict. If the requested leaf is not found, or the query is for a branch, the system will then begin to poll the clay methods of all of the class that implements the object, all of that classes’ ancestors, as well as all of the classes that have been mixed into this object, and all of their ancestors.
Intended branches on a tree end with a directory slash (/). Intended leaves are left unadorned. This is a guide for the tool that builds the search results to know what parts of a dict are intended to be branches and which are intended to be leaves. For simple cases, branch marking can be ignored:
::oo::class create ::foo { } ::foo clay set property/ color blue ::foo clay set property/ shape round set A [::foo new] $A clay get property/ {color blue shape round} $A clay set property/ shape square $A clay get property/ {color blue shape square}
But when you start storing blocks of text, guessing what field is a dict and what isn’t gets messy:
::foo clay set description {A generic thing of designated color and shape} $A clay get description {A generic thing of designated color and shape} Without a convention for discerning branches for leaves what should have been a value can be accidentally parsed as a dictionary, and merged with all of the other values that were never intended to be merge. Here is an example of it all going wrong: ::oo::class create ::foo { } # Add description as a leaf ::foo clay set description {A generic thing of designated color and shape} # Add description as a branch ::foo clay set description/ {A generic thing of designated color and shape} ::oo::class create ::bar { superclass foo } # Add description as a leaf ::bar clay set description {A drinking establishment of designated color and shape and size} # Add description as a branch ::bar clay set description/ {A drinking establishment of designated color and shape and size} set B [::bar new] # As a leaf we get the value verbatim from he nearest ancestor $B clay get description {A drinking establishment of designated color and shape and size} # As a branch we get a recursive merge $B clay get description/ {A drinking establishment of designated color and size thing of}
Clay is built using the oo::dialect module from Tcllib. oo::dialect allows you to either add keywords directly to clay, or to create your own metaclass and keyword set using Clay as a foundation. For details on the keywords and what they do, consult the functions in the ::clay::define namespace.
Method Delegation It is sometimes useful to have an external object that can be invoked as if it were a method of the object. Clay provides a delegate ensemble method to perform that delegation, as well as introspect which methods are delegated in that manner. All delegated methods are marked with html-like tag markings (< >) around them.
::clay::define counter { Variable counter 0 method incr {{howmuch 1}} { my variable counter incr counter $howmuch } method value {} { my variable counter return $counter } method reset {} { my variable counter set counter 0 } } ::clay::define example { variable buffer constructor {} { # Build a counter object set obj [namespace current]::counter ::counter create $obj # Delegate the counter my delegate <counter> $obj } method line {text} { my <counter> incr append buffer $text } } set A [example new] $A line {Who’s line is it anyway?} $A <counter> value 1
Example:
> clay::tree::storage {foo bar baz bang} foo bar baz bang > clay::tree::storage {foo bar baz bang/} foo bar baz bang > clay::tree::storage {foo bar baz bang:} foo bar baz bang: > clay::tree::storage {foo/bar/baz bang:} foo bar baz bang: > clay::tree::storage {foo/bar/baz/bang} foo bar baz bang
Example:
> set r {} > ::clay::tree::dictset r option color default Green . {} option {. {} color {. {} default Green}} > ::clay::tree::dictset r option {Something not dictlike} . {} option {Something not dictlike} # Note that if the value is not a dict, and you try to force it to be # an error with be thrown on the merge > ::clay::tree::dictset r option color default Blue missing value to go with key
Example:
> set mydict {sub/ {sub/ {description {a block of text}}}} > ::clay::tree::dictmerge mydict {sub/ {sub/ {field {another block of text}}}}] > clay::tree::print $mydict sub/ { sub/ { description {a block of text} field {another block of text} } }
A routine to recursively dig through dicts and merge adapted from http://stevehavelka.com/tcl-dict-operation-nested-merge/
Example:
> set mydict {sub/ {sub/ {description {a block of text}}}} > set odict [clay::tree::merge $mydict {sub/ {sub/ {field {another block of text}}}}] > clay::tree::print $odict sub/ { sub/ { description {a block of text} field {another block of text} } }
property variable NAME {default DEFAULT}
Variables registered in the variable property are also initialized (if missing) when the object changes class via the morph method.
Example:
::clay::ensemble_methodbody foo { bar {tailcall my Foo_bar {*}$args} baz {tailcall my Foo_baz {*}$args} clock {return [clock seconds]} default {puts "You gave me $method"} }
Methods
clay::object This class is inherited by all classes that have options.
Methods
1. The as a value in local dict variable config
2. The as a value in local dict variable clay
3. As a leaf in any ancestor as a root of the clay tree
4. As a leaf in any ancestor as const field
5. As a leaf in any ancestor as option field default
oo::objdefine [self] forward {*}$args
Sean Woods mailto:<yoda@etoyoc.com>
This document, and the package it describes, will undoubtedly contain bugs and other problems. Please report such in the category oo of the Tcllib Trackers [http://core.tcl.tk/tcllib/reportlist]. Please also report any ideas for enhancements you may have for either package and/or documentation.
When proposing code changes, please provide unified diffs, i.e the output of diff -u.
Note further that attachments are strongly preferred over inlined patches. Attachments can be made by going to the Edit form of the ticket immediately after its creation, and then using the left-most button in the secondary navigation bar.
TclOO, oo
Programming tools
Copyright (c) 2018 Sean Woods <yoda@etoyoc.com>
0.8.6 | tcllib |