Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch tip-478 Excluding Merge-Ins
This is equivalent to a diff from e3cb60581f to c253e68a51
2018-09-02
| ||
13:48 | Implement TIP 478: Add Expected Class Level Behaviors to oo::class check-in: b9f75ba387 user: dkf tags: core-8-branch | |
2018-08-29
| ||
17:01 | merge 8.6 check-in: 9f791c2d99 user: sebres tags: core-8-branch | |
2018-08-28
| ||
18:59 | merge core-8-branch check-in: 364e4f0003 user: jan.nijtmans tags: trunk | |
2018-08-26
| ||
11:07 | merge core-8-branch Closed-Leaf check-in: c253e68a51 user: dkf tags: tip-478 | |
2018-08-19
| ||
09:33 | Re-base branch "all-wideint" to core-8-branch. Still WIP check-in: 4932848e36 user: jan.nijtmans tags: tip-514 | |
2018-08-17
| ||
22:21 | Merge 8.6 check-in: e3cb60581f user: jan.nijtmans tags: core-8-branch | |
22:15 | Minor fix to entier(): Allow it to convert to "wideInt" as well when range is appropriate check-in: d7d65c2ac3 user: jan.nijtmans tags: core-8-6-branch | |
2018-08-14
| ||
05:43 | Reposition the MODULE_SCOPE definition so that packages like tbcload don't get an error when they in... check-in: 7e7c72ccc9 user: pooryorick tags: core-8-branch | |
2018-08-11
| ||
12:01 | Added a note about the genesis of the compiled header. check-in: fe3eeb39c3 user: dkf tags: tip-478 | |
Added doc/abstract.n.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | '\" '\" Copyright (c) 2018 Donal K. Fellows '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .TH abstract n 0.3 TclOO "TclOO Commands" .so man.macros .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME oo::abstract \- a class that does not allow direct instances of itself .SH SYNOPSIS .nf package require TclOO \fBoo::abstract\fI method \fR?\fIarg ...\fR? .fi .SH "CLASS HIERARCHY" .nf \fBoo::object\fR \(-> \fBoo::class\fR \(-> \fBoo::abstract\fR .fi .BE .SH DESCRIPTION Abstract classes are classes that can contain definitions, but which cannot be directly manufactured; they are intended to only ever be inherited from and instantiated indirectly. The characteristic methods of \fBoo::class\fR (\fBcreate\fR and \fBnew\fR) are not exported by an instance of \fBoo::abstract\fR. .PP Note that \fBoo::abstract\fR is not itself an instance of \fBoo::abstract\fR. .SS CONSTRUCTOR The \fBoo::abstract\fR class does not define an explicit constructor; this means that it is effectively the same as the constructor of the \fBoo::class\fR class. .SS DESTRUCTOR The \fBoo::abstract\fR class does not define an explicit destructor; destroying an instance of it is just like destroying an ordinary class (and will destroy all its subclasses). .SS "EXPORTED METHODS" The \fBoo::abstract\fR class defines no new exported methods. .SS "NON-EXPORTED METHODS" The \fBoo::abstract\fR class explicitly states that \fBcreate\fR, \fBcreateWithNamespace\fR, and \fBnew\fR are unexported. .SH EXAMPLES .PP This example defines a simple class hierarchy and creates a new instance of it. It then invokes a method of the object before destroying the hierarchy and showing that the destruction is transitive. .PP .CS \fBoo::abstract\fR create fruit { method eat {} { puts "yummy!" } } oo::class create banana { superclass fruit method peel {} { puts "skin now off" } } set b [banana \fBnew\fR] $b peel \fI\(-> prints 'skin now off'\fR $b eat \fI\(-> prints 'yummy!'\fR set f [fruit new] \fI\(-> error 'unknown method "new"...'\fR .CE .SH "SEE ALSO" oo::define(n), oo::object(n) .SH KEYWORDS abstract class, class, metaclass, object .\" Local variables: .\" mode: nroff .\" fill-column: 78 .\" End: |
Added doc/callback.n.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | '\" '\" Copyright (c) 2018 Donal K. Fellows '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .TH callback n 0.3 TclOO "TclOO Commands" .so man.macros .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME callback, mymethod \- generate callbacks to methods .SH SYNOPSIS .nf package require TclOO \fBcallback\fR \fImethodName\fR ?\fIarg ...\fR? \fBmymethod\fR \fImethodName\fR ?\fIarg ...\fR? .fi .BE .SH DESCRIPTION The \fBcallback\fR command, '\" Based on notes in the tcllib docs, we know the provenance of mymethod also called \fBmymethod\fR for compatibility with the ooutil and snit packages of Tcllib, and which should only be used from within the context of a call to a method (i.e. inside a method, constructor or destructor body) is used to generate a script fragment that will invoke the method, \fImethodName\fR, on the current object (as reported by \fBself\fR) when executed. Any additional arguments provided will be provided as leading arguments to the callback. The resulting script fragment shall be a proper list. .PP Note that it is up to the caller to ensure that the current object is able to handle the call of \fImethodName\fR; this command does not check that. \fImethodName\fR may refer to any exported or unexported method, but may not refer to a private method as those can only be invoked directly from within methods. If there is no such method present at the point when the callback is invoked, the standard \fBunknown\fR method handler will be called. .SH EXAMPLE This is a simple echo server class. The \fBcallback\fR command is used in two places, to arrange for the incoming socket connections to be handled by the \fIAccept\fR method, and to arrange for the incoming bytes on those connections to be handled by the \fIReceive\fR method. .PP .CS oo::class create EchoServer { variable server clients constructor {port} { set server [socket -server [\fBcallback\fR Accept] $port] set clients {} } destructor { chan close $server foreach client [dict keys $clients] { chan close $client } } method Accept {channel clientAddress clientPort} { dict set clients $channel [dict create \e address $clientAddress port $clientPort] chan event $channel readable [\fBcallback\fR Receive $channel] } method Receive {channel} { if {[chan gets $channel line] >= 0} { my echo $channel $line } else { chan close $channel dict unset clients $channel } } method echo {channel line} { dict with clients $channel { chan puts $channel \e [format {[%s:%d] %s} $address $port $line] } } } .CE .SH "SEE ALSO" chan(n), fileevent(n), my(n), self(n), socket(n), trace(n) .SH KEYWORDS callback, object .\" Local Variables: .\" mode: nroff .\" fill-column: 78 .\" End: |
Added doc/classvariable.n.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | '\" '\" Copyright (c) 2011-2015 Andreas Kupries '\" Copyright (c) 2018 Donal K. Fellows '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .TH classvariable n 0.3 TclOO "TclOO Commands" .so man.macros .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME classvariable \- create link from local variable to variable in class .SH SYNOPSIS .nf package require TclOO \fBclassvariable\fR \fIvariableName\fR ?\fI...\fR? .fi .BE .SH DESCRIPTION The \fBclassvariable\fR command is available within methods. It takes a series of one or more variable names and makes them available in the method's scope; those variable names must not be qualified and must not refer to array elements. The originating scope for the variables is the namespace of the class that the method was defined by. In other words, the referenced variables are shared between all instances of that class. .PP Note: This command is equivalent to the command \fBtypevariable\fR provided by the snit package in tcllib for approximately the same purpose. If used in a method defined directly on a class instance (e.g., through the \fBoo::objdefine\fR \fBmethod\fR definition) this is very much like just using: .PP .CS namespace upvar [namespace current] $var $var .CE .PP for each variable listed to \fBclassvariable\fR. .SH EXAMPLE This class counts how many instances of it have been made. .PP .CS oo::class create Counted { initialise { variable count 0 } variable number constructor {} { \fBclassvariable\fR count set number [incr count] } method report {} { \fBclassvariable\fR count puts "This is instance $number of $count" } } set a [Counted new] set b [Counted new] $a report \fI\(-> This is instance 1 of 2\fR set c [Counted new] $b report \fI\(-> This is instance 2 of 3\fR $c report \fI\(-> This is instance 3 of 3\fR .CE .SH "SEE ALSO" global(n), namespace(n), oo::class(n), oo::define(n), upvar(n), variable(n) .SH KEYWORDS class, class variable, variable .\" Local Variables: .\" mode: nroff .\" fill-column: 78 .\" End: |
Changes to doc/define.n.
1 | '\" | | | 1 2 3 4 5 6 7 8 9 | '\" '\" Copyright (c) 2007-2018 Donal K. Fellows '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .TH define n 0.3 TclOO "TclOO Commands" .so man.macros .BS |
︙ | ︙ | |||
34 35 36 37 38 39 40 41 42 43 44 45 46 47 | \fIarg\fR arguments; when the second is present, it is exactly as if all the arguments from \fIsubcommand\fR onwards are made into a list and that list is used as the \fIdefScript\fR argument. .SS "CONFIGURING CLASSES" .PP The following commands are supported in the \fIdefScript\fR for \fBoo::define\fR, each of which may also be used in the \fIsubcommand\fR form: .TP \fBconstructor\fI argList bodyScript\fR . This creates or updates the constructor for a class. The formal arguments to the constructor (defined using the same format as for the Tcl \fBproc\fR command) will be \fIargList\fR, and the body of the constructor will be \fIbodyScript\fR. When the body of the constructor is evaluated, the current | > > > > > > > > > > > > > > > > > > > > > | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | \fIarg\fR arguments; when the second is present, it is exactly as if all the arguments from \fIsubcommand\fR onwards are made into a list and that list is used as the \fIdefScript\fR argument. .SS "CONFIGURING CLASSES" .PP The following commands are supported in the \fIdefScript\fR for \fBoo::define\fR, each of which may also be used in the \fIsubcommand\fR form: .TP \fBclassmethod\fI name\fR ?\fIargList bodyScrip\fR? .VS TIP478 This creates a class method, or (if \fIargList\fR and \fIbodyScript\fR are omitted) promotes an existing method on the class object to be a class method. The \fIname\fR, \fIargList\fR and \fIbodyScript\fR arguments are as in the \fBmethod\fR definition, below. .RS .PP Class methods can be called on either the class itself or on the instances of that class. When they are called, the current object (see the \fBself\R and \fBmy\fR commands) is the class on which they are called or the class of the instance on which they are called, depending on whether they are called on the class or an instance of the class, respectively. If called on a subclass or instance of the subclass, the current object is the subclass. .PP In a private definition context, the methods as invoked on classes are \fInot\fR private, but the methods as invoked on instances of classes are private. .RE .VE TIP478 .TP \fBconstructor\fI argList bodyScript\fR . This creates or updates the constructor for a class. The formal arguments to the constructor (defined using the same format as for the Tcl \fBproc\fR command) will be \fIargList\fR, and the body of the constructor will be \fIbodyScript\fR. When the body of the constructor is evaluated, the current |
︙ | ︙ | |||
105 106 107 108 109 110 111 112 113 114 115 116 117 118 | .RS .PP .VS TIP500 If in a private definition context (see the \fBprivate\fR definition command, below), this command creates private forwarded methods. .VE TIP500 .RE .TP \fBmethod\fI name argList bodyScript\fR . This creates or updates a method that is implemented as a procedure-like script. The name of the method is \fIname\fR, the formal arguments to the method (defined using the same format as for the Tcl \fBproc\fR command) will be \fIargList\fR, and the body of the method will be \fIbodyScript\fR. When | > > > > > > > > > | 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | .RS .PP .VS TIP500 If in a private definition context (see the \fBprivate\fR definition command, below), this command creates private forwarded methods. .VE TIP500 .RE .TP \fBinitialise\fI script\fR .TP \fBinitialize\fI script\fR .VS TIP478 This evaluates \fIscript\fR in a context which supports local variables and where the current namespace is the instance namespace of the class object itself. This is useful for setting up, e.g., class-scoped variables. .VE TIP478 .TP \fBmethod\fI name argList bodyScript\fR . This creates or updates a method that is implemented as a procedure-like script. The name of the method is \fIname\fR, the formal arguments to the method (defined using the same format as for the Tcl \fBproc\fR command) will be \fIargList\fR, and the body of the method will be \fIbodyScript\fR. When |
︙ | ︙ | |||
492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 | } \fBoo::objdefine\fR inst { \fBmixin -append\fR B } inst m1 \fI\(-> prints "red brick"\fR inst m2 \fI\(-> prints "blue brick"\fR .CE .SH "SEE ALSO" next(n), oo::class(n), oo::object(n) .SH KEYWORDS class, definition, method, object, slot .\" Local variables: .\" mode: nroff .\" fill-column: 78 .\" End: | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 | } \fBoo::objdefine\fR inst { \fBmixin -append\fR B } inst m1 \fI\(-> prints "red brick"\fR inst m2 \fI\(-> prints "blue brick"\fR .CE .PP .VS TIP478 This example shows how to create and use class variables. It is a class that counts how many instances of itself have been made. .PP .CS oo::class create Counted \fBoo::define\fR Counted { \fBinitialise\fR { variable count 0 } \fBvariable\fR number \fBconstructor\fR {} { classvariable count set number [incr count] } \fBmethod\fR report {} { classvariable count puts "This is instance $number of $count" } } set a [Counted new] set b [Counted new] $a report \fI\(-> This is instance 1 of 2\fR set c [Counted new] $b report \fI\(-> This is instance 2 of 3\fR $c report \fI\(-> This is instance 3 of 3\fR .CE .PP This example demonstrates how to use class methods. (Note that the constructor for \fBoo::class\fR calls \fBoo::define\fR on the class.) .PP .CS oo::class create DBTable { \fBclassmethod\fR find {description} { puts "DB: locate row from [self] matching $description" return [my new] } \fBclassmethod\fR insert {description} { puts "DB: create row in [self] matching $description" return [my new] } \fBmethod\fR update {description} { puts "DB: update row [self] with $description" } \fBmethod\fR delete {} { puts "DB: delete row [self]" my destroy; # Just delete the object, not the DB row } } oo::class create Users { \fBsuperclass\fR DBTable } oo::class create Groups { \fBsuperclass\fR DBTable } set u1 [Users insert "username=abc"] \fI\(-> DB: create row from ::Users matching username=abc\fR set u2 [Users insert "username=def"] \fI\(-> DB: create row from ::Users matching username=def\fR $u2 update "group=NULL" \fI\(-> DB: update row ::oo::Obj124 with group=NULL\fR $u1 delete \fI\(-> DB: delete row ::oo::Obj123\fR set g [Group find "groupname=webadmins"] \fI\(-> DB: locate row ::Group with groupname=webadmins\fR $g update "emailaddress=admins" \fI\(-> DB: update row ::oo::Obj125 with emailaddress=admins\fR .CE .VE TIP478 .SH "SEE ALSO" next(n), oo::class(n), oo::object(n) .SH KEYWORDS class, definition, method, object, slot .\" Local variables: .\" mode: nroff .\" fill-column: 78 .\" End: |
Added doc/link.n.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | '\" '\" Copyright (c) 2011-2015 Andreas Kupries '\" Copyright (c) 2018 Donal K. Fellows '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .TH link n 0.3 TclOO "TclOO Commands" .so man.macros .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME link \- create link from command to method of object .SH SYNOPSIS .nf package require TclOO \fBlink\fR \fImethodName\fR ?\fI...\fR? \fBlink\fR \fB{\fIcommandName methodName\fB}\fR ?\fI...\fR? .fi .BE .SH DESCRIPTION The \fBlink\fR command is available within methods. It takes a series of one or more method names (\fImethodName ...\fR) and/or pairs of command- and method-name (\fB{\fIcommandName methodName\fB}\fR) and makes the named methods available as commands without requiring the explicit use of the name of the object or the \fBmy\fR command. The method does not need to exist at the time that the link is made; if the link command is invoked when the method does not exist, the standard \fBunknown\fR method handling system is used. .PP The command name under which the method becomes available defaults to the method name, except where explicitly specified through an alias/method pair. Formally, every argument must be a list; if the list has two elements, the first element is the name of the command to create and the second element is the name of the method of the current object to which the command links; otherwise, the name of the command and the name of the method are the same string (the first element of the list). .PP If the name of the command is not a fully-qualified command name, it will be resolved with respect to the current namespace (i.e., the object namespace). .SH EXAMPLES This demonstrates linking a single method in various ways. First it makes a simple link, then a renamed link, then an external link. Note that the method itself is unexported, but that it can still be called directly from outside the class. .PP .CS oo::class create ABC { method Foo {} { puts "This is Foo in [self]" } constructor {} { \fBlink\fR Foo # The method foo is now directly accessible as foo here \fBlink\fR {bar Foo} # The method foo is now directly accessible as bar \fBlink\fR {::ExternalCall Foo} # The method foo is now directly accessible in the global # namespace as ExternalCall } method grill {} { puts "Step 1:" Foo puts "Step 2:" bar } } ABC create abc abc grill \fI\(-> Step 1:\fR \fI\(-> This is foo in ::abc\fR \fI\(-> Step 2:\fR \fI\(-> This is foo in ::abc\fR # Direct access via the linked command puts "Step 3:"; ExternalCall \fI\(-> Step 3:\fR \fI\(-> This is foo in ::abc\fR .CE .PP This example shows that multiple linked commands can be made in a call to \fBlink\fR, and that they can handle arguments. .PP .CS oo::class create Ex { constructor {} { \fBlink\fR a b c # The methods a, b, and c (defined below) are all now # directly acessible within methods under their own names. } method a {} { puts "This is a" } method b {x} { puts "This is b($x)" } method c {y z} { puts "This is c($y,$z)" } method call {p q r} { a b $p c $q $r } } set o [Ex new] $o 3 5 7 \fI\(-> This is a\fR \fI\(-> This is b(3)\fR \fI\(-> This is c(5,7)\fR .CE .SH "SEE ALSO" interp(n), my(n), oo::class(n), oo::define(n) .SH KEYWORDS command, method, object .\" Local Variables: .\" mode: nroff .\" fill-column: 78 .\" End: |
Changes to doc/my.n.
1 2 3 4 5 6 7 8 9 10 11 | '\" '\" Copyright (c) 2007 Donal K. Fellows '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .TH my n 0.1 TclOO "TclOO Commands" .so man.macros .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME | | > | > > > > > > | | > > > > > > > | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | '\" '\" Copyright (c) 2007 Donal K. Fellows '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .TH my n 0.1 TclOO "TclOO Commands" .so man.macros .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME my, myclass \- invoke any method of current object or its class .SH SYNOPSIS .nf package require TclOO \fBmy\fI methodName\fR ?\fIarg ...\fR? \fBmyclass\fI methodName\fR ?\fIarg ...\fR? .fi .BE .SH DESCRIPTION .PP The \fBmy\fR command is used to allow methods of objects to invoke methods of the object (or its class), .VS TIP478 and he \fBmyclass\fR command is used to allow methods of objects to invoke methods of the current class of the object \fIas an object\fR. .VE TIP478 In particular, the set of valid values for \fImethodName\fR is the set of all methods supported by an object and its superclasses, including those that are not exported .VS TIP500 and private methods of the object or class when used within another method defined by that object or class. .VE TIP500 .PP The object upon which the method is invoked via \fBmy\fR is the one that owns the namespace that the \fBmy\fR command is contained in initially (\fBNB:\fR the link remains if the command is renamed), which is the currently invoked object by default. .VS TIP478 Similarly, the object on which the method is invoked via \fBmyclass\fR is the object that is the current class of the object that owns the namespace that the \fBmyclass\fR command is contained in initially. As with \fBmy\fR, the link remains even if the command is renamed into another namespace, and defaults to being the manufacturing class of the current object. .VE TIP478 .PP Each object has its own \fBmy\fR and \fBmyclass\fR commands, contained in its instance namespace. .SH EXAMPLES .PP This example shows basic use of \fBmy\fR to use the \fBvariables\fR method of the \fBoo::object\fR class, which is not publicly visible by default: .PP .CS oo::class create c { |
︙ | ︙ | |||
50 51 52 53 54 55 56 | o count \fI\(-> prints "1"\fR o count \fI\(-> prints "2"\fR o count \fI\(-> prints "3"\fR .CE .PP This example shows how you can use \fBmy\fR to make callbacks to private methods from outside the object (from a \fBtrace\fR), using | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | o count \fI\(-> prints "1"\fR o count \fI\(-> prints "2"\fR o count \fI\(-> prints "3"\fR .CE .PP This example shows how you can use \fBmy\fR to make callbacks to private methods from outside the object (from a \fBtrace\fR), using \fBnamespace code\fR to enter the correct context. (See the \fBcallback\fR command for the recommended way of doing this.) .PP .CS oo::class create HasCallback { method makeCallback {} { return [namespace code { \fBmy\fR Callback }] } method Callback {args} { puts "callback: $args" } } set o [HasCallback new] trace add variable xyz write [$o makeCallback] set xyz "called" \fI\(-> prints "callback: xyz {} write"\fR .CE .PP .VS TIP478 This example shows how to access a private method of a class from an instance of that class. (See the \fBclassmethod\fR declaration in \fBoo::define\fR for a higher level interface for doing this.) .PP .CS oo::class create CountedSteps { self { variable count method Count {} { return [incr count] } } method advanceTwice {} { puts "in [self] step A: [\fBmyclass\fR Count]" puts "in [self] step B: [\fBmyclass\fR Count]" } } CountedSteps create x CountedSteps create y x advanceTwice \fI\(-> prints "in ::x step A: 1"\fR \fI\(-> prints "in ::x step B: 2"\fR y advanceTwice \fI\(-> prints "in ::y step A: 3"\fR \fI\(-> prints "in ::y step B: 4"\fR x advanceTwice \fI\(-> prints "in ::x step A: 5"\fR \fI\(-> prints "in ::x step B: 6"\fR y advanceTwice \fI\(-> prints "in ::y step A: 7"\fR \fI\(-> prints "in ::y step B: 8"\fR .CE .VE TIP478 .SH "SEE ALSO" next(n), oo::object(n), self(n) .SH KEYWORDS method, method visibility, object, private method, public method .\" Local variables: .\" mode: nroff .\" fill-column: 78 .\" End: |
Added doc/singleton.n.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | '\" '\" Copyright (c) 2018 Donal K. Fellows '\" '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" .TH singleton n 0.3 TclOO "TclOO Commands" .so man.macros .BS '\" Note: do not modify the .SH NAME line immediately below! .SH NAME oo::singleton \- a class that does only allows one instance of itself .SH SYNOPSIS .nf package require TclOO \fBoo::singleton\fI method \fR?\fIarg ...\fR? .fi .SH "CLASS HIERARCHY" .nf \fBoo::object\fR \(-> \fBoo::class\fR \(-> \fBoo::singleton\fR .fi .BE .SH DESCRIPTION Singleton classes are classes that only permit at most one instance of themselves to exist. They unexport the \fBcreate\fR and \fBcreateWithNamespace\fR methods entirely, and override the \fBnew\fR method so that it only makes a new instance if there is no existing instance. It is not recommended to inherit from a singleton class; singleton-ness is \fInot\fR inherited. It is not recommended that a singleton class's constructor take any arguments. .PP Instances have their\fB destroy\fR method overridden with a method that always returns an error in order to discourage destruction of the object, but destruction remains possible if strictly necessary (e.g., by destroying the class or using \fBrename\fR to delete it). They also have a (non-exported) \fB<cloned>\fR method defined on them that similarly always returns errors to make attempts to use the singleton instance with \fBoo::copy\fR fail. .SS CONSTRUCTOR The \fBoo::singleton\fR class does not define an explicit constructor; this means that it is effectively the same as the constructor of the \fBoo::class\fR class. .SS DESTRUCTOR The \fBoo::singleton\fR class does not define an explicit destructor; destroying an instance of it is just like destroying an ordinary class (and will destroy the singleton object). .SS "EXPORTED METHODS" .TP \fIcls \fBnew \fR?\fIarg ...\fR? . This returns the current instance of the singleton class, if one exists, and creates a new instance only if there is no existing instance. The additional arguments, \fIarg ...\fR, are only used if a new instance is actually manufactured; that construction is via the \fBoo::class\fR class's \fBnew\fR method. .RS .PP This is an override of the behaviour of a superclass's method with an identical call signature to the superclass's implementation. .RE .SS "NON-EXPORTED METHODS" The \fBoo::singleton\fR class explicitly states that \fBcreate\fR and \fBcreateWithNamespace\fR are unexported; callers should not assume that they have control over either the name or the namespace name of the singleton instance. .SH EXAMPLE .PP This example demonstrates that there is only one instance even though the \fBnew\fR method is called three times. .PP .CS \fBoo::singleton\fR create Highlander { method say {} { puts "there can be only one" } } set h1 [Highlander new] set h2 [Highlander new] if {$h1 eq $h2} { puts "equal objects" \fI\(-> prints "equal objects"\fR } set h3 [Highlander new] if {$h1 eq $h3} { puts "equal objects" \fI\(-> prints "equal objects"\fR } .CE .PP Note that the name of the instance of the singleton is not guaranteed to be anything in particular. .SH "SEE ALSO" oo::class(n) .SH KEYWORDS class, metaclass, object, single instance .\" Local variables: .\" mode: nroff .\" fill-column: 78 .\" End: |
Changes to generic/tclOO.c.
︙ | ︙ | |||
98 99 100 101 102 103 104 105 106 107 108 109 110 111 | Tcl_Obj *const *objv); static int PrivateObjectCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); static int PrivateNRObjectCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); /* * Methods in the oo::object and oo::class classes. First, we define a helper * macro that makes building the method type declaration structure a lot * easier. No point in making life harder than it has to be! * * Note that the core methods don't need clone or free proc callbacks. | > > > > > > > | 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | Tcl_Obj *const *objv); static int PrivateObjectCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); static int PrivateNRObjectCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); static int MyClassObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); static int MyClassNRObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv); static void MyClassDeleted(ClientData clientData); /* * Methods in the oo::object and oo::class classes. First, we define a helper * macro that makes building the method type declaration structure a lot * easier. No point in making life harder than it has to be! * * Note that the core methods don't need clone or free proc callbacks. |
︙ | ︙ | |||
148 149 150 151 152 153 154 | "package ifneeded TclOO " TCLOO_PATCHLEVEL " {# Already present, OK?};" "namespace eval ::oo { variable version " TCLOO_VERSION " };" "namespace eval ::oo { variable patchlevel " TCLOO_PATCHLEVEL " };"; /* "tcl_findLibrary tcloo $oo::version $oo::version" */ /* " tcloo.tcl OO_LIBRARY oo::library;"; */ /* | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < | 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | "package ifneeded TclOO " TCLOO_PATCHLEVEL " {# Already present, OK?};" "namespace eval ::oo { variable version " TCLOO_VERSION " };" "namespace eval ::oo { variable patchlevel " TCLOO_PATCHLEVEL " };"; /* "tcl_findLibrary tcloo $oo::version $oo::version" */ /* " tcloo.tcl OO_LIBRARY oo::library;"; */ /* * The scripted part of the definitions of TclOO. */ #include "tclOOScript.h" /* * The actual definition of the variable holding the TclOO stub table. */ MODULE_SCOPE const TclOOStubs tclOOStubs; |
︙ | ︙ | |||
356 357 358 359 360 361 362 | InitFoundation( Tcl_Interp *interp) { static Tcl_ThreadDataKey tsdKey; ThreadLocalData *tsdPtr = Tcl_GetThreadData(&tsdKey, sizeof(ThreadLocalData)); Foundation *fPtr = ckalloc(sizeof(Foundation)); | | | 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 | InitFoundation( Tcl_Interp *interp) { static Tcl_ThreadDataKey tsdKey; ThreadLocalData *tsdPtr = Tcl_GetThreadData(&tsdKey, sizeof(ThreadLocalData)); Foundation *fPtr = ckalloc(sizeof(Foundation)); Tcl_Obj *namePtr; Tcl_DString buffer; Command *cmdPtr; int i; /* * Initialize the structure that holds the OO system core. This is * attached to the interpreter via an assocData entry; not very efficient, |
︙ | ︙ | |||
435 436 437 438 439 440 441 | for (i=0 ; objMethods[i].name ; i++) { TclOONewBasicMethod(interp, fPtr->objectCls, &objMethods[i]); } for (i=0 ; clsMethods[i].name ; i++) { TclOONewBasicMethod(interp, fPtr->classCls, &clsMethods[i]); } | < < < < < < < < < < < < | 387 388 389 390 391 392 393 394 395 396 397 398 399 400 | for (i=0 ; objMethods[i].name ; i++) { TclOONewBasicMethod(interp, fPtr->objectCls, &objMethods[i]); } for (i=0 ; clsMethods[i].name ; i++) { TclOONewBasicMethod(interp, fPtr->classCls, &clsMethods[i]); } /* * Finish setting up the class of classes by marking the 'new' method as * private; classes, unlike general objects, must have explicit names. We * also need to create the constructor for classes. */ TclNewLiteralStringObj(namePtr, "new"); |
︙ | ︙ | |||
487 488 489 490 491 492 493 | /* * Now make the class of slots. */ if (TclOODefineSlots(fPtr) != TCL_OK) { return TCL_ERROR; } | > > > > > | | 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 | /* * Now make the class of slots. */ if (TclOODefineSlots(fPtr) != TCL_OK) { return TCL_ERROR; } /* * Evaluate the remaining definitions, which are a compiled-in Tcl script. */ return Tcl_EvalEx(interp, tclOOSetupScript, -1, 0); } /* * ---------------------------------------------------------------------- * * InitClassSystemRoots -- * |
︙ | ︙ | |||
793 794 795 796 797 798 799 800 801 802 803 804 805 806 | tracePtr->clientData = oPtr; tracePtr->flags = TCL_TRACE_RENAME|TCL_TRACE_DELETE; tracePtr->nextPtr = NULL; tracePtr->refCount = 1; oPtr->myCommand = TclNRCreateCommandInNs(interp, "my", oPtr->namespacePtr, PrivateObjectCmd, PrivateNRObjectCmd, oPtr, MyDeleted); return oPtr; } /* * ---------------------------------------------------------------------- * * SquelchCachedName -- | > > > | 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 | tracePtr->clientData = oPtr; tracePtr->flags = TCL_TRACE_RENAME|TCL_TRACE_DELETE; tracePtr->nextPtr = NULL; tracePtr->refCount = 1; oPtr->myCommand = TclNRCreateCommandInNs(interp, "my", oPtr->namespacePtr, PrivateObjectCmd, PrivateNRObjectCmd, oPtr, MyDeleted); oPtr->myclassCommand = TclNRCreateCommandInNs(interp, "myclass", oPtr->namespacePtr, MyClassObjCmd, MyClassNRObjCmd, oPtr, MyClassDeleted); return oPtr; } /* * ---------------------------------------------------------------------- * * SquelchCachedName -- |
︙ | ︙ | |||
820 821 822 823 824 825 826 | oPtr->cachedNameObj = NULL; } } /* * ---------------------------------------------------------------------- * | | | | > | < > > > > > > > > | 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 | oPtr->cachedNameObj = NULL; } } /* * ---------------------------------------------------------------------- * * MyDeleted, MyClassDeleted -- * * These callbacks are triggered when the object's [my] or [myclass] * commands are deleted by any mechanism. They just mark the object as * not having a [my] command or [myclass] command, and so prevent cleanup * of those commands when the object itself is deleted. * * ---------------------------------------------------------------------- */ static void MyDeleted( ClientData clientData) /* Reference to the object whose [my] has been * squelched. */ { register Object *oPtr = clientData; oPtr->myCommand = NULL; } static void MyClassDeleted( ClientData clientData) { Object *oPtr = clientData; oPtr->myclassCommand = NULL; } /* * ---------------------------------------------------------------------- * * ObjectRenamedTrace -- * * This callback is triggered when the object is deleted by any |
︙ | ︙ | |||
1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 | * The namespace must have been deleted directly. Delete the command * as well. */ Tcl_DeleteCommandFromToken(oPtr->fPtr->interp, oPtr->command); } if (oPtr->myCommand) { Tcl_DeleteCommandFromToken(oPtr->fPtr->interp, oPtr->myCommand); } /* * Splice the object out of its context. After this, we must *not* call * methods on the object. | > > > | 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 | * The namespace must have been deleted directly. Delete the command * as well. */ Tcl_DeleteCommandFromToken(oPtr->fPtr->interp, oPtr->command); } if (oPtr->myclassCommand) { Tcl_DeleteCommandFromToken(oPtr->fPtr->interp, oPtr->myclassCommand); } if (oPtr->myCommand) { Tcl_DeleteCommandFromToken(oPtr->fPtr->interp, oPtr->myCommand); } /* * Splice the object out of its context. After this, we must *not* call * methods on the object. |
︙ | ︙ | |||
2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 | return TclOOObjectCmdCore((Object *) object, interp, objc, objv, PRIVATE_METHOD, (Class *) startCls); default: return TclOOObjectCmdCore((Object *) object, interp, objc, objv, 0, (Class *) startCls); } } /* * ---------------------------------------------------------------------- * * TclOOObjectCmdCore, FinalizeObjectCall -- * * Main function for object invocations. Does call chain creation, | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 | return TclOOObjectCmdCore((Object *) object, interp, objc, objv, PRIVATE_METHOD, (Class *) startCls); default: return TclOOObjectCmdCore((Object *) object, interp, objc, objv, 0, (Class *) startCls); } } /* * ---------------------------------------------------------------------- * * MyClassObjCmd, MyClassNRObjCmd -- * * Special trap door to allow an object to delegate simply to its class. * * ---------------------------------------------------------------------- */ static int MyClassObjCmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { return Tcl_NRCallObjProc(interp, MyClassNRObjCmd, clientData, objc, objv); } static int MyClassNRObjCmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) { Object *oPtr = clientData; if (objc < 2) { Tcl_WrongNumArgs(interp, 1, objv, "methodName ?arg ...?"); return TCL_ERROR; } return TclOOObjectCmdCore(oPtr->selfCls->thisPtr, interp, objc, objv, 0, NULL); } /* * ---------------------------------------------------------------------- * * TclOOObjectCmdCore, FinalizeObjectCall -- * * Main function for object invocations. Does call chain creation, |
︙ | ︙ |
Changes to generic/tclOOBasic.c.
︙ | ︙ | |||
79 80 81 82 83 84 85 | ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const *objv) { Object *oPtr = (Object *) Tcl_ObjectContextObject(context); | | > > > > > > > > > > > | > > > > > > > > > > > > > | > > | 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | ClientData clientData, Tcl_Interp *interp, Tcl_ObjectContext context, int objc, Tcl_Obj *const *objv) { Object *oPtr = (Object *) Tcl_ObjectContextObject(context); Tcl_Obj **invoke, *nameObj; if (objc-1 > Tcl_ObjectContextSkippedArgs(context)) { Tcl_WrongNumArgs(interp, Tcl_ObjectContextSkippedArgs(context), objv, "?definitionScript?"); return TCL_ERROR; } else if (objc == Tcl_ObjectContextSkippedArgs(context)) { return TCL_OK; } /* * Make the class definition delegate. This is special; it doesn't reenter * here (and the class definition delegate doesn't run any constructors). */ nameObj = Tcl_NewStringObj(oPtr->namespacePtr->fullName, -1); Tcl_AppendToObj(nameObj, ":: oo ::delegate", -1); Tcl_NewObjectInstance(interp, (Tcl_Class) oPtr->fPtr->classCls, TclGetString(nameObj), NULL, -1, NULL, -1); Tcl_DecrRefCount(nameObj); /* * Delegate to [oo::define] to do the work. */ invoke = ckalloc(3 * sizeof(Tcl_Obj *)); invoke[0] = oPtr->fPtr->defineName; invoke[1] = TclOOObjectName(interp, oPtr); invoke[2] = objv[objc-1]; /* * Must add references or errors in configuration script will cause * trouble. */ Tcl_IncrRefCount(invoke[0]); Tcl_IncrRefCount(invoke[1]); Tcl_IncrRefCount(invoke[2]); TclNRAddCallback(interp, DecrRefsPostClassConstructor, invoke, oPtr, NULL, NULL); /* * Tricky point: do not want the extra reported level in the Tcl stack * trace, so use TCL_EVAL_NOERR. */ return TclNREvalObjv(interp, 3, invoke, TCL_EVAL_NOERR, NULL); } static int DecrRefsPostClassConstructor( ClientData data[], Tcl_Interp *interp, int result) { Tcl_Obj **invoke = data[0]; Object *oPtr = data[1]; Tcl_InterpState saved; int code; TclDecrRefCount(invoke[0]); TclDecrRefCount(invoke[1]); TclDecrRefCount(invoke[2]); invoke[0] = Tcl_NewStringObj("::oo::MixinClassDelegates", -1); invoke[1] = TclOOObjectName(interp, oPtr); Tcl_IncrRefCount(invoke[0]); Tcl_IncrRefCount(invoke[1]); saved = Tcl_SaveInterpState(interp, result); code = Tcl_EvalObjv(interp, 2, invoke, 0); TclDecrRefCount(invoke[0]); TclDecrRefCount(invoke[1]); ckfree(invoke); if (code != TCL_OK) { Tcl_DiscardInterpState(saved); return code; } return Tcl_RestoreInterpState(interp, saved); } /* * ---------------------------------------------------------------------- * * TclOO_Class_Create -- * |
︙ | ︙ |
Changes to generic/tclOOInt.h.
︙ | ︙ | |||
205 206 207 208 209 210 211 212 213 214 215 216 217 218 | Tcl_ObjectMapMethodNameProc *mapMethodNameProc; /* Function to allow remapping of method * names. For itcl-ng. */ VariableNameList variables; PrivateVariableList privateVariables; /* Configurations for the variable resolver * used inside methods. */ } Object; #define OBJECT_DELETED 1 /* Flag to say that an object has been * destroyed. */ #define DESTRUCTOR_CALLED 2 /* Flag to say that the destructor has been * called. */ #define CLASS_GONE 4 /* Obsolete. Indicates that the class of this | > > | 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | Tcl_ObjectMapMethodNameProc *mapMethodNameProc; /* Function to allow remapping of method * names. For itcl-ng. */ VariableNameList variables; PrivateVariableList privateVariables; /* Configurations for the variable resolver * used inside methods. */ Tcl_Command myclassCommand; /* Reference to this object's class dispatcher * command. */ } Object; #define OBJECT_DELETED 1 /* Flag to say that an object has been * destroyed. */ #define DESTRUCTOR_CALLED 2 /* Flag to say that the destructor has been * called. */ #define CLASS_GONE 4 /* Obsolete. Indicates that the class of this |
︙ | ︙ |
Added generic/tclOOScript.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | /* * tclOOScript.h -- * * This file contains support scripts for TclOO. They are defined here so * that the code can be definitely run even in safe interpreters; TclOO's * core setup is safe. * * Copyright (c) 2012-2018 Donal K. Fellows * Copyright (c) 2013 Andreas Kupries * Copyright (c) 2017 Gerald Lester * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #ifndef TCL_OO_SCRIPT_H #define TCL_OO_SCRIPT_H /* * The scripted part of the definitions of TclOO. * * Compiled from generic/tclOOScript.tcl by tools/makeHeader.tcl, which * contains the commented version of everything; *this* file is automatically * generated. */ static const char *tclOOSetupScript = /* !BEGIN!: Do not edit below this line. */ "::namespace eval ::oo {\n" "\t::namespace path {}\n" "\tnamespace eval Helpers {\n" "\t\t::namespace path {}\n" "\t\tproc callback {method args} {\n" "\t\t\tlist [uplevel 1 {::namespace which my}] $method {*}$args\n" "\t\t}\n" "\t\tnamespace export callback\n" "\t\tnamespace eval tmp {namespace import ::oo::Helpers::callback}\n" "\t\tnamespace export -clear\n" "\t\trename tmp::callback mymethod\n" "\t\tnamespace delete tmp\n" "\t\tproc classvariable {name args} {\n" "\t\t\tset ns [info object namespace [uplevel 1 {self class}]]\n" "\t\t\tforeach v [list $name {*}$args] {\n" "\t\t\t\tif {[string match *(*) $v]} {\n" "\t\t\t\t\tset reason \"can\'t create a scalar variable that looks like an array element\"\n" "\t\t\t\t\treturn -code error -errorcode {TCL UPVAR LOCAL_ELEMENT} \\\n" "\t\t\t\t\t\t[format {bad variable name \"%s\": %s} $v $reason]\n" "\t\t\t\t}\n" "\t\t\t\tif {[string match *::* $v]} {\n" "\t\t\t\t\tset reason \"can\'t create a local variable with a namespace separator in it\"\n" "\t\t\t\t\treturn -code error -errorcode {TCL UPVAR INVERTED} \\\n" "\t\t\t\t\t\t[format {bad variable name \"%s\": %s} $v $reason]\n" "\t\t\t\t}\n" "\t\t\t\tlappend vs $v $v\n" "\t\t\t}\n" "\t\t\ttailcall namespace upvar $ns {*}$vs\n" "\t\t}\n" "\t\tproc link {args} {\n" "\t\t\tset ns [uplevel 1 {::namespace current}]\n" "\t\t\tforeach link $args {\n" "\t\t\t\tif {[llength $link] == 2} {\n" "\t\t\t\t\tlassign $link src dst\n" "\t\t\t\t} elseif {[llength $link] == 1} {\n" "\t\t\t\t\tlassign $link src\n" "\t\t\t\t\tset dst $src\n" "\t\t\t\t} else {\n" "\t\t\t\t\treturn -code error -errorcode {TCLOO CMDLINK FORMAT} \\\n" "\t\t\t\t\t\t\"bad link description; must only have one or two elements\"\n" "\t\t\t\t}\n" "\t\t\t\tif {![string match ::* $src]} {\n" "\t\t\t\t\tset src [string cat $ns :: $src]\n" "\t\t\t\t}\n" "\t\t\t\tinterp alias {} $src {} ${ns}::my $dst\n" "\t\t\t\ttrace add command ${ns}::my delete [list \\\n" "\t\t\t\t\t::oo::UnlinkLinkedCommand $src]\n" "\t\t\t}\n" "\t\t\treturn\n" "\t\t}\n" "\t}\n" "\tproc UnlinkLinkedCommand {cmd args} {\n" "\t\tif {[namespace which $cmd] ne {}} {\n" "\t\t\trename $cmd {}\n" "\t\t}\n" "\t}\n" "\tproc DelegateName {class} {\n" "\t\tstring cat [info object namespace $class] {:: oo ::delegate}\n" "\t}\n" "\tproc MixinClassDelegates {class} {\n" "\t\tif {![info object isa class $class]} {\n" "\t\t\treturn\n" "\t\t}\n" "\t\tset delegate [DelegateName $class]\n" "\t\tif {![info object isa class $delegate]} {\n" "\t\t\treturn\n" "\t\t}\n" "\t\tforeach c [info class superclass $class] {\n" "\t\t\tset d [DelegateName $c]\n" "\t\t\tif {![info object isa class $d]} {\n" "\t\t\t\tcontinue\n" "\t\t\t}\n" "\t\t\tdefine $delegate superclass -append $d\n" "\t\t}\n" "\t\tobjdefine $class mixin -append $delegate\n" "\t}\n" "\tproc UpdateClassDelegatesAfterClone {originObject targetObject} {\n" "\t\tset originDelegate [DelegateName $originObject]\n" "\t\tset targetDelegate [DelegateName $targetObject]\n" "\t\tif {\n" "\t\t\t[info object isa class $originDelegate]\n" "\t\t\t&& ![info object isa class $targetDelegate]\n" "\t\t} then {\n" "\t\t\tcopy $originDelegate $targetDelegate\n" "\t\t\tobjdefine $targetObject mixin -set \\\n" "\t\t\t\t{*}[lmap c [info object mixin $targetObject] {\n" "\t\t\t\t\tif {$c eq $originDelegate} {set targetDelegate} {set c}\n" "\t\t\t\t}]\n" "\t\t}\n" "\t}\n" "\tproc define::classmethod {name {args {}} {body {}}} {\n" "\t\t::set argc [::llength [::info level 0]]\n" "\t\t::if {$argc == 3} {\n" "\t\t\t::return -code error -errorcode {TCL WRONGARGS} [::format \\\n" "\t\t\t\t{wrong # args: should be \"%s name \?args body\?\"} \\\n" "\t\t\t\t[::lindex [::info level 0] 0]]\n" "\t\t}\n" "\t\t::set cls [::uplevel 1 self]\n" "\t\t::if {$argc == 4} {\n" "\t\t\t::oo::define [::oo::DelegateName $cls] method $name $args $body\n" "\t\t}\n" "\t\t::tailcall forward $name myclass $name\n" "\t}\n" "\tproc define::initialise {body} {\n" "\t\t::set clsns [::info object namespace [::uplevel 1 self]]\n" "\t\t::tailcall apply [::list {} $body $clsns]\n" "\t}\n" "\tnamespace eval define {\n" "\t\t::namespace export initialise\n" "\t\t::namespace eval tmp {::namespace import ::oo::define::initialise}\n" "\t\t::namespace export -clear\n" "\t\t::rename tmp::initialise initialize\n" "\t\t::namespace delete tmp\n" "\t}\n" "\tdefine Slot {\n" "\t\tmethod Get {} {\n" "\t\t\treturn -code error -errorcode {TCLOO ABSTRACT_SLOT} \"unimplemented\"\n" "\t\t}\n" "\t\tmethod Set list {\n" "\t\t\treturn -code error -errorcode {TCLOO ABSTRACT_SLOT} \"unimplemented\"\n" "\t\t}\n" "\t\tmethod -set args {tailcall my Set $args}\n" "\t\tmethod -append args {\n" "\t\t\tset current [uplevel 1 [list [namespace which my] Get]]\n" "\t\t\ttailcall my Set [list {*}$current {*}$args]\n" "\t\t}\n" "\t\tmethod -clear {} {tailcall my Set {}}\n" "\t\tforward --default-operation my -append\n" "\t\tmethod unknown {args} {\n" "\t\t\tset def --default-operation\n" "\t\t\tif {[llength $args] == 0} {\n" "\t\t\t\ttailcall my $def\n" "\t\t\t} elseif {![string match -* [lindex $args 0]]} {\n" "\t\t\t\ttailcall my $def {*}$args\n" "\t\t\t}\n" "\t\t\tnext {*}$args\n" "\t\t}\n" "\t\texport -set -append -clear\n" "\t\tunexport unknown destroy\n" "\t}\n" "\tobjdefine define::superclass forward --default-operation my -set\n" "\tobjdefine define::mixin forward --default-operation my -set\n" "\tobjdefine objdefine::mixin forward --default-operation my -set\n" "\tdefine object method <cloned> {originObject} {\n" "\t\tforeach p [info procs [info object namespace $originObject]::*] {\n" "\t\t\tset args [info args $p]\n" "\t\t\tset idx -1\n" "\t\t\tforeach a $args {\n" "\t\t\t\tif {[info default $p $a d]} {\n" "\t\t\t\t\tlset args [incr idx] [list $a $d]\n" "\t\t\t\t} else {\n" "\t\t\t\t\tlset args [incr idx] [list $a]\n" "\t\t\t\t}\n" "\t\t\t}\n" "\t\t\tset b [info body $p]\n" "\t\t\tset p [namespace tail $p]\n" "\t\t\tproc $p $args $b\n" "\t\t}\n" "\t\tforeach v [info vars [info object namespace $originObject]::*] {\n" "\t\t\tupvar 0 $v vOrigin\n" "\t\t\tnamespace upvar [namespace current] [namespace tail $v] vNew\n" "\t\t\tif {[info exists vOrigin]} {\n" "\t\t\t\tif {[array exists vOrigin]} {\n" "\t\t\t\t\tarray set vNew [array get vOrigin]\n" "\t\t\t\t} else {\n" "\t\t\t\t\tset vNew $vOrigin\n" "\t\t\t\t}\n" "\t\t\t}\n" "\t\t}\n" "\t}\n" "\tdefine class method <cloned> {originObject} {\n" "\t\tnext $originObject\n" "\t\t::oo::UpdateClassDelegatesAfterClone $originObject [self]\n" "\t}\n" "\tclass create singleton {\n" "\t\tsuperclass class\n" "\t\tvariable object\n" "\t\tunexport create createWithNamespace\n" "\t\tmethod new args {\n" "\t\t\tif {![info exists object] || ![info object isa object $object]} {\n" "\t\t\t\tset object [next {*}$args]\n" "\t\t\t\t::oo::objdefine $object {\n" "\t\t\t\t\tmethod destroy {} {\n" "\t\t\t\t\t\t::return -code error -errorcode {TCLOO SINGLETON} \\\n" "\t\t\t\t\t\t\t\"may not destroy a singleton object\"\n" "\t\t\t\t\t}\n" "\t\t\t\t\tmethod <cloned> {originObject} {\n" "\t\t\t\t\t\t::return -code error -errorcode {TCLOO SINGLETON} \\\n" "\t\t\t\t\t\t\t\"may not clone a singleton object\"\n" "\t\t\t\t\t}\n" "\t\t\t\t}\n" "\t\t\t}\n" "\t\t\treturn $object\n" "\t\t}\n" "\t}\n" "\tclass create abstract {\n" "\t\tsuperclass class\n" "\t\tunexport create createWithNamespace new\n" "\t}\n" "}\n" /* !END!: Do not edit above this line. */ ; #endif /* TCL_OO_SCRIPT_H */ /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ |
Added generic/tclOOScript.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 | # tclOOScript.h -- # # This file contains support scripts for TclOO. They are defined here so # that the code can be definitely run even in safe interpreters; TclOO's # core setup is safe. # # Copyright (c) 2012-2018 Donal K. Fellows # Copyright (c) 2013 Andreas Kupries # Copyright (c) 2017 Gerald Lester # # See the file "license.terms" for information on usage and redistribution of # this file, and for a DISCLAIMER OF ALL WARRANTIES. ::namespace eval ::oo { ::namespace path {} # # Commands that are made available to objects by default. # namespace eval Helpers { ::namespace path {} # ------------------------------------------------------------------ # # callback, mymethod -- # # Create a script prefix that calls a method on the current # object. Same operation, two names. # # ------------------------------------------------------------------ proc callback {method args} { list [uplevel 1 {::namespace which my}] $method {*}$args } # Make the [callback] command appear as [mymethod] too. namespace export callback namespace eval tmp {namespace import ::oo::Helpers::callback} namespace export -clear rename tmp::callback mymethod namespace delete tmp # ------------------------------------------------------------------ # # classvariable -- # # Link to a variable in the class of the current object. # # ------------------------------------------------------------------ proc classvariable {name args} { # Get a reference to the class's namespace set ns [info object namespace [uplevel 1 {self class}]] # Double up the list of variable names foreach v [list $name {*}$args] { if {[string match *(*) $v]} { set reason "can't create a scalar variable that looks like an array element" return -code error -errorcode {TCL UPVAR LOCAL_ELEMENT} \ [format {bad variable name "%s": %s} $v $reason] } if {[string match *::* $v]} { set reason "can't create a local variable with a namespace separator in it" return -code error -errorcode {TCL UPVAR INVERTED} \ [format {bad variable name "%s": %s} $v $reason] } lappend vs $v $v } # Lastly, link the caller's local variables to the class's variables tailcall namespace upvar $ns {*}$vs } # ------------------------------------------------------------------ # # link -- # # Make a command that invokes a method on the current object. # The name of the command and the name of the method match by # default. # # ------------------------------------------------------------------ proc link {args} { set ns [uplevel 1 {::namespace current}] foreach link $args { if {[llength $link] == 2} { lassign $link src dst } elseif {[llength $link] == 1} { lassign $link src set dst $src } else { return -code error -errorcode {TCLOO CMDLINK FORMAT} \ "bad link description; must only have one or two elements" } if {![string match ::* $src]} { set src [string cat $ns :: $src] } interp alias {} $src {} ${ns}::my $dst trace add command ${ns}::my delete [list \ ::oo::UnlinkLinkedCommand $src] } return } } # ---------------------------------------------------------------------- # # UnlinkLinkedCommand -- # # Callback used to remove linked command when the underlying mechanism # that supports it is deleted. # # ---------------------------------------------------------------------- proc UnlinkLinkedCommand {cmd args} { if {[namespace which $cmd] ne {}} { rename $cmd {} } } # ---------------------------------------------------------------------- # # DelegateName -- # # Utility that gets the name of the class delegate for a class. It's # trivial, but makes working with them much easier as delegate names are # intentionally hard to create by accident. # # ---------------------------------------------------------------------- proc DelegateName {class} { string cat [info object namespace $class] {:: oo ::delegate} } # ---------------------------------------------------------------------- # # MixinClassDelegates -- # # Support code called *after* [oo::define] inside the constructor of a # class that patches in the appropriate class delegates. # # ---------------------------------------------------------------------- proc MixinClassDelegates {class} { if {![info object isa class $class]} { return } set delegate [DelegateName $class] if {![info object isa class $delegate]} { return } foreach c [info class superclass $class] { set d [DelegateName $c] if {![info object isa class $d]} { continue } define $delegate superclass -append $d } objdefine $class mixin -append $delegate } # ---------------------------------------------------------------------- # # UpdateClassDelegatesAfterClone -- # # Support code that is like [MixinClassDelegates] except for when a # class is cloned. # # ---------------------------------------------------------------------- proc UpdateClassDelegatesAfterClone {originObject targetObject} { # Rebuild the class inheritance delegation class set originDelegate [DelegateName $originObject] set targetDelegate [DelegateName $targetObject] if { [info object isa class $originDelegate] && ![info object isa class $targetDelegate] } then { copy $originDelegate $targetDelegate objdefine $targetObject mixin -set \ {*}[lmap c [info object mixin $targetObject] { if {$c eq $originDelegate} {set targetDelegate} {set c} }] } } # ---------------------------------------------------------------------- # # oo::define::classmethod -- # # Defines a class method. See define(n) for details. # # Note that the ::oo::define namespace is semi-public and a bit weird # anyway, so we don't regard the namespace path as being under control: # fully qualified names are used for everything. # # ---------------------------------------------------------------------- proc define::classmethod {name {args {}} {body {}}} { # Create the method on the class if the caller gave arguments and body ::set argc [::llength [::info level 0]] ::if {$argc == 3} { ::return -code error -errorcode {TCL WRONGARGS} [::format \ {wrong # args: should be "%s name ?args body?"} \ [::lindex [::info level 0] 0]] } ::set cls [::uplevel 1 self] ::if {$argc == 4} { ::oo::define [::oo::DelegateName $cls] method $name $args $body } # Make the connection by forwarding ::tailcall forward $name myclass $name } # ---------------------------------------------------------------------- # # oo::define::initialise, oo::define::initialize -- # # Do specific initialisation for a class. See define(n) for details. # # Note that the ::oo::define namespace is semi-public and a bit weird # anyway, so we don't regard the namespace path as being under control: # fully qualified names are used for everything. # # ---------------------------------------------------------------------- proc define::initialise {body} { ::set clsns [::info object namespace [::uplevel 1 self]] ::tailcall apply [::list {} $body $clsns] } # Make the [initialise] definition appear as [initialize] too namespace eval define { ::namespace export initialise ::namespace eval tmp {::namespace import ::oo::define::initialise} ::namespace export -clear ::rename tmp::initialise initialize ::namespace delete tmp } # ---------------------------------------------------------------------- # # Slot -- # # The class of slot operations, which are basically lists at the low # level of TclOO; this provides a more consistent interface to them. # # ---------------------------------------------------------------------- define Slot { # ------------------------------------------------------------------ # # Slot Get -- # # Basic slot getter. Retrieves the contents of the slot. # Particular slots must provide concrete non-erroring # implementation. # # ------------------------------------------------------------------ method Get {} { return -code error -errorcode {TCLOO ABSTRACT_SLOT} "unimplemented" } # ------------------------------------------------------------------ # # Slot Set -- # # Basic slot setter. Sets the contents of the slot. Particular # slots must provide concrete non-erroring implementation. # # ------------------------------------------------------------------ method Set list { return -code error -errorcode {TCLOO ABSTRACT_SLOT} "unimplemented" } # ------------------------------------------------------------------ # # Slot -set, -append, -clear, --default-operation -- # # Standard public slot operations. If a slot can't figure out # what method to call directly, it uses --default-operation. # # ------------------------------------------------------------------ method -set args {tailcall my Set $args} method -append args { set current [uplevel 1 [list [namespace which my] Get]] tailcall my Set [list {*}$current {*}$args] } method -clear {} {tailcall my Set {}} # Default handling forward --default-operation my -append method unknown {args} { set def --default-operation if {[llength $args] == 0} { tailcall my $def } elseif {![string match -* [lindex $args 0]]} { tailcall my $def {*}$args } next {*}$args } # Set up what is exported and what isn't export -set -append -clear unexport unknown destroy } # Set the default operation differently for these slots objdefine define::superclass forward --default-operation my -set objdefine define::mixin forward --default-operation my -set objdefine objdefine::mixin forward --default-operation my -set # ---------------------------------------------------------------------- # # oo::object <cloned> -- # # Handler for cloning objects that clones basic bits (only!) of the # object's namespace. Non-procedures, traces, sub-namespaces, etc. need # more complex (and class-specific) handling. # # ---------------------------------------------------------------------- define object method <cloned> {originObject} { # Copy over the procedures from the original namespace foreach p [info procs [info object namespace $originObject]::*] { set args [info args $p] set idx -1 foreach a $args { if {[info default $p $a d]} { lset args [incr idx] [list $a $d] } else { lset args [incr idx] [list $a] } } set b [info body $p] set p [namespace tail $p] proc $p $args $b } # Copy over the variables from the original namespace foreach v [info vars [info object namespace $originObject]::*] { upvar 0 $v vOrigin namespace upvar [namespace current] [namespace tail $v] vNew if {[info exists vOrigin]} { if {[array exists vOrigin]} { array set vNew [array get vOrigin] } else { set vNew $vOrigin } } } # General commands, sub-namespaces and advancd variable config (traces, # etc) are *not* copied over. Classes that want that should do it # themselves. } # ---------------------------------------------------------------------- # # oo::class <cloned> -- # # Handler for cloning classes, which fixes up the delegates. # # ---------------------------------------------------------------------- define class method <cloned> {originObject} { next $originObject # Rebuild the class inheritance delegation class ::oo::UpdateClassDelegatesAfterClone $originObject [self] } # ---------------------------------------------------------------------- # # oo::singleton -- # # A metaclass that is used to make classes that only permit one instance # of them to exist. See singleton(n). # # ---------------------------------------------------------------------- class create singleton { superclass class variable object unexport create createWithNamespace method new args { if {![info exists object] || ![info object isa object $object]} { set object [next {*}$args] ::oo::objdefine $object { method destroy {} { ::return -code error -errorcode {TCLOO SINGLETON} \ "may not destroy a singleton object" } method <cloned> {originObject} { ::return -code error -errorcode {TCLOO SINGLETON} \ "may not clone a singleton object" } } } return $object } } # ---------------------------------------------------------------------- # # oo::abstract -- # # A metaclass that is used to make classes that can't be directly # instantiated. See abstract(n). # # ---------------------------------------------------------------------- class create abstract { superclass class unexport create createWithNamespace new } } # Local Variables: # mode: tcl # c-basic-offset: 4 # fill-column: 78 # End: |
Changes to tests/oo.test.
︙ | ︙ | |||
336 337 338 339 340 341 342 | lappend x [info class $cmd ::oo::$initial] } } foreach initial {object class Slot} { lappend x [info object class ::oo::$initial] } return $x | | | | 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 | lappend x [info class $cmd ::oo::$initial] } } foreach initial {object class Slot} { lappend x [info object class ::oo::$initial] } return $x }] {lsort [lmap y $x {if {[string match *::delegate $y]} continue; set y}]} } -cleanup { interp delete $fresh } -result {{} {::oo::Slot ::oo::abstract ::oo::class ::oo::object ::oo::singleton} {::oo::define::filter ::oo::define::mixin ::oo::define::superclass ::oo::define::variable ::oo::objdefine::filter ::oo::objdefine::mixin ::oo::objdefine::variable} {::oo::Slot ::oo::class} {::oo::abstract ::oo::singleton} {} {} {} {} {} ::oo::object ::oo::object ::oo::class ::oo::class ::oo::class} test oo-2.1 {basic test of OO functionality: constructor} -setup { # This is a bit complex because it needs to run in a sub-interp as # we're modifying the root object class's constructor interp create subinterp subinterp eval { package require TclOO |
︙ | ︙ | |||
4841 4842 4843 4844 4845 4846 4847 | unexport foo } lappend result {*}[lmap s {public unexported private} { info class methods cls -scope $s}] } -cleanup { cls destroy } -result {{} {} foo {} foo {}} | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 | unexport foo } lappend result {*}[lmap s {public unexported private} { info class methods cls -scope $s}] } -cleanup { cls destroy } -result {{} {} foo {} foo {}} test oo-41.1 {TIP 478: myclass command, including class morphing} -setup { oo::class create parent set result {} } -body { oo::class create cls1 { superclass parent self method count {} { my variable c incr c } method act {} { myclass count } } cls1 create x lappend result [x act] [x act] cls1 create y lappend result [y act] [y act] [x act] oo::class create cls2 { superclass cls1 self method count {} { my variable d expr {1.0 * [incr d]} } } oo::objdefine x {class cls2} lappend result [x act] [y act] [x act] [y act] } -cleanup { parent destroy } -result {1 2 3 4 5 1.0 6 2.0 7} test oo-41.2 {TIP 478: myclass command cleanup} -setup { oo::class create parent set result {} } -body { oo::class create cls1 { superclass parent self method hi {} { return "this is [self]" } method hi {} { return "this is [self]" } } cls1 create x rename [info object namespace x]::my foo rename [info object namespace x]::myclass bar lappend result [cls1 hi] [x hi] [foo hi] [bar hi] x destroy lappend result [catch {foo hi}] [catch {bar hi}] } -cleanup { parent destroy } -result {{this is ::cls1} {this is ::x} {this is ::x} {this is ::cls1} 1 1} test oo-41.3 {TIP 478: myclass command calls unexported methods, via forward} -setup { oo::class create parent set result {} } -body { oo::class create cls1 { superclass parent self method Hi {} { return "this is [self]" } forward poke myclass Hi } cls1 create x lappend result [catch {cls1 Hi}] [x poke] } -cleanup { parent destroy } -result {1 {this is ::cls1}} cleanupTests return # Local Variables: # mode: tcl # End: |
Added tests/ooUtil.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 | # This file contains a collection of tests for functionality originally # sourced from the ooutil package in Tcllib. Sourcing this file into Tcl runs # the tests and generates output for errors. No output means no errors were # found. # # Copyright (c) 2014-2016 Andreas Kupries # Copyright (c) 2018 Donal K. Fellows # # See the file "license.terms" for information on usage and redistribution of # this file, and for a DISCLAIMER OF ALL WARRANTIES. package require TclOO 1.0.3 package require tcltest 2 if {"::tcltest" in [namespace children]} { namespace import -force ::tcltest::* } test ooUtil-1.1 {TIP 478: classmethod} -setup { oo::class create parent } -body { oo::class create ActiveRecord { superclass parent classmethod find args { return "[self] called with arguments: $args" } } oo::class create Table { superclass ActiveRecord } Table find foo bar } -cleanup { parent destroy } -result {::Table called with arguments: foo bar} test ooUtil-1.2 {TIP 478: classmethod in namespace} -setup { namespace eval ::testns {} } -body { namespace eval ::testns { oo::class create ActiveRecord { classmethod find args { return "[self] called with arguments: $args" } } oo::class create Table { superclass ActiveRecord } } testns::Table find foo bar } -cleanup { namespace delete ::testns } -result {::testns::Table called with arguments: foo bar} test ooUtil-1.3 {TIP 478: classmethod must not interfere with constructor signatures} -setup { oo::class create parent } -body { oo::class create TestClass { superclass oo::class parent self method create {name ignore body} { next $name $body } } TestClass create okay {} {} } -cleanup { parent destroy } -result {::okay} test ooUtil-1.4 {TIP 478: classmethod with several inheritance levels} -setup { oo::class create parent } -body { oo::class create ActiveRecord { superclass parent classmethod find args { return "[self] called with arguments: $args" } } oo::class create Table { superclass ActiveRecord } oo::class create SubTable { superclass Table } SubTable find foo bar } -cleanup { parent destroy } -result {::SubTable called with arguments: foo bar} test ooUtil-1.5 {TIP 478: classmethod and instances} -setup { oo::class create parent } -body { oo::class create ActiveRecord { superclass parent classmethod find args { return "[self] called with arguments: $args" } } oo::class create Table { superclass ActiveRecord } set t [Table new] $t find 1 2 3 } -cleanup { parent destroy } -result {::Table called with arguments: 1 2 3} test ooUtil-1.6 {TIP 478: classmethod and instances} -setup { oo::class create parent } -body { oo::class create ActiveRecord { superclass parent classmethod find args { return "[self] called with arguments: $args" } } oo::class create Table { superclass ActiveRecord unexport find } set t [Table new] $t find 1 2 3 } -returnCodes error -cleanup { parent destroy } -match glob -result {unknown method "find": must be *} test ooUtil-1.7 {} -setup { oo::class create parent } -body { oo::class create Foo { superclass parent classmethod bar {} { puts "This is in the class; self is [self]" my meee } classmethod meee {} { puts "This is meee" } } oo::class create Grill { superclass Foo classmethod meee {} { puts "This is meee 2" } } list [Foo bar] [Grill bar] [[Foo new] bar] [[Grill new] bar] } -cleanup { parent destroy } -result {{} {} {} {}} -output "This is in the class; self is ::Foo\nThis is meee\nThis is in the class; self is ::Grill\nThis is meee 2\nThis is in the class; self is ::Foo\nThis is meee\nThis is in the class; self is ::Grill\nThis is meee 2\n" # Two tests to confirm that we correctly initialise the scripted part of TclOO # in child interpreters. This is slightly tricky at the implementation level # because we cannot count on either [source] or [open] being available. test ooUtil-1.8 {TIP 478: classmethod in child interp} -setup { set childinterp [interp create] } -body { $childinterp eval { oo::class create ActiveRecord { classmethod find args { return "[self] called with arguments: $args" } } oo::class create Table { superclass ActiveRecord } # This is confirming that this is not the master interpreter list [Table find foo bar] [info globals childinterp] } } -cleanup { interp delete $childinterp } -result {{::Table called with arguments: foo bar} {}} test ooUtil-1.9 {TIP 478: classmethod in safe child interp} -setup { set safeinterp [interp create -safe] } -body { $safeinterp eval { oo::class create ActiveRecord { classmethod find args { return "[self] called with arguments: $args" } } oo::class create Table { superclass ActiveRecord } # This is confirming that this is a (basic) safe interpreter list [Table find foo bar] [info commands source] } } -cleanup { interp delete $safeinterp } -result {{::Table called with arguments: foo bar} {}} test ooUtil-2.1 {TIP 478: callback generation} -setup { oo::class create parent } -body { oo::class create c { superclass parent method CallMe {} { return ok,[self] } method makeCall {} { return [callback CallMe] } } c create ::context set cb [context makeCall] {*}$cb } -cleanup { parent destroy } -result {ok,::context} test ooUtil-2.2 {TIP 478: callback generation} -setup { oo::class create parent } -body { oo::class create c { superclass parent method CallMe {a b c} { return ok,[self],$a,$b,$c } method makeCall {b} { return [callback CallMe 123 $b] } } c create ::context set cb [context makeCall "a b c"] {*}$cb PQR } -cleanup { parent destroy } -result {ok,::context,123,a b c,PQR} test ooUtil-2.3 {TIP 478: callback generation, alternate name} -setup { oo::class create parent } -body { oo::class create c { superclass parent method CallMe {} { return ok,[self] } method makeCall {} { return [mymethod CallMe] } } c create ::context set cb [context makeCall] {*}$cb } -cleanup { parent destroy } -result {ok,::context} test ooUtil-2.4 {TIP 478: callback generation, alternate name} -setup { oo::class create parent } -body { oo::class create c { superclass parent method CallMe {a b c} { return ok,[self],$a,$b,$c } method makeCall {b} { return [mymethod CallMe 123 $b] } } c create ::context set cb [context makeCall "a b c"] {*}$cb PQR } -cleanup { parent destroy } -result {ok,::context,123,a b c,PQR} test ooUtil-2.5 {TIP 478: callbacks and method lifetime} -setup { oo::class create parent } -body { oo::class create c { superclass parent method makeCall {b} { return [callback CallMe 123 $b] } } c create ::context set cb [context makeCall "a b c"] set result [list [catch {{*}$cb PQR} msg] $msg] oo::objdefine context { method CallMe {a b c} { return ok,[self],$a,$b,$c } } lappend result [{*}$cb PQR] } -cleanup { parent destroy } -result {1 {unknown method "CallMe": must be <cloned>, destroy, eval, makeCall, unknown, variable or varname} {ok,::context,123,a b c,PQR}} test ooUtil-2.6 {TIP 478: callback use case} -setup { oo::class create parent unset -nocomplain x } -body { oo::class create c { superclass parent variable count constructor {var} { set count 0 upvar 1 $var v trace add variable v write [callback TraceCallback] } method count {} {return $count} method TraceCallback {name1 name2 op} { incr count } } set o [c new x] for {set x 0} {$x < 5} {incr x} {} $o count } -cleanup { unset -nocomplain x parent destroy } -result 6 test ooUtil-3.1 {TIP 478: class initialisation} -setup { oo::class create parent catch {rename ::foobar-3.1 {}} } -body { oo::class create ::cls { superclass parent initialise { proc foobar-3.1 {} {return ok} } method calls {} { list [catch foobar-3.1 msg] $msg \ [namespace eval [info object namespace [self class]] foobar-3.1] } } [cls new] calls } -cleanup { parent destroy } -result {1 {invalid command name "foobar-3.1"} ok} test ooUtil-3.2 {TIP 478: class variables} -setup { oo::class create parent catch {rename ::foobar-3.1 {}} } -body { oo::class create ::cls { superclass parent initialise { variable x 123 } method call {} { classvariable x incr x } } cls create a cls create b cls create c list [a call] [b call] [c call] [a call] [b call] [c call] } -cleanup { parent destroy } -result {124 125 126 127 128 129} test ooUtil-3.3 {TIP 478: class initialisation} -setup { oo::class create parent catch {rename ::foobar-3.3 {}} } -body { oo::class create ::cls { superclass parent initialize { proc foobar-3.3 {} {return ok} } method calls {} { list [catch foobar-3.3 msg] $msg \ [namespace eval [info object namespace [self class]] foobar-3.3] } } [cls new] calls } -cleanup { parent destroy } -result {1 {invalid command name "foobar-3.3"} ok} test ooUtil-3.4 {TIP 478: class initialisation} -setup { oo::class create parent catch {rename ::appendToResultVar {}} proc ::appendToResultVar args { lappend ::result {*}$args } set result {} } -body { trace add execution oo::define::initialise enter appendToResultVar oo::class create ::cls { superclass parent initialize {proc xyzzy {} {}} } return $result } -cleanup { catch { trace remove execution oo::define::initialise enter appendToResultVar } rename ::appendToResultVar {} parent destroy } -result {{initialize {proc xyzzy {} {}}} enter} test ooUtil-3.5 {TIP 478: class initialisation} -body { oo::define oo::object { ::list [::namespace which initialise] [::namespace which initialize] \ [::namespace origin initialise] [::namespace origin initialize] } } -result {::oo::define::initialise ::oo::define::initialize ::oo::define::initialise ::oo::define::initialise} test ooUtil-4.1 {TIP 478: singleton} -setup { oo::class create parent } -body { oo::singleton create xyz { superclass parent } set x [xyz new] set y [xyz new] set z [xyz new] set code [catch {$x destroy} msg] set p [xyz new] lappend code [catch {rename $x ""}] set q [xyz new] string map [list $x ONE $q TWO] [list {*}$code $x $y $z $p $q [xyz new]] } -cleanup { parent destroy } -result {1 0 ONE ONE ONE ONE TWO TWO} test ooUtil-4.2 {TIP 478: singleton errors} -setup { oo::class create parent } -body { oo::singleton create xyz { superclass parent } [xyz new] destroy } -returnCodes error -cleanup { parent destroy } -result {may not destroy a singleton object} test ooUtil-4.3 {TIP 478: singleton errors} -setup { oo::class create parent } -body { oo::singleton create xyz { superclass parent } oo::copy [xyz new] } -returnCodes error -cleanup { parent destroy } -result {may not clone a singleton object} test ooUtil-5.1 {TIP 478: abstract} -setup { oo::class create parent } -body { oo::abstract create xyz { superclass parent method foo {} {return 123} } oo::class create pqr { superclass xyz method bar {} {return 456} } set codes [list [catch {xyz new}] [catch {xyz create x}] [catch {xyz createWithNamespace x y}]] set x [pqr new] set y [pqr create ::y] lappend codes [$x foo] [$x bar] $y } -cleanup { parent destroy } -result {1 1 1 123 456 ::y} test ooUtil-6.1 {TIP 478: classvarable} -setup { oo::class create parent } -body { oo::class create xyz { superclass parent initialise { variable x 1 y 2 } method a {} { classvariable x incr x } method b {} { classvariable y incr y } method c {} { classvariable x y list $x $y } } set p [xyz new] set q [xyz new] set result [list [$p c] [$q c]] $p a $q b lappend result [[xyz new] c] } -cleanup { parent destroy } -result {{1 2} {1 2} {2 3}} test ooUtil-6.2 {TIP 478: classvarable error case} -setup { oo::class create parent } -body { oo::class create xyz { superclass parent method a {} { classvariable x(1) incr x(1) } } set p [xyz new] set q [xyz new] list [$p a] [$q a] } -returnCodes error -cleanup { parent destroy } -result {bad variable name "x(1)": can't create a scalar variable that looks like an array element} test ooUtil-6.3 {TIP 478: classvarable error case} -setup { oo::class create parent } -body { oo::class create xyz { superclass parent method a {} { classvariable ::x incr x } } set p [xyz new] set q [xyz new] list [$p a] [$q a] } -returnCodes error -cleanup { parent destroy } -result {bad variable name "::x": can't create a local variable with a namespace separator in it} test ooUtil-7.1 {TIP 478: link calling pattern} -setup { oo::class create parent } -body { oo::class create cls { superclass parent method foo {} {return "in foo of [self]"} method Bar {} {return "in bar of [self]"} method Grill {} {return "in grill of [self]"} export eval constructor {} { link foo link {bar Bar} {grill Grill} } } cls create o o eval {list [foo] [bar] [grill]} } -cleanup { parent destroy } -result {{in foo of ::o} {in bar of ::o} {in grill of ::o}} test ooUtil-7.2 {TIP 478: link removed when [my] disappears} -setup { oo::class create parent } -body { oo::class create cls { superclass parent method foo {} {return "in foo of [self]"} constructor {cmd} { link [list ::$cmd foo] } } cls create o pqr list [o foo] [pqr] [rename [info object namespace o]::my {}] [catch pqr msg] $msg } -cleanup { parent destroy } -result {{in foo of ::o} {in foo of ::o} {} 1 {invalid command name "pqr"}} # Tests that verify issues detected with the tcllib version of the code test ooUtil-tcllib-ticket-b3577ed586 {test scoping of delegation in oo::class.Delegate } -setup { oo::class create animal {} namespace eval ::ooutiltest { oo::class create pet { superclass animal } } } -body { namespace eval ::ooutiltest { oo::class create dog { superclass pet } } } -cleanup { namespace delete ooutiltest rename animal {} } -result {::ooutiltest::dog} test ooUtil-tcllib-ticket-fe7a0e0a3a {classmethod must not interfere with constructor signatures} -setup { oo::class create TestClass { superclass oo::class self method create {name ignore body} { next $name $body } } } -body { TestClass create okay {} {} } -cleanup { rename TestClass {} } -result {::okay} cleanupTests return # Local Variables: # fill-column: 78 # mode: tcl # End: |
Added tools/makeHeader.tcl.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | # makeHeader.tcl -- # # This script generates embeddable C source (in a .h file) from a .tcl # script. # # Copyright (c) 2018 Donal K. Fellows # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. package require Tcl 8.6 namespace eval makeHeader { #################################################################### # # mapSpecial -- # Transform a single line so that it is able to be put in a C string. # proc mapSpecial {str} { # All Tcl metacharacters and key C backslash sequences set MAP { \" \\\\\" \\ \\\\\\\\ $ \\$ [ \\[ ] \\] ' \\\\' ? \\\\? \a \\\\a \b \\\\b \f \\\\f \n \\\\n \r \\\\r \t \\\\t \v \\\\v } set XFORM {[format \\\\\\\\u%04x {*}[scan & %c]]} subst [regsub -all {[^\u0020-\u007e]} [string map $MAP $str] $XFORM] } #################################################################### # # compactLeadingSpaces -- # Converts the leading whitespace on a line into a more compact form. # proc compactLeadingSpaces {line} { set line [string map {\t { }} [string trimright $line]] if {[regexp {^[ ]+} $line spaces]} { regsub -all {[ ]{4}} $spaces \t replace set len [expr {[string length $spaces] - 1}] set line [string replace $line 0 $len $replace] } return $line } #################################################################### # # processScript -- # Transform a whole sequence of lines with [mapSpecial]. # proc processScript {scriptLines} { lmap line $scriptLines { # Skip blank and comment lines; they're there in the original # sources so we don't need to copy them over. if {[regexp {^\s*(?:#|$)} $line]} continue format {"%s"} [mapSpecial [compactLeadingSpaces $line]\n] } } #################################################################### # # updateTemplate -- # Rewrite a template to contain the content from the input script. # proc updateTemplate {dataVar scriptLines} { set BEGIN "*!BEGIN!: Do not edit below this line.*" set END "*!END!: Do not edit above this line.*" upvar 1 $dataVar data set from [lsearch -glob $data $BEGIN] set to [lsearch -glob $data $END] if {$from == -1 || $to == -1 || $from >= $to} { throw BAD "not a template" } set data [lreplace $data $from+1 $to-1 {*}[processScript $scriptLines]] } #################################################################### # # stripSurround -- # Removes the header and footer comments from a (line-split list of # lines of) Tcl script code. # proc stripSurround {lines} { set RE {^\s*$|^#} set state 0 set lines [lmap line [lreverse $lines] { if {!$state && [regexp $RE $line]} continue { set state 1 set line } }] return [lmap line [lreverse $lines] { if {$state && [regexp $RE $line]} continue { set state 0 set line } }] } #################################################################### # # updateTemplateFile -- # Rewrites a template file with the lines of the given script. # proc updateTemplateFile {headerFile scriptLines} { set f [open $headerFile "r+"] try { set content [split [chan read -nonewline $f] "\n"] updateTemplate content [stripSurround $scriptLines] chan seek $f 0 chan puts $f [join $content \n] chan truncate $f } trap BAD msg { # Add the filename to the message throw BAD "${headerFile}: $msg" } finally { chan close $f } } #################################################################### # # readScript -- # Read a script from a file and return its lines. # proc readScript {script} { set f [open $script] try { chan configure $f -encoding utf-8 return [split [string trim [chan read $f]] "\n"] } finally { chan close $f } } #################################################################### # # run -- # The main program of this script. # proc run {args} { try { if {[llength $args] != 2} { throw ARGS "inputTclScript templateFile" } lassign $args inputTclScript templateFile puts "Inserting $inputTclScript into $templateFile" set scriptLines [readScript $inputTclScript] updateTemplateFile $templateFile $scriptLines exit 0 } trap ARGS msg { puts stderr "wrong # args: should be \"[file tail $::argv0] $msg\"" exit 2 } trap BAD msg { puts stderr $msg exit 1 } trap POSIX msg { puts stderr $msg exit 1 } on error {- opts} { puts stderr [dict get $opts -errorinfo] exit 3 } } } ######################################################################## # # Launch the main program # if {[info script] eq $::argv0} { makeHeader::run {*}$::argv } # Local-Variables: # mode: tcl # fill-column: 78 # End: |
Changes to unix/Makefile.in.
︙ | ︙ | |||
255 256 257 258 259 260 261 262 263 264 265 266 267 268 | #-------------------------------------------------------------------------- # The information below is usually usable as is. The configure script won't # modify it and it only exists to make working around selected rare system # configurations easier. #-------------------------------------------------------------------------- GDB = gdb TRACE = strace TRACE_OPTS = VALGRIND = valgrind VALGRINDARGS = --tool=memcheck --num-callers=24 \ --leak-resolution=high --leak-check=yes --show-reachable=yes -v \ --suppressions=$(TOOL_DIR)/valgrind_suppress | > | 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 | #-------------------------------------------------------------------------- # The information below is usually usable as is. The configure script won't # modify it and it only exists to make working around selected rare system # configurations easier. #-------------------------------------------------------------------------- GDB = gdb LLDB = lldb TRACE = strace TRACE_OPTS = VALGRIND = valgrind VALGRINDARGS = --tool=memcheck --num-callers=24 \ --leak-resolution=high --leak-check=yes --show-reachable=yes -v \ --suppressions=$(TOOL_DIR)/valgrind_suppress |
︙ | ︙ | |||
727 728 729 730 731 732 733 734 735 736 737 738 739 740 | gdb-test: ${TCLTEST_EXE} @echo "set env @LD_LIBRARY_PATH_VAR@=`pwd`:$${@LD_LIBRARY_PATH_VAR@}" > gdb.run @echo "set env TCL_LIBRARY=${TCL_BUILDTIME_LIBRARY}" >> gdb.run @echo "set args $(TOP_DIR)/tests/all.tcl $(TESTFLAGS) -singleproc 1" >> gdb.run $(GDB) ./${TCLTEST_EXE} --command=gdb.run rm gdb.run # Useful target to launch a built tcltest with the proper path,... runtest: ${TCLTEST_EXE} $(SHELL_ENV) ./${TCLTEST_EXE} # Useful target for running the test suite with an unwritable current # directory... | > > > > > > | 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 | gdb-test: ${TCLTEST_EXE} @echo "set env @LD_LIBRARY_PATH_VAR@=`pwd`:$${@LD_LIBRARY_PATH_VAR@}" > gdb.run @echo "set env TCL_LIBRARY=${TCL_BUILDTIME_LIBRARY}" >> gdb.run @echo "set args $(TOP_DIR)/tests/all.tcl $(TESTFLAGS) -singleproc 1" >> gdb.run $(GDB) ./${TCLTEST_EXE} --command=gdb.run rm gdb.run lldb-test: ${TCLTEST_EXE} @echo "settings set target.env-vars @LD_LIBRARY_PATH_VAR@=`pwd`:$${@LD_LIBRARY_PATH_VAR@}" > lldb.run @echo "settings set target.env-vars TCL_LIBRARY=${TCL_BUILDTIME_LIBRARY}" >> lldb.run $(LLDB) --source lldb.run ./${TCLTEST_EXE} -- $(TOP_DIR)/tests/all.tcl $(TESTFLAGS) -singleproc 1 rm lldb.run # Useful target to launch a built tcltest with the proper path,... runtest: ${TCLTEST_EXE} $(SHELL_ENV) ./${TCLTEST_EXE} # Useful target for running the test suite with an unwritable current # directory... |
︙ | ︙ | |||
1218 1219 1220 1221 1222 1223 1224 | tclNamesp.o: $(GENERIC_DIR)/tclNamesp.c $(COMPILEHDR) $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclNamesp.c tclNotify.o: $(GENERIC_DIR)/tclNotify.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclNotify.c | | | 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 | tclNamesp.o: $(GENERIC_DIR)/tclNamesp.c $(COMPILEHDR) $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclNamesp.c tclNotify.o: $(GENERIC_DIR)/tclNotify.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclNotify.c tclOO.o: $(GENERIC_DIR)/tclOO.c $(GENERIC_DIR)/tclOOScript.h $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclOO.c tclOOBasic.o: $(GENERIC_DIR)/tclOOBasic.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclOOBasic.c tclOOCall.o: $(GENERIC_DIR)/tclOOCall.c $(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tclOOCall.c |
︙ | ︙ | |||
1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 | @echo "This warning can be safely ignored, do not report as a bug!" $(GENERIC_DIR)/tclOOStubInit.c: $(GENERIC_DIR)/tclOO.decls @echo "Warning: tclOOStubInit.c may be out of date." @echo "Developers may want to run \"make genstubs\" to regenerate." @echo "This warning can be safely ignored, do not report as a bug!" genstubs: $(NATIVE_TCLSH) $(TOOL_DIR)/genStubs.tcl $(GENERIC_DIR) \ $(GENERIC_DIR)/tcl.decls $(GENERIC_DIR)/tclInt.decls \ $(GENERIC_DIR)/tclTomMath.decls $(NATIVE_TCLSH) $(TOOL_DIR)/genStubs.tcl $(GENERIC_DIR) \ $(GENERIC_DIR)/tclOO.decls # # Target to check that all exported functions have an entry in the stubs # tables. # checkstubs: $(TCL_LIB_FILE) -@for i in `nm -p $(TCL_LIB_FILE) \ | > > > > > > > > > | 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 | @echo "This warning can be safely ignored, do not report as a bug!" $(GENERIC_DIR)/tclOOStubInit.c: $(GENERIC_DIR)/tclOO.decls @echo "Warning: tclOOStubInit.c may be out of date." @echo "Developers may want to run \"make genstubs\" to regenerate." @echo "This warning can be safely ignored, do not report as a bug!" $(GENERIC_DIR)/tclOOScript.h: $(GENERIC_DIR)/tclOOScript.tcl @echo "Warning: tclOOScript.h may be out of date." @echo "Developers may want to run \"make genscript\" to regenerate." @echo "This warning can be safely ignored, do not report as a bug!" genstubs: $(NATIVE_TCLSH) $(TOOL_DIR)/genStubs.tcl $(GENERIC_DIR) \ $(GENERIC_DIR)/tcl.decls $(GENERIC_DIR)/tclInt.decls \ $(GENERIC_DIR)/tclTomMath.decls $(NATIVE_TCLSH) $(TOOL_DIR)/genStubs.tcl $(GENERIC_DIR) \ $(GENERIC_DIR)/tclOO.decls genscript: $(NATIVE_TCLSH) $(TOOL_DIR)/makeHeader.tcl \ $(GENERIC_DIR)/tclOOScript.tcl $(GENERIC_DIR)/tclOOScript.h # # Target to check that all exported functions have an entry in the stubs # tables. # checkstubs: $(TCL_LIB_FILE) -@for i in `nm -p $(TCL_LIB_FILE) \ |
︙ | ︙ |