Index: TODO =================================================================== diff -u -N -rafbb465916db08e038e559241416749cd042b186 -rf31c1a01c6a389f693b8db0f2204cbb46180fef1 --- TODO (.../TODO) (revision afbb465916db08e038e559241416749cd042b186) +++ TODO (.../TODO) (revision f31c1a01c6a389f693b8db0f2204cbb46180fef1) @@ -5515,7 +5515,7 @@ - updated "/cls/ info filters" and "/obj/ info object filters" - dropped "/cls/ info mixin guard" and "/obj/ info object mixin guard" dropped "/cls/ info filter guard" and "/obj/ info object filter guard" - (use "-guard option insteads)y + (use "-guard option instead) - updated "/cls/ mixins ...", "/obj/ object mixins ...", "/cls/ filteres ...", "/obj/ object filters ..." @@ -5551,7 +5551,7 @@ make "DTPLITE=/usr/local/ns/bin/tclsh8.5 /usr/local/ns/bin/dtplite" man - regenerate documentation -- bump verison number to 2.0.0 (also in .man files) +- bump version number to 2.0.0 (also in .man files) - write body-blocks of if on separate lines - change variable name "validCscPtr" to "isValidCsc", since @@ -5575,7 +5575,7 @@ pt. 2: NsfParamDefs.slotObj and its memory-management statements all over remain in place, to be reviewed. -- removed NsfParamDefs.slotObj (and single occurance for memory-management) +- removed NsfParamDefs.slotObj (and single occurrence for memory-management) since it is not used for the time being - fix potential bug on tcl-triggered cmd-delete operations, where destroy returns non-TCL_OK and name of the object could not be @@ -5591,15 +5591,26 @@ - update licenses - reduce implicit conversions -- wite body of if-statements as blocks +- write body of if-statements as blocks - whitespace changes - prefer boolean expressions - add likely/unlikely hints +- added optional paramter "-target" for serializer to ease + changing name of object in serialization + +- new command nsf::method::forward::property in analogy to nsf::method::property + for reading+writing introspection of forwarders (important for serializer, + when different target objects are specified, to map the per-object forwarder) +- extended regression test +- bumped version number of serializer to 2.1 + + + ======================================================================== TODO: +- maybe more complete handling of other forward "properties" - - should we change "/obj/ info lookup syntax /methodName/" to return obj and method as well? (similar to "info method syntax /methodName/") Index: generic/nsf.c =================================================================== diff -u -N -rafbb465916db08e038e559241416749cd042b186 -rf31c1a01c6a389f693b8db0f2204cbb46180fef1 --- generic/nsf.c (.../nsf.c) (revision afbb465916db08e038e559241416749cd042b186) +++ generic/nsf.c (.../nsf.c) (revision f31c1a01c6a389f693b8db0f2204cbb46180fef1) @@ -23429,7 +23429,7 @@ ClientData clientData = (cmd != NULL) ? Tcl_Command_objClientData(cmd) : NULL; ForwardCmdClientData *tcd = (ForwardCmdClientData *)clientData; - if (tcd && Tcl_Command_objProc(cmd) == NsfForwardMethod) { + if (tcd != NULL && Tcl_Command_objProc(cmd) == NsfForwardMethod) { Tcl_Obj *listObj = Tcl_NewListObj(0, NULL); AppendForwardDefinition(interp, listObj, tcd); @@ -25292,6 +25292,83 @@ /* +cmd "method::forward::property" NsfForwardPropertyCmd { + {-argName "object" -required 1 -type object} + {-argName "-per-object" -required 0 -nrargs 0 -type switch} + {-argName "methodName" -required 1 -type tclobj} + {-argName "forwardProperty" -required 1 -type "target|verbose"} + {-argName "value" -type tclobj} +} +*/ +static int +NsfForwardPropertyCmd(Tcl_Interp *interp, NsfObject *object, int withPer_object, + Tcl_Obj *methodObj, int methodproperty, Tcl_Obj *valueObj) { + ForwardCmdClientData *tcd; + Tcl_ObjCmdProc *procPtr; + Tcl_Command cmd; + NsfObject *defObject; + NsfClass *cl; + int fromClassNS; + + assert(interp != NULL); + assert(object != NULL); + assert(methodObj != NULL); + + cl = withPer_object == 0 && NsfObjectIsClass(object) ? (NsfClass *)object : NULL; + fromClassNS = cl != NULL; + + cmd = ResolveMethodName(interp, (cl != NULL) ? cl->nsPtr : object->nsPtr, methodObj, + NULL, NULL, &defObject, NULL, &fromClassNS); + + if (unlikely(cmd == NULL)) { + return NsfPrintError(interp, "cannot lookup %s method '%s' for %s", + cl == NULL ? "object " : "", + ObjStr(methodObj), ObjectName(object)); + } + + procPtr = Tcl_Command_objProc(cmd); + if (procPtr != NsfForwardMethod) { + return NsfPrintError(interp, "%s is not a forwarder method", + ObjStr(methodObj)); + } + + tcd = (ForwardCmdClientData *)Tcl_Command_objClientData(cmd); + if (tcd == NULL) { + return NsfPrintError(interp, "forwarder method has no client data"); + } + + switch (methodproperty) { + case ForwardpropertyTargetIdx: + if (valueObj != NULL) { + DECR_REF_COUNT(tcd->cmdName); + INCR_REF_COUNT(valueObj); + tcd->cmdName = valueObj; + } + // should we return old or new value? /class/set/... return new value, /configure/ often the old. + Tcl_SetObjResult(interp, tcd->cmdName); + break; + + case ForwardpropertyPrefixIdx: + if (valueObj != NULL) { + DECR_REF_COUNT(tcd->prefix); + INCR_REF_COUNT(valueObj); + tcd->prefix = valueObj; + } + Tcl_SetObjResult(interp, tcd->prefix); + break; + + case ForwardpropertyVerboseIdx: + if (valueObj != NULL) { + Tcl_GetBooleanFromObj(interp, valueObj, &tcd->verbose); + } + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(tcd->verbose)); + break; + } + + return TCL_OK; +} + +/* cmd ::method::property NsfMethodPropertyCmd { {-argName "object" -required 1 -type object} {-argName "-per-object"} @@ -25438,6 +25515,7 @@ return TCL_OK; } + /* cmd "method::registered" NsfMethodRegisteredCmd { {-argName "handle" -required 1 -type tclobj} Index: generic/nsfAPI.decls =================================================================== diff -u -N -r6c9eb2ec861ed79b5dedf32abe2ea26059168215 -rf31c1a01c6a389f693b8db0f2204cbb46180fef1 --- generic/nsfAPI.decls (.../nsfAPI.decls) (revision 6c9eb2ec861ed79b5dedf32abe2ea26059168215) +++ generic/nsfAPI.decls (.../nsfAPI.decls) (revision f31c1a01c6a389f693b8db0f2204cbb46180fef1) @@ -199,7 +199,15 @@ {-argName "args" -type args} } {-nxdoc 1} +cmd "method::forward::property" NsfForwardPropertyCmd { + {-argName "object" -required 1 -type object} + {-argName "-per-object" -required 0 -nrargs 0 -type switch} + {-argName "methodName" -required 1 -type tclobj} + {-argName "forwardProperty" -required 1 -type "prefix|target|verbose"} + {-argName "value" -type tclobj} +} + cmd "method::property" NsfMethodPropertyCmd { {-argName "object" -required 1 -type object} {-argName "-per-object" -required 0 -nrargs 0 -type switch} Index: generic/nsfAPI.h =================================================================== diff -u -N -rcad3e31c72e3d35d75e67c8ceb7f6a1a775336e1 -rf31c1a01c6a389f693b8db0f2204cbb46180fef1 --- generic/nsfAPI.h (.../nsfAPI.h) (revision cad3e31c72e3d35d75e67c8ceb7f6a1a775336e1) +++ generic/nsfAPI.h (.../nsfAPI.h) (revision f31c1a01c6a389f693b8db0f2204cbb46180fef1) @@ -168,6 +168,19 @@ return result; } +enum ForwardpropertyIdx {ForwardpropertyNULL, ForwardpropertyPrefixIdx, ForwardpropertyTargetIdx, ForwardpropertyVerboseIdx}; + +static int ConvertToForwardproperty(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, + ClientData *clientData, Tcl_Obj **outObjPtr) { + int index, result; + static const char *opts[] = {"prefix", "target", "verbose", NULL}; + (void)pPtr; + result = Tcl_GetIndexFromObj(interp, objPtr, opts, "forwardProperty", 0, &index); + *clientData = (ClientData) INT2PTR(index + 1); + *outObjPtr = objPtr; + return result; +} + enum ProtectionIdx {ProtectionNULL, ProtectionCall_protectedIdx, ProtectionRedefine_protectedIdx, ProtectionNoneIdx}; static int ConvertToProtection(Tcl_Interp *interp, Tcl_Obj *objPtr, Nsf_Param const *pPtr, @@ -271,6 +284,7 @@ {ConvertToMethodproperty, "class-only|call-private|call-protected|redefine-protected|returns"}, {ConvertToRelationtype, "object-mixin|class-mixin|object-filter|class-filter|class|superclass|rootclass"}, {ConvertToSource, "all|application|system"}, + {ConvertToForwardproperty, "prefix|target|verbose"}, {ConvertToConfigureoption, "debug|dtrace|filter|profile|trace|softrecreate|objectsystems|keepcmds|checkresults|checkarguments"}, {ConvertToObjectproperty, "initialized|class|rootmetaclass|rootclass|volatile|slotcontainer|hasperobjectslots|keepcallerself|perobjectdispatch"}, {ConvertToAssertionsubcmd, "check|object-invar|class-invar"}, @@ -281,7 +295,7 @@ /* just to define the symbol */ -static Nsf_methodDefinition method_definitions[111]; +static Nsf_methodDefinition method_definitions[112]; static const char *method_command_namespace_names[] = { "::nsf::methods::object::info", @@ -357,6 +371,8 @@ NSF_nonnull(2) NSF_nonnull(4); static int NsfFinalizeCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST* objv) NSF_nonnull(2) NSF_nonnull(4); +static int NsfForwardPropertyCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST* objv) + NSF_nonnull(2) NSF_nonnull(4); static int NsfInterpObjCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST* objv) NSF_nonnull(2) NSF_nonnull(4); static int NsfIsCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST* objv) @@ -578,6 +594,8 @@ NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(5); static int NsfFinalizeCmd(Tcl_Interp *interp, int withKeepvars) NSF_nonnull(1); +static int NsfForwardPropertyCmd(Tcl_Interp *interp, NsfObject *object, int withPer_object, Tcl_Obj *methodName, int forwardProperty, Tcl_Obj *value) + NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(4); static int NsfInterpObjCmd(Tcl_Interp *interp, const char *name, int objc, Tcl_Obj *CONST* objv) NSF_nonnull(1) NSF_nonnull(2); static int NsfIsCmd(Tcl_Interp *interp, int withComplain, int withConfigure, const char *withName, Tcl_Obj *constraint, Tcl_Obj *value) @@ -766,6 +784,7 @@ NsfDirectDispatchCmdIdx, NsfDispatchCmdIdx, NsfFinalizeCmdIdx, + NsfForwardPropertyCmdIdx, NsfInterpObjCmdIdx, NsfIsCmdIdx, NsfMethodAliasCmdIdx, @@ -1716,6 +1735,30 @@ } static int +NsfForwardPropertyCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST* objv) { + ParseContext pc; + (void)clientData; + + if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], + method_definitions[NsfForwardPropertyCmdIdx].paramDefs, + method_definitions[NsfForwardPropertyCmdIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, + &pc) == TCL_OK)) { + NsfObject *object = (NsfObject *)pc.clientData[0]; + int withPer_object = (int )PTR2INT(pc.clientData[1]); + Tcl_Obj *methodName = (Tcl_Obj *)pc.clientData[2]; + int forwardProperty = (int )PTR2INT(pc.clientData[3]); + Tcl_Obj *value = (Tcl_Obj *)pc.clientData[4]; + + assert(pc.status == 0); + return NsfForwardPropertyCmd(interp, object, withPer_object, methodName, forwardProperty, value); + + } else { + + return TCL_ERROR; + } +} + +static int NsfInterpObjCmdStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST* objv) { ParseContext pc; (void)clientData; @@ -3402,7 +3445,7 @@ } } -static Nsf_methodDefinition method_definitions[111] = { +static Nsf_methodDefinition method_definitions[112] = { {"::nsf::methods::class::alloc", NsfCAllocMethodStub, 1, { {"objectName", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, @@ -3552,6 +3595,13 @@ {"::nsf::finalize", NsfFinalizeCmdStub, 1, { {"-keepvars", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}} }, +{"::nsf::method::forward::property", NsfForwardPropertyCmdStub, 5, { + {"object", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Object, NULL,NULL,"object",NULL,NULL,NULL,NULL,NULL}, + {"-per-object", 0, 0, Nsf_ConvertTo_Boolean, NULL,NULL,"switch",NULL,NULL,NULL,NULL,NULL}, + {"methodName", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, + {"forwardProperty", NSF_ARG_REQUIRED|NSF_ARG_IS_ENUMERATION, 1, ConvertToForwardproperty, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, + {"value", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} +}, {"::nsf::interp", NsfInterpObjCmdStub, 2, { {"name", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, {"args", 0, 1, ConvertToNothing, NULL,NULL,"allargs",NULL,NULL,NULL,NULL,NULL}} Index: generic/nsfAPI.nxdocindex =================================================================== diff -u -N -rc5f2227387dec2a5c0af9b36dc1ebc8578d6603e -rf31c1a01c6a389f693b8db0f2204cbb46180fef1 --- generic/nsfAPI.nxdocindex (.../nsfAPI.nxdocindex) (revision c5f2227387dec2a5c0af9b36dc1ebc8578d6603e) +++ generic/nsfAPI.nxdocindex (.../nsfAPI.nxdocindex) (revision f31c1a01c6a389f693b8db0f2204cbb46180fef1) @@ -26,6 +26,7 @@ set ::nxdoc::include(::nsf::method::create) 1 set ::nxdoc::include(::nsf::method::delete) 1 set ::nxdoc::include(::nsf::method::forward) 1 +set ::nxdoc::include(::nsf::method::forward::property) 0 set ::nxdoc::include(::nsf::method::property) 1 set ::nxdoc::include(::nsf::method::registered) 1 set ::nxdoc::include(::nsf::method::setter) 1 Index: library/nx/nx.tcl =================================================================== diff -u -N -r71a3245fb6a6e31e9188cf86d813f30cb8eb3ae7 -rf31c1a01c6a389f693b8db0f2204cbb46180fef1 --- library/nx/nx.tcl (.../nx.tcl) (revision 71a3245fb6a6e31e9188cf86d813f30cb8eb3ae7) +++ library/nx/nx.tcl (.../nx.tcl) (revision f31c1a01c6a389f693b8db0f2204cbb46180fef1) @@ -5,7 +5,7 @@ # Implementation of the Next Scripting Language (NX) object # system, based on the Next Scripting Framework (NSF). # -# Copyright (C) 2010-2014 Gustaf Neumann +# Copyright (C) 2010-2015 Gustaf Neumann # Copyright (C) 2010-2014 Stefan Sobernig # # Vienna University of Economics and Business @@ -2626,6 +2626,12 @@ return [lindex $objs 0] } + #:public object method mapSlot {newslot origin dest} { + # if {[$oldslot cget -domain] eq $origin} {$newslot configure -domain $dest} + # if {[$oldslot cget -manager] eq $oldslot} {$newslot configure -manager $newslot} + # $newslot eval :init + #} + :public method copy {obj {dest ""}} { #puts stderr "[::nsf::self] copy <$obj> <$dest>" set :objLength [string length $obj] Index: library/serialize/pkgIndex.tcl =================================================================== diff -u -N -rb34996b24ea334963e83aadda66384680a6f8ce5 -rf31c1a01c6a389f693b8db0f2204cbb46180fef1 --- library/serialize/pkgIndex.tcl (.../pkgIndex.tcl) (revision b34996b24ea334963e83aadda66384680a6f8ce5) +++ library/serialize/pkgIndex.tcl (.../pkgIndex.tcl) (revision f31c1a01c6a389f693b8db0f2204cbb46180fef1) @@ -1 +1 @@ -package ifneeded nx::serializer 2.0 [list source [file join $dir serializer.tcl]] +package ifneeded nx::serializer 2.1 [list source [file join $dir serializer.tcl]] Index: library/serialize/serializer.tcl =================================================================== diff -u -N -r47b4f88271108484539139a31a34c431d8cd322d -rf31c1a01c6a389f693b8db0f2204cbb46180fef1 --- library/serialize/serializer.tcl (.../serializer.tcl) (revision 47b4f88271108484539139a31a34c431d8cd322d) +++ library/serialize/serializer.tcl (.../serializer.tcl) (revision f31c1a01c6a389f693b8db0f2204cbb46180fef1) @@ -3,7 +3,7 @@ #package require nx::plain-object-method package require XOTcl 2.0 -package provide nx::serializer 2.0 +package provide nx::serializer 2.1 # For the time being, we require classical XOTcl. @@ -199,17 +199,18 @@ } :public method getTargetName {sourceName} { - # TODO: make more efficent; + # TODO: make more efficent; + if {![string match ::* $sourceName]} { + set sourceName ::$sourceName + } set targetName $sourceName if {[array exists :objmap]} { foreach {source target} [array get :objmap] { #puts "[list regsub ^$source $targetName $target targetName]" regsub ^$source $targetName $target targetName } } - if {![string match ::* $targetName]} { - set targetName ::$targetName - } + #puts stderr "targetName of <$sourceName> = <$targetName>" return $targetName @@ -457,7 +458,7 @@ :public object method methodSerialize {object method prefix} { foreach oss [ObjectSystemSerializer info instances] { if {[$oss responsibleSerializer $object]} { - set result [$oss serializeExportedMethod $object $prefix $method] + set result [$oss serializeExportedMethod $object $prefix $method [self]] break } } @@ -584,7 +585,7 @@ {return Class} {return Object} } - :method collectVars {o s} { + :method collectVars {{-serializeSlot:boolean false} o s} { set setcmd [list] foreach v [lsort [$o info vars]] { if {![::nsf::var::exists $s ignoreVarsRE] @@ -597,7 +598,12 @@ if {[::nsf::var::exists -array $o $v]} { lappend setcmd [list array set :$v [::nsf::var::set -array $o $v]] } else { - lappend setcmd [list set :$v [::nsf::var::set $o $v]] + set value [::nsf::var::set $o $v] + if {$serializeSlot && $v in {domain manager}} { + # map the values for these variables in the slot + set value [$s getTargetName $value] + } + lappend setcmd [list set :$v $value] } } } @@ -621,7 +627,7 @@ continue } set :targetName [$s getTargetName $o] - append methods($o) [:serializeExportedMethod $o $p $m]\n + append methods($o) [:serializeExportedMethod $o $p $m $s]\n } foreach o [array names methods] {set ($o) 1} foreach o [list ${:rootClass} ${:rootMetaClass}] { @@ -771,25 +777,47 @@ expr {[$object info method type $name] ne ""} } - :public object method serializeExportedMethod {object kind name} { + :public object method serializeExportedMethod {object kind name s} { # todo: object modifier is missing set :targetName $object - return [:method-serialize $object $name ""] + return [:method-serialize $object $name "" $s] } - :object method method-serialize {o m modifier} { + :object method method-serialize {o m modifier s} { if {![::nsf::is class $o]} {set modifier "object"} - if {[$o info {*}$modifier method type $m] eq "object"} { - # object serialization is fully handled by the serializer - return "# [$o info {*}$modifier method definition $m]" + set methodType [$o info {*}$modifier method type $m] + #puts stderr "methodType (*o $modifier $m) = $methodType" + set def [$o info {*}$modifier method definition $m] + switch -exact -- $methodType { + "object" { + # object serialization is fully handled by the serializer + return "# $def" + } + "setter" { + return "" + } + "forward" { + # + # handle targets of forwarders: when target object mapping + # is activated, we might have to adapt the forwarding target + # as well. This is particulary important for per-object + # forwarders, which are used frequently in the slot objects + # (but not necessarily only there). + # + if {${:targetName} ne $o} { + set perObject [expr {$modifier eq "object" ? "-per-object" : ""}] + set forwardTarget [nsf::method::forward::property $o {*}$perObject $m target] + set mappedForwardTarget [$s getTargetName $forwardTarget] + if {$forwardTarget ne $mappedForwardTarget} { + nsf::method::forward::property $o {*}$perObject $m target $mappedForwardTarget + set def [$o info {*}$modifier method definition $m] + nsf::method::forward::property $o {*}$perObject $m target $forwardTarget + } + } + } } - if {[$o info {*}$modifier method type $m] eq "setter"} { - set def "" - } else { - set def [$o info {*}$modifier method definition $m] - if {${:targetName} ne $o} { - set def [lreplace $def 0 0 ${:targetName}] - } + if {${:targetName} ne $o} { + set def [lreplace $def 0 0 ${:targetName}] } return $def } @@ -805,9 +833,11 @@ set traces [:collect-var-traces $o $s] - set evalList [:collectVars $o $s] + set serializeSlot [$o info has type ::nx::Slot] - if {[$o info has type ::nx::Slot]} { + set evalList [:collectVars -serializeSlot $serializeSlot $o $s] + + if {$serializeSlot} { # Slots need to be explicitely initialized to ensure # __invalidateobjectparameter to be called lappend evalList :init @@ -825,7 +855,7 @@ #puts stderr "CREATE targetName '${:targetName}'" append cmd [list ::nsf::object::alloc [$o info class] ${:targetName} [join $evalList "\n "]]\n foreach i [lsort [$o ::nsf::methods::object::info::methods -callprotection all -path]] { - append cmd [:method-serialize $o $i "object"] "\n" + append cmd [:method-serialize $o $i "object" $s] "\n" } } @@ -850,7 +880,7 @@ set cmd [:Object-serialize $o $s] foreach i [lsort [$o ::nsf::methods::class::info::methods -callprotection all -path]] { - append cmd [:method-serialize $o $i ""] "\n" + append cmd [:method-serialize $o $i "" $s] "\n" } append cmd \ [:frameWorkCmd ::nsf::relation::get $o superclass -unless ${:rootClass}] \ @@ -862,8 +892,9 @@ } # register serialize a global method - ::nx::Object public method serialize {} { - ::Serializer deepSerialize [::nsf::current object] + ::nx::Object public method serialize {-target} { + set objmap [expr {[info exists target] ? [list [::nsf::current object] $target] : ""}] + ::Serializer deepSerialize -objmap $objmap [::nsf::current object] } } @@ -909,18 +940,18 @@ } } - :public object method serializeExportedMethod {object kind name} { + :public object method serializeExportedMethod {object kind name s} { set :targetName $object set code "" switch $kind { "" - inst { # legacy; kind is prefix - set code [:method-serialize $object $name $kind]\n + set code [:method-serialize $object $name $kind $s]\n } proc - instproc { if {[$object info ${kind}s $name] ne ""} { set prefix [expr {$kind eq "proc" ? "" : "inst"}] - set code [:method-serialize $object $name $prefix]\n + set code [:method-serialize $object $name $prefix $s]\n } } forward - instforward { @@ -932,7 +963,7 @@ return $code } - :object method method-serialize {o m prefix} { + :object method method-serialize {o m prefix s} { if {![nsf::is class $o] || $prefix eq ""} { set scope object } else { @@ -965,7 +996,7 @@ set traces [:collect-var-traces $o $s] append cmd [list ::nsf::object::alloc [$o info class] ${:targetName} [join [:collectVars $o $s] "\n "]]\n foreach i [$o ::nsf::methods::object::info::methods -type scripted -callprotection all] { - append cmd [:method-serialize $o $i ""] "\n" + append cmd [:method-serialize $o $i "" $s] "\n" } foreach i [$o ::nsf::methods::object::info::methods -type forward -callprotection all] { append cmd [concat [list ${:targetName}] forward $i [$o info forward -definition $i]] "\n" @@ -990,7 +1021,7 @@ :object method Class-serialize {o s} { set cmd [:Object-serialize $o $s] foreach i [$o info instprocs] { - append cmd [:method-serialize $o $i inst] "\n" + append cmd [:method-serialize $o $i inst $s] "\n" } foreach i [$o info instforward] { append cmd [concat [list ${:targetName}] instforward $i [$o info instforward -definition $i]] "\n" @@ -1013,8 +1044,9 @@ } # register serialize a global method for XOTcl - ::xotcl::Object instproc serialize {} { - ::Serializer deepSerialize [::nsf::current object] + ::xotcl::Object instproc serialize {-target} { + set objmap [expr {[info exists target] ? [list [::nsf::current object] $target] : ""}] + ::Serializer deepSerialize -objmap $objmap [::nsf::current object] } # include this method in the serialized code Index: library/xotcl/library/serialize/Serializer.xotcl =================================================================== diff -u -N -rdce087a55bbf5ba3dae500e3409bea0a58ed9afc -rf31c1a01c6a389f693b8db0f2204cbb46180fef1 --- library/xotcl/library/serialize/Serializer.xotcl (.../Serializer.xotcl) (revision dce087a55bbf5ba3dae500e3409bea0a58ed9afc) +++ library/xotcl/library/serialize/Serializer.xotcl (.../Serializer.xotcl) (revision f31c1a01c6a389f693b8db0f2204cbb46180fef1) @@ -1,4 +1,4 @@ # -*- Tcl -*- # offer old package name for backward minimal compatibility -package provide xotcl::serializer 2.0 -package require nx::serializer \ No newline at end of file +package provide xotcl::serializer 2.1 +package require nx::serializer Index: tests/serialize.test =================================================================== diff -u -N -rc52c4d07b0c6921e5a94baa31e905ae21241eb25 -rf31c1a01c6a389f693b8db0f2204cbb46180fef1 --- tests/serialize.test (.../serialize.test) (revision c52c4d07b0c6921e5a94baa31e905ae21241eb25) +++ tests/serialize.test (.../serialize.test) (revision f31c1a01c6a389f693b8db0f2204cbb46180fef1) @@ -1,8 +1,58 @@ # -*- Tcl -*- package req nx::test -package req nx::serializer +package req nx::serializer +nx::test case serialize-target { + # + # Create object structure with a forwarder and a slot + # + Object create ::xxx { + :object property -accessor public ref + Object create [self]::b { + [:info parent] ref set [Object create [self]::c] + } + } + # + # check forwarder target and domain+manager of slot. + # + ? {nsf::method::forward::property :::xxx -per-object ref target} "::xxx::per-object-slot::ref" + ? {nsf::var::get ::xxx::per-object-slot::ref manager} "::xxx::per-object-slot::ref" + ? {nsf::var::get ::xxx::per-object-slot::ref domain} "::xxx" + + #puts [xxx serialize -target XXX] + # + # Create an serialized object, which has the target mapped to + # XXX. The target name has intentionally no leading colons, such + # that the object can be instantiated in a different namespace. This + # is for example useful when importing objects in OpenACS from a + # different system, where one has to assure that the imported + # objects do not clash with the already existing objects, but it has + # as well certain dangers. + # + set code [xxx serialize -target XXX] + + # + # Create the object with the new target + # + set result [eval $code] + + ? [list set _ $result] ::XXX::per-object-slot::ref + + # + # The target object of the forwarder + the slot manager and domain are mapped as well. + # Otherwise, we would trigger warnings during destroy + # + + ? {nsf::method::forward::property ::XXX -per-object ref target} "XXX::per-object-slot::ref" + ? {nsf::var::get ::XXX::per-object-slot::ref manager} "XXX::per-object-slot::ref" + ? {nsf::var::get ::XXX::per-object-slot::ref domain} "XXX" + +} + + + + nx::test case deepSerialize-map-filter { Object create ::a { @@ -28,7 +78,7 @@ ? {::nsf::object::exists ::a::b::c} 0 eval $script - + ? {::nsf::object::exists ::a} 0 ? {::nsf::object::exists ::a::b} 0 ? {::nsf::object::exists ::a::b::c} 0 @@ -45,15 +95,15 @@ set script [::a eval { ::Serializer deepSerialize -map [list ::x::y [self] ::x [self]] ::x::y::c }] - + ? {::x::y::c eval {set :parentRef}} ::x ? {::nsf::object::exists ::a::c} 0 eval $script ? {::nsf::object::exists ::a::c} 1 ? {::a::c eval {set :parentRef}} ::a } -nx::test case deepSerialize-ignoreVarsRE-filter { +nx::test case deepSerialize-ignoreVarsRE-filter { nx::Class create C { :object property -accessor public x :object property -accessor public y @@ -66,7 +116,7 @@ ? {C x get} 1 ? {C y set 1} 1 ? {C y get} 1 - + ? {lsort [C info methods]} "a b" ? {lsort [C info object methods]} "x y" ? {c1 a set b} {expected integer but got "b" for parameter "value"} @@ -80,7 +130,7 @@ set c1(IgnoreAll) [list [::Serializer deepSerialize -ignoreVarsRE "." c1] ""] set names {}; foreach s [C info slots] {lappend names [$s cget -name]} set c1(None2) [list [::Serializer deepSerialize -ignoreVarsRE [join $names |] c1] ""] - + c1 destroy foreach t [array names c1] { ? {nsf::object::exists c1} 0 @@ -91,17 +141,17 @@ c1 destroy } - + set C(IgnoreNone1) [list [::Serializer deepSerialize C] "x y"] set C(IgnoreNone2) [list [::Serializer deepSerialize -ignoreVarsRE "" C] "x y"] #set C(One) [list [::Serializer deepSerialize -ignoreVarsRE "x" C] "y"] set C(One2) [list [::Serializer deepSerialize -ignoreVarsRE {::x$} C] "y"] #set C(IgnoreAll) [list [::Serializer deepSerialize -ignoreVarsRE "." C] ""] set names {}; foreach s [C info object slots] {lappend names [$s cget -name]} #set C(None2) [list [::Serializer deepSerialize -ignoreVarsRE [join $names |] C] ""] - + C destroy - + foreach t [array names C] { ? {nsf::object::exists C} 0 lassign $C($t) script res @@ -115,9 +165,9 @@ } } -nx::test case deepSerialize-ignore-filter { +nx::test case deepSerialize-ignore-filter { Object create ::a { - Object create [self]::b + Object create [self]::b Object create [self]::c } @@ -136,7 +186,7 @@ ? {::nsf::object::exists ::a} 1 ? {::nsf::object::exists ::a::b} 0 ? {::nsf::object::exists ::a::c} 1 - + set script [::Serializer deepSerialize -ignore ::a ::a] ::a destroy @@ -146,7 +196,7 @@ } nx::test case serialize-slotContainer { - + nx::Class create C { :object property x :property a @@ -179,7 +229,7 @@ # perobjectdispatch for nx::Objects are handled correctly via serialize # nx::test case serialize-object-properties { - + # # Check on object o #