1clay(n) Clay Framework clay(n)
2
3
4
5______________________________________________________________________________
6
8 clay - A minimalist framework for large scale OO Projects
9
11 package require Tcl 8.6
12
13 package require uuid
14
15 package require oo::dialect
16
17 proc clay::PROC name arglist body ?ninja ?
18
19 proc clay::_ancestors resultvar class
20
21 proc clay::ancestors ?args?
22
23 proc clay::args_to_dict ?args?
24
25 proc clay::args_to_options ?args?
26
27 proc clay::dynamic_arguments ensemble method arglist ?args?
28
29 proc clay::dynamic_wrongargs_message arglist
30
31 proc clay::is_dict d
32
33 proc clay::is_null value
34
35 proc clay::leaf ?args?
36
37 proc clay::K a b
38
39 proc clay::noop ?args?
40
41 proc clay::cleanup
42
43 proc clay::object_create objname ?class ?
44
45 proc clay::object_rename object newname
46
47 proc clay::object_destroy ?args?
48
49 proc clay::path ?args?
50
51 proc clay::putb ?map? text
52
53 proc clay::script_path
54
55 proc clay::NSNormalize qualname
56
57 proc clay::uuid_generate ?args?
58
59 proc clay::uuid::generate_tcl_machinfo
60
61 proc clay::uuid::tostring uuid
62
63 proc clay::uuid::fromstring uuid
64
65 proc clay::uuid::equal left right
66
67 proc clay::uuid cmd ?args?
68
69 proc clay::tree::sanitize dict
70
71 proc clay::tree::_sanitizeb path varname dict
72
73 proc clay::tree::storage rawpath
74
75 proc clay::tree::dictset varname ?args?
76
77 proc clay::tree::dictmerge varname ?args?
78
79 proc clay::tree::merge ?args?
80
81 proc dictargs::proc name argspec body
82
83 proc dictargs::method name argspec body
84
85 proc clay::dialect::Push class
86
87 proc clay::dialect::Peek
88
89 proc clay::dialect::Pop
90
91 proc clay::dialect::create name ?parent ?
92
93 proc clay::dialect::NSNormalize namespace qualname
94
95 proc clay::dialect::DefineThunk target ?args?
96
97 proc clay::dialect::Canonical namespace NSpace class
98
99 proc clay::dialect::Define namespace class ?args?
100
101 proc clay::dialect::Aliases namespace ?args?
102
103 proc clay::dialect::SuperClass namespace ?args?
104
105 proc clay::dynamic_methods class
106
107 proc clay::dynamic_methods_class thisclass
108
109 proc clay::define::Array name ?values ?
110
111 proc clay::define::Delegate name info
112
113 proc clay::define::constructor arglist rawbody
114
115 proc clay::define::Class_Method name arglist body
116
117 proc clay::define::class_method name arglist body
118
119 proc clay::define::clay ?args?
120
121 proc clay::define::destructor rawbody
122
123 proc clay::define::Dict name ?values ?
124
125 proc clay::define::Option name ?args?
126
127 proc clay::define::Method name argstyle argspec body
128
129 proc clay::define::Option_Class name ?args?
130
131 proc clay::define::Variable name ?default ?
132
133 proc clay::ensemble_methodbody ensemble einfo
134
135 proc clay::define::Ensemble rawmethod ?args?
136
137 proc clay::event::cancel self ?task *?
138
139 proc clay::event::generate self event ?args?
140
141 proc clay::event::nextid
142
143 proc clay::event::Notification_list self event ?stackvar ?
144
145 proc clay::event::notify rcpt sender event eventinfo
146
147 proc clay::event::process self handle script
148
149 proc clay::event::schedule self handle interval script
150
151 proc clay::event::subscribe self who event
152
153 proc clay::event::unsubscribe self ?args?
154
155 proc clay::singleton name script
156
157 method clay ancestors
158
159 method clay dump
160
161 method clay find path ?path...?
162
163 method clay get path ?path...?
164
165 method clay GET path ?path...?
166
167 method clay merge dict ?dict...?
168
169 method clay replace dictionary
170
171 method clay search path ?path...?
172
173 method clay set path ?path...? value
174
175 method clay ancestors
176
177 method clay cache path value
178
179 method clay cget field
180
181 method clay delegate ?stub? ?object?
182
183 method clay dump
184
185 method clay ensemble_map
186
187 method clay eval script
188
189 method clay evolve
190
191 method clay exists path ?path...?
192
193 method clay flush
194
195 method clay forward method object
196
197 method clay get path ?path...?
198
199 method clay leaf path ?path...?
200
201 method clay merge dict ?dict...?
202
203 method clay mixin class ?class...?
204
205 method clay mixinmap ?stub? ?classes?
206
207 method clay provenance path ?path...?
208
209 method clay replace dictionary
210
211 method clay search path valuevar isleafvar
212
213 method clay source filename
214
215 method clay set path ?path...? value
216
217 method InitializePublic
218
219______________________________________________________________________________
220
222 Clay introduces a method ensemble to both oo::class and oo::object
223 called clay. This ensemble handles all of the high level interactions
224 within the framework. Clay stores structured data. Clan manages method
225 delegation. Clay has facilities to manage the complex interactions that
226 come about with mixins.
227
228 The central concept is that inside of every object and class (which are
229 actually objects too) is a dict called clay. What is stored in that
230 dict is left to the imagination. But because this dict is exposed via a
231 public method, we can share structured data between object, classes,
232 and mixins.
233
234 STRUCTURED DATA
235 Clay uses a standardized set of method interactions and introspection
236 that TclOO already provides to perform on-the-fly searches. On-the-fly
237 searches mean that the data is never stale, and we avoid many of the
238 sorts of collisions that would arise when objects start mixing in other
239 classes during operation.
240
241 The clay methods for both classes and objects have a get and a set
242 method. For objects, get will search through the local clay dict. If
243 the requested leaf is not found, or the query is for a branch, the sys‐
244 tem will then begin to poll the clay methods of all of the class that
245 implements the object, all of that classes’ ancestors, as well as all
246 of the classes that have been mixed into this object, and all of their
247 ancestors.
248
249 Intended branches on a tree end with a directory slash (/). Intended
250 leaves are left unadorned. This is a guide for the tool that builds the
251 search results to know what parts of a dict are intended to be branches
252 and which are intended to be leaves. For simple cases, branch marking
253 can be ignored:
254
255
256 ::oo::class create ::foo { }
257 ::foo clay set property/ color blue
258 ::foo clay set property/ shape round
259
260 set A [::foo new]
261 $A clay get property/
262 {color blue shape round}
263
264 $A clay set property/ shape square
265 $A clay get property/
266 {color blue shape square}
267
268
269 But when you start storing blocks of text, guessing what field is a
270 dict and what isn’t gets messy:
271
272
273 ::foo clay set description {A generic thing of designated color and shape}
274
275 $A clay get description
276 {A generic thing of designated color and shape}
277
278 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:
279 ::oo::class create ::foo { }
280 # Add description as a leaf
281 ::foo clay set description {A generic thing of designated color and shape}
282 # Add description as a branch
283 ::foo clay set description/ {A generic thing of designated color and shape}
284
285 ::oo::class create ::bar {
286 superclass foo
287 }
288 # Add description as a leaf
289 ::bar clay set description {A drinking establishment of designated color and shape and size}
290 # Add description as a branch
291 ::bar clay set description/ {A drinking establishment of designated color and shape and size}
292
293 set B [::bar new]
294 # As a leaf we get the value verbatim from he nearest ancestor
295 $B clay get description
296 {A drinking establishment of designated color and shape and size}
297 # As a branch we get a recursive merge
298 $B clay get description/
299 {A drinking establishment of designated color and size thing of}
300
301
302 CLAY DIALECT
303 Clay is built using the oo::dialect module from Tcllib. oo::dialect al‐
304 lows you to either add keywords directly to clay, or to create your own
305 metaclass and keyword set using Clay as a foundation. For details on
306 the keywords and what they do, consult the functions in the ::clay::de‐
307 fine namespace.
308
309 METHOD DELEGATION
310 Method Delegation It is sometimes useful to have an external object
311 that can be invoked as if it were a method of the object. Clay provides
312 a delegate ensemble method to perform that delegation, as well as in‐
313 trospect which methods are delegated in that manner. All delegated
314 methods are marked with html-like tag markings (< >) around them.
315
316
317 ::clay::define counter {
318 Variable counter 0
319 method incr {{howmuch 1}} {
320 my variable counter
321 incr counter $howmuch
322 }
323 method value {} {
324 my variable counter
325 return $counter
326 }
327 method reset {} {
328 my variable counter
329 set counter 0
330 }
331 }
332 ::clay::define example {
333 variable buffer
334 constructor {} {
335 # Build a counter object
336 set obj [namespace current]::counter
337 ::counter create $obj
338 # Delegate the counter
339 my delegate <counter> $obj
340 }
341 method line {text} {
342 my <counter> incr
343 append buffer $text
344 }
345 }
346
347 set A [example new]
348 $A line {Who’s line is it anyway?}
349 $A <counter> value
350 1
351
352
354 proc clay::PROC name arglist body ?ninja ?
355 Because many features in this package may be added as commands
356 to future tcl cores, or be provided in binary form by packages,
357 I need a declaritive way of saying Create this command if there
358 isn't one already. The ninja argument is a script to execute if
359 the command is created by this mechanism.
360
361 proc clay::_ancestors resultvar class
362
363 proc clay::ancestors ?args?
364
365 proc clay::args_to_dict ?args?
366
367 proc clay::args_to_options ?args?
368
369 proc clay::dynamic_arguments ensemble method arglist ?args?
370
371 proc clay::dynamic_wrongargs_message arglist
372
373 proc clay::is_dict d
374
375 proc clay::is_null value
376
377 proc clay::leaf ?args?
378
379 proc clay::K a b
380
381 proc clay::noop ?args?
382 Perform a noop. Useful in prototyping for commenting out blocks
383 of code without actually having to comment them out. It also
384 makes a handy default for method delegation if a delegate has
385 not been assigned yet.
386
387 proc clay::cleanup
388 Process the queue of objects to be destroyed
389
390 proc clay::object_create objname ?class ?
391
392 proc clay::object_rename object newname
393
394 proc clay::object_destroy ?args?
395 Mark an objects for destruction on the next cleanup
396
397 proc clay::path ?args?
398
399 proc clay::putb ?map? text
400 Append a line of text to a variable. Optionally apply a string
401 mapping.
402
403 proc clay::script_path
404
405 proc clay::NSNormalize qualname
406
407 proc clay::uuid_generate ?args?
408
409 proc clay::uuid::generate_tcl_machinfo
410
411 proc clay::uuid::tostring uuid
412
413 proc clay::uuid::fromstring uuid
414 Convert a string representation of a uuid into its binary for‐
415 mat.
416
417 proc clay::uuid::equal left right
418 Compare two uuids for equality.
419
420 proc clay::uuid cmd ?args?
421 uuid generate -> string rep of a new uuid uuid equal uuid1 uuid2
422
423 proc clay::tree::sanitize dict
424 Output a dictionary removing any . entries added by
425 clay::tree::merge
426
427 proc clay::tree::_sanitizeb path varname dict
428 Helper function for ::clay::tree::sanitize Formats the string
429 representation for a dictionary element within a human readable
430 stream of lines, and determines if it needs to call itself with
431 further indentation to express a sub-branch
432
433 proc clay::tree::storage rawpath
434 Return the path as a storage path for clay::tree with all branch
435 terminators removed. This command will also break arguments up
436 if they contain /.
437
438 Example:
439
440 > clay::tree::storage {foo bar baz bang}
441 foo bar baz bang
442 > clay::tree::storage {foo bar baz bang/}
443 foo bar baz bang
444 > clay::tree::storage {foo bar baz bang:}
445 foo bar baz bang:
446 > clay::tree::storage {foo/bar/baz bang:}
447 foo bar baz bang:
448 > clay::tree::storage {foo/bar/baz/bang}
449 foo bar baz bang
450
451
452
453
454 proc clay::tree::dictset varname ?args?
455 Set an element with a recursive dictionary, marking all branches
456 on the way down to the final element. If the value does not ex‐
457 ists in the nested dictionary it is added as a leaf. If the
458 value already exists as a branch the value given is merged if
459 the value is a valid dict. If the incoming value is not a valid
460 dict, the value overrides the value stored, and the value is
461 treated as a leaf from then on.
462
463 Example:
464
465 > set r {}
466 > ::clay::tree::dictset r option color default Green
467 . {} option {. {} color {. {} default Green}}
468 > ::clay::tree::dictset r option {Something not dictlike}
469 . {} option {Something not dictlike}
470 # Note that if the value is not a dict, and you try to force it to be
471 # an error with be thrown on the merge
472 > ::clay::tree::dictset r option color default Blue
473 missing value to go with key
474
475
476
477
478 proc clay::tree::dictmerge varname ?args?
479 A recursive form of dict merge, intended for modifying variables
480 in place.
481
482 Example:
483
484 > set mydict {sub/ {sub/ {description {a block of text}}}}
485 > ::clay::tree::dictmerge mydict {sub/ {sub/ {field {another block of text}}}}]
486 > clay::tree::print $mydict
487 sub/ {
488 sub/ {
489 description {a block of text}
490 field {another block of text}
491 }
492 }
493
494
495
496
497 proc clay::tree::merge ?args?
498 A recursive form of dict merge
499
500 A routine to recursively dig through dicts and merge adapted
501 from http://stevehavelka.com/tcl-dict-operation-nested-merge/
502
503 Example:
504
505 > set mydict {sub/ {sub/ {description {a block of text}}}}
506 > set odict [clay::tree::merge $mydict {sub/ {sub/ {field {another block of text}}}}]
507 > clay::tree::print $odict
508 sub/ {
509 sub/ {
510 description {a block of text}
511 field {another block of text}
512 }
513 }
514
515
516
517
518 proc dictargs::proc name argspec body
519 Named Procedures as new command
520
521 proc dictargs::method name argspec body
522
523 proc clay::dialect::Push class
524
525 proc clay::dialect::Peek
526
527 proc clay::dialect::Pop
528
529 proc clay::dialect::create name ?parent ?
530 This proc will generate a namespace, a "mother of all classes",
531 and a rudimentary set of policies for this dialect.
532
533 proc clay::dialect::NSNormalize namespace qualname
534 Support commands; not intended to be called directly.
535
536 proc clay::dialect::DefineThunk target ?args?
537
538 proc clay::dialect::Canonical namespace NSpace class
539
540 proc clay::dialect::Define namespace class ?args?
541 Implementation of the languages' define command
542
543 proc clay::dialect::Aliases namespace ?args?
544
545 proc clay::dialect::SuperClass namespace ?args?
546
547 proc clay::dynamic_methods class
548
549 proc clay::dynamic_methods_class thisclass
550
551 proc clay::define::Array name ?values ?
552 New OO Keywords for clay
553
554 proc clay::define::Delegate name info
555 An annotation that objects of this class interact with delegated
556 methods. The annotation is intended to be a dictionary, and the
557 only reserved key is description, a human readable description.
558
559 proc clay::define::constructor arglist rawbody
560
561 proc clay::define::Class_Method name arglist body
562 Specify the a method for the class object itself, instead of for
563 objects of the class
564
565 proc clay::define::class_method name arglist body
566 And alias to the new Class_Method keyword
567
568 proc clay::define::clay ?args?
569
570 proc clay::define::destructor rawbody
571
572 proc clay::define::Dict name ?values ?
573
574 proc clay::define::Option name ?args?
575 Define an option for the class
576
577 proc clay::define::Method name argstyle argspec body
578
579 proc clay::define::Option_Class name ?args?
580 Define a class of options All field / value pairs will be be in‐
581 herited by an option that specify name as it class field.
582
583 proc clay::define::Variable name ?default ?
584 This keyword can also be expressed:
585
586 property variable NAME {default DEFAULT}
587
588 Variables registered in the variable property are also initialized (if
589 missing) when the object changes class via the morph method.
590
591 proc clay::ensemble_methodbody ensemble einfo
592 Produce the body of an ensemble's public dispatch method ensem‐
593 ble is the name of the the ensemble. einfo is a dictionary of
594 methods for the ensemble, and each value is a script to execute
595 on dispatch
596
597 Example:
598
599 ::clay::ensemble_methodbody foo {
600 bar {tailcall my Foo_bar {*}$args}
601 baz {tailcall my Foo_baz {*}$args}
602 clock {return [clock seconds]}
603 default {puts "You gave me $method"}
604 }
605
606
607
608
609 proc clay::define::Ensemble rawmethod ?args?
610
611 proc clay::event::cancel self ?task *?
612 Cancel a scheduled event
613
614 proc clay::event::generate self event ?args?
615 Generate an event Adds a subscription mechanism for objects to
616 see who has recieved this event and prevent spamming or infinite
617 recursion
618
619 proc clay::event::nextid
620
621 proc clay::event::Notification_list self event ?stackvar ?
622 Called recursively to produce a list of who recieves notifica‐
623 tions
624
625 proc clay::event::notify rcpt sender event eventinfo
626 Final delivery to intended recipient object
627
628 proc clay::event::process self handle script
629 Evaluate an event script in the global namespace
630
631 proc clay::event::schedule self handle interval script
632 Schedule an event to occur later
633
634 proc clay::event::subscribe self who event
635 Subscribe an object to an event pattern
636
637 proc clay::event::unsubscribe self ?args?
638 Unsubscribe an object from an event pattern
639
640 proc clay::singleton name script
641 An object which is intended to be it's own class.
642
644 CLASS CLAY::CLASS
645 Methods
646
647 method clay ancestors
648 Return this class and all ancestors in search order.
649
650 method clay dump
651 Return a complete dump of this object's clay data, but only this
652 object's clay data.
653
654 method clay find path ?path...?
655 Pull a chunk of data from the clay system. If the last element
656 of path is a branch, returns a recursive merge of all data from
657 this object and it's constituent classes of the data in that
658 branch. If the last element is a leaf, search this object for a
659 matching leaf, or search all constituent classes for a matching
660 leaf and return the first value found. If no value is found,
661 returns an empty string. If a branch is returned the topmost .
662 entry is omitted.
663
664 method clay get path ?path...?
665 Pull a chunk of data from the class's clay system. If no value
666 is found, returns an empty string. If a branch is returned the
667 topmost . entry is omitted.
668
669 method clay GET path ?path...?
670 Pull a chunk of data from the class's clay system. If no value
671 is found, returns an empty string.
672
673 method clay merge dict ?dict...?
674 Recursively merge the dictionaries given into the object's local
675 clay storage.
676
677 method clay replace dictionary
678 Replace the contents of the internal clay storage with the dic‐
679 tionary given.
680
681 method clay search path ?path...?
682 Return the first matching value for the path in either this
683 class's clay data or one of its ancestors
684
685 method clay set path ?path...? value
686 Merge the conents of value with the object's clay storage at
687 path.
688
689 CLASS CLAY::OBJECT
690 clay::object This class is inherited by all classes that have options.
691
692 Methods
693
694 method clay ancestors
695 Return the class this object belongs to, all classes mixed into
696 this object, and all ancestors of those classes in search order.
697
698 method clay cache path value
699 Store VALUE in such a way that request in SEARCH for PATH will
700 always return it until the cache is flushed
701
702 method clay cget field
703 Pull a value from either the object's clay structure or one of
704 its constituent classes that matches the field name. The order
705 of search us:
706
707 1. The as a value in local dict variable config
708
709 2. The as a value in local dict variable clay
710
711 3. As a leaf in any ancestor as a root of the clay tree
712
713 4. As a leaf in any ancestor as const field
714
715 5. As a leaf in any ancestor as option field default
716
717 method clay delegate ?stub? ?object?
718 Introspect or control method delegation. With no arguments, the
719 method will return a key/value list of stubs and objects. With
720 just the stub argument, the method will return the object (if
721 any) attached to the stub. With a stub and an object this com‐
722 mand will forward all calls to the method stub to the object.
723
724 method clay dump
725 Return a complete dump of this object's clay data, as well as
726 the data from all constituent classes recursively blended in.
727
728 method clay ensemble_map
729 Return a dictionary describing the method ensembles to be assem‐
730 bled for this object
731
732 method clay eval script
733 Evaluated a script in the namespace of this object
734
735 method clay evolve
736 Trigger the InitializePublic private method
737
738 method clay exists path ?path...?
739 Returns 1 if path exists in either the object's clay data. Val‐
740 ues greater than one indicate the element exists in one of the
741 object's constituent classes. A value of zero indicates the path
742 could not be found.
743
744 method clay flush
745 Wipe any caches built by the clay implementation
746
747 method clay forward method object
748 A convenience wrapper for
749
750 oo::objdefine [self] forward {*}$args
751
752 method clay get path ?path...?
753 Pull a chunk of data from the clay system. If the last element
754 of path is a branch (ends in a slash /), returns a recursive
755 merge of all data from this object and it's constituent classes
756 of the data in that branch. If the last element is a leaf,
757 search this object for a matching leaf, or search all con‐
758 stituent classes for a matching leaf and return the first value
759 found. If no value is found, returns an empty string.
760
761 method clay leaf path ?path...?
762 A modified get which is tailored to pull only leaf elements
763
764 method clay merge dict ?dict...?
765 Recursively merge the dictionaries given into the object's local
766 clay storage.
767
768 method clay mixin class ?class...?
769 Perform [oo::objdefine [self] mixin] on this object, with a few
770 additional rules: Prior to the call, for any class was previ‐
771 ously mixed in, but not in the new result, execute the script
772 registered to mixin/ unmap-script (if given.) For all new
773 classes, that were not present prior to this call, after the na‐
774 tive TclOO mixin is invoked, execute the script registered to
775 mixin/ map-script (if given.) Fall all classes that are now
776 present and “mixed in”, execute the script registered to mixin/
777 react-script (if given.)
778
779 method clay mixinmap ?stub? ?classes?
780 With no arguments returns the map of stubs and classes mixed
781 into the current object. When only stub is given, returns the
782 classes mixed in on that stub. When stub and classlist given,
783 replace the classes currently on that stub with the given
784 classes and invoke clay mixin on the new matrix of mixed in
785 classes.
786
787 method clay provenance path ?path...?
788 Return either self if that path exists in the current object, or
789 return the first class (if any) along the clay search path which
790 contains that element.
791
792 method clay replace dictionary
793 Replace the contents of the internal clay storage with the dic‐
794 tionary given.
795
796 method clay search path valuevar isleafvar
797 Return true, and set valuevar to the value and isleafar to true
798 for false if PATH was found in the cache.
799
800 method clay source filename
801 Source the given filename within the object's namespace
802
803 method clay set path ?path...? value
804 Merge the conents of value with the object's clay storage at
805 path.
806
807 method InitializePublic
808 Instantiate variables. Called on object creation and during clay
809 mixin.
810
812 Sean Woods mailto:<yoda@etoyoc.com>
813
815 This document, and the package it describes, will undoubtedly contain
816 bugs and other problems. Please report such in the category oo of the
817 Tcllib Trackers [http://core.tcl.tk/tcllib/reportlist]. Please also
818 report any ideas for enhancements you may have for either package
819 and/or documentation.
820
821 When proposing code changes, please provide unified diffs, i.e the out‐
822 put of diff -u.
823
824 Note further that attachments are strongly preferred over inlined
825 patches. Attachments can be made by going to the Edit form of the
826 ticket immediately after its creation, and then using the left-most
827 button in the secondary navigation bar.
828
830 TclOO, oo
831
833 Programming tools
834
836 Copyright (c) 2018 Sean Woods <yoda@etoyoc.com>
837
838
839
840
841tcllib 0.8.6 clay(n)