Index: generic/nsf.nxd =================================================================== diff -u -r459ae500daf2a8e5012c8f59519d3adfd7e3c2e7 -r26ce746b45449fbff64f88c6d9e9050a63b89449 --- generic/nsf.nxd (.../nsf.nxd) (revision 459ae500daf2a8e5012c8f59519d3adfd7e3c2e7) +++ generic/nsf.nxd (.../nsf.nxd) (revision 26ce746b45449fbff64f88c6d9e9050a63b89449) @@ -1,3 +1,5 @@ +# -*- Tcl -*- + # @command assertion # # @parameter object:object @@ -14,8 +16,8 @@ # @parameter object:object # @parameter -per-object:switch # @parameter methodName -# @parameter methodproperty Accepts one of: {{{protected}}}, -# {{{redefine-protected}}}, {{{returns}}}, {{{slotobj}}} +# @parameter methodproperty Accepts one of: '''protected''', +# '''redefine-protected''', '''returns''', '''slotobj''' # @parameter value # @command setter @@ -46,8 +48,8 @@ # @command objectproperty # # @parameter object:object -# @parameter objectkind Accepts one of: {{{type}}}, {{{object}}}, -# {{{class}}}, {{{baseclass}}}, {{{metaclass}}}, {{{hasmixin}}} +# @parameter objectkind Accepts one of: '''type''', '''object''', +# '''class''', '''baseclass''', '''metaclass''', '''hasmixin''' # @parameter value:optional # @command importvar @@ -97,11 +99,11 @@ # # Invokes the shadowed (i.e, same-named) method which is next along # the precedence path and returns the results of this invocation. If -# {{{next}}} is called without arguments, the arguments of the current +# '''next''' is called without arguments, the arguments of the current # method (i.e., the arguments as present at the current callframe) are # passed through to the shadowed method. If next is invoked with the # flag --noArgs, the shadowed method is called without the active -# callframe arguments. If other arguments are specified for {{{next}}} +# callframe arguments. If other arguments are specified for '''next''' # explicitly, these will be passed instead. # # @parameter --noArgs:optional Deactivates the forward-passing of the current callframe's arguments @@ -112,15 +114,15 @@ # # An introspective command which allows you to explore the callstack # from within the scope of a method (or a proc bound to an object via -# {{{alias}}}). If executed without specifying a subcommand, -# i.e. {{{[current]}}}, it defaults to {{@command.command "current -# object"}}. While {{{current}}} operates on the Tcl callstack, it is +# '''alias'''). If executed without specifying a subcommand, +# i.e. '''[current]''', it defaults to <<@command.command "current +# object">>. While '''current''' operates on the Tcl callstack, it is # aware of object-specific callstack and frame information. To some # extent, this object introspection protocol can be approximated at -# the script level by instrumenting {{{[info frame]}}}. +# the script level by instrumenting '''[info frame]'''. # # If invoked outside of an object's scope (e.g., an ordinary proc, the -# global namespace), it fails and reports {{{No current object}}}. +# global namespace), it fails and reports '''No current object'''. # # It comes with a variety of sub-commands to query the object-specific # callstack information available. See below. @@ -147,7 +149,7 @@ # (applicable in a filter only). # # @sub-command isnextcall Returns 1 if the executing method was -# invoked via {{@command next}}, 0 otherwise. +# invoked via <<@command next>>, 0 otherwise. # # @sub-command next Returns the name of the method next on the # precedence path as a string. @@ -159,18 +161,18 @@ # @command callinglevel Resolves the callstack level which represents # the originating invocation into the currently executing method. Levels # of indirection (e.g., filters) and method combination along the -# class linearisation path ({{{next}}}) are ignored. The callstack is +# class linearisation path ('''next''') are ignored. The callstack is # returned as an absolute level number (# followed by a digit). The # level number returned can be directly used as the first argument to -# {{{uplevel}}} or {{{upvar}}} calls. See also {{@command.command -# "current activelevel"}} +# '''uplevel''' or '''upvar''' calls. See also <<@command.command +# "current activelevel">> # # @sub-command activelevel Returns the actual callstack level calling # into the executing method. The active might correspond the -# {{{callinglevel}}}, but this is not necessarily the case. The -# {{{activelevel}}} counts {{@command next}} call. The level +# '''callinglevel''', but this is not necessarily the case. The +# '''activelevel''' counts <<@command next>> call. The level # is returned in a form so that it can be used as first argument in -# {{{uplevel}}} or {{{upvar}}}. +# '''uplevel''' or '''upvar'''. # @command.command {current object} # @@ -182,13 +184,13 @@ # # A top-level configuration facility which allows you modify # properties of the "Next" object system for the scope of an entire -# {{{interp}}}. +# '''interp'''. # @command.sub-command {configure filter} # # Allows turning on or off filters globally for the current # interpreter. By default, the filter state is turned off. This -# function returns the old filter state. This filterless {{{interp}}} +# function returns the old filter state. This filterless '''interp''' # state is needed for the serializer which should introspect and stream the # objects and classes without being affected by active filter. # @@ -198,21 +200,21 @@ # @command.sub-command {configure softrecreate} # # Allows controlling the scheme applied when recreating an object or a -# class. By default, it is set to {{{off}}}. This means that the +# class. By default, it is set to '''off'''. This means that the # object/class is destroyed and all relations # (e.g. subclass/superclass) to other objects/classes are revoked as -# well. If softrecreate is set to {{{on}}}, the object is re-set, but not +# well. If softrecreate is set to '''on''', the object is re-set, but not # destroyed, the relations are # kept. # # A "soft" recreation is important for e.g. reloading a file with # class definitions (e.g. when used in OpenACS with file watching and # reloading). With softrecreate set, it is not necessary to recreate # dependent subclasses etc. Consider the example of a class hierarchy -# {{{A <- B <- C}}}. Without {{{softrecreate}}} set, a reload of -# {{{B}}} means first a destroy of B, leading to {{{A <- C}}}, and -# instances of {{{B}}} are re-classed to {{@class -# ::nx::Object}}. When softrecreate is set, the class hierarchy +# '''A <- B <- C'''. Without '''softrecreate''' set, a reload of +# '''B''' means first a destroy of B, leading to '''A <- C''', and +# instances of '''B''' are re-classed to <<@class +# ::nx::Object>>. When softrecreate is set, the class hierarchy # remains untouched. # # @parameter toggle Accepts either "on" or "off" @@ -225,23 +227,23 @@ # current object system, i.e., the ruling root class and root # meta-class. For "Next": # -# {{{ +# ''' # configure objectsystems; # returns "::nx::Object ::nx::Class" -# }}} +# ''' # # @return The active pair of root class and root meta-class # @command.sub-command {configure keepinitcmd} # -# Usually, initcmd scripts are discarded by the {{{interp}}} once -# having been evaluated (in contrast to {{{proc}}} and {{{method}}} +# Usually, initcmd scripts are discarded by the '''interp''' once +# having been evaluated (in contrast to '''proc''' and '''method''' # bodies). If you need them preserved for later introspection and # processing (as in the "Next" documentation system), set this option -# to {{{true}}}. Then, the initcmd scripts are retained as a -# particular object variable ({{{__initcmd}}}) of classes and -# objects. It defaults to {{{false}}}. +# to '''true'''. Then, the initcmd scripts are retained as a +# particular object variable ('''__initcmd''') of classes and +# objects. It defaults to '''false'''. # -# @parameter value:boolean Either {{{true}}} or {{{false}}} +# @parameter value:boolean Either '''true''' or '''false''' # @return The current setting # @command alias Index: library/lib/doc-assets/glossary.html.tmpl =================================================================== diff -u -r18ff1444fef5c209dfb40cf2ae694206c0d10309 -r26ce746b45449fbff64f88c6d9e9050a63b89449 --- library/lib/doc-assets/glossary.html.tmpl (.../glossary.html.tmpl) (revision 18ff1444fef5c209dfb40cf2ae694206c0d10309) +++ library/lib/doc-assets/glossary.html.tmpl (.../glossary.html.tmpl) (revision 26ce746b45449fbff64f88c6d9e9050a63b89449) @@ -1,30 +1,36 @@ -[:!let entries [sorted [::nx::doc::@glossary info instances] name]] -[:? {$entries ne ""} { +[:?var :@glossary { +[:!let entries [sorted ${:@glossary} name]]
[:for entry $entries { [:!let ddesc [$entry as_text]] [:?objvar $entry @acronym { [:!let dtext [$entry @acronym]] - [:!let ddesc "[$entry @pretty_name] — $ddesc"] + [:? {$ddesc ne ""} { + [:!let ddesc "[$entry @pretty_name] — $ddesc"] } - { + [:!let ddesc "[$entry @pretty_name]"] + }] + + } - { [:!let dtext [$entry @pretty_name]] }]
$dtext
$ddesc [:?objvar $entry refs { - [:!let refs [$entry eval {set :refs}]] + [:!let refs [sort_by_value [$entry eval {set :refs}]]]
Index: library/lib/doc-assets/method.html.tmpl =================================================================== diff -u -r459ae500daf2a8e5012c8f59519d3adfd7e3c2e7 -r26ce746b45449fbff64f88c6d9e9050a63b89449 --- library/lib/doc-assets/method.html.tmpl (.../method.html.tmpl) (revision 459ae500daf2a8e5012c8f59519d3adfd7e3c2e7) +++ library/lib/doc-assets/method.html.tmpl (.../method.html.tmpl) (revision 26ce746b45449fbff64f88c6d9e9050a63b89449) @@ -24,10 +24,10 @@ [$sm render -initscript [list set supermethod [current]] submethod.html.tmpl] }] } - { - [:? {[info exists :@param]} { + [:? {[info exists :@parameter]} {
Method parameters:
- [:for param ${:@param} { + [:for param ${:@parameter} {
[$param name] [:? {[$param eval {info exists :spec}] && [$param spec] ne ""} {<[$param spec]>}] Index: library/lib/doc-assets/package.html.tmpl =================================================================== diff -u -r5f765b6d8713f416a443cc2367c3a47903cc2f83 -r26ce746b45449fbff64f88c6d9e9050a63b89449 --- library/lib/doc-assets/package.html.tmpl (.../package.html.tmpl) (revision 5f765b6d8713f416a443cc2367c3a47903cc2f83) +++ library/lib/doc-assets/package.html.tmpl (.../package.html.tmpl) (revision 26ce746b45449fbff64f88c6d9e9050a63b89449) @@ -24,7 +24,7 @@
    - [:let idx 0] + [:!let idx 0] [:for class ${:@class} {
  • [${class} name]
  • [incr idx; return] @@ -40,7 +40,7 @@
      - [:let idx 0] + [:!let idx 0] [:for obj ${:@object} {
    • [${obj} name]
    • [incr idx; return] @@ -57,7 +57,7 @@
        - [:let idx 0] + [:!let idx 0] [:for cmd ${:@command} {
      • [$cmd name]
      • [incr idx; return] Index: library/lib/doc-tools.tcl =================================================================== diff -u -r18ff1444fef5c209dfb40cf2ae694206c0d10309 -r26ce746b45449fbff64f88c6d9e9050a63b89449 --- library/lib/doc-tools.tcl (.../doc-tools.tcl) (revision 18ff1444fef5c209dfb40cf2ae694206c0d10309) +++ library/lib/doc-tools.tcl (.../doc-tools.tcl) (revision 26ce746b45449fbff64f88c6d9e9050a63b89449) @@ -36,7 +36,8 @@ # # @param class Request an instance of a particular entity class (e.g., ...) # @param name What is the entity name (e.g., nx::doc for a package) - # @param args A vector of arbitrary arguments, provided to the entity when being constructed + # @param args A vector of arbitrary arguments, provided to the + # entity when being constructed # @return The identifier of the newly created entity object # @subcommand ::nx::doc::@#foo @@ -94,6 +95,15 @@ return $result } + proc sort_by_value {d} { + set haystack [list] + dict for {key value} $d { + lappend haystack [list $key $value] + } + return [dict create {*}[concat {*}[lsort -integer -index 1 -decreasing $haystack]]] + } + + proc find_asset_path {{subdir library/lib/doc-assets}} { # This helper tries to identify the file system path of the # asset ressources. @@ -113,23 +123,15 @@ :public method apply {} { foreach mixin [:info children -type [current class]::Mixin] { set base "${:prefix}::[namespace tail $mixin]" - puts "TRYING mixin $mixin base $base" if {[::nsf::isobject $base]} { set scope [expr {[$mixin scope] eq "object" && [$base info is class]?"class-object":""}] - puts stderr "APPLYING $base {*}$scope mixin add $mixin" $base {*}$scope mixin add $mixin } } } Class create [current]::Mixin -superclass Class { :attribute {scope class} - :method init args { - :public method foo {} { - puts stderr "[current class]->[current method]"; - next - } - } } } @@ -140,15 +142,18 @@ # basic name-generating mechanisms for documentation entities # based on properties such as entity name, root namespace, etc. # - # @param tag Defaults to the tag label to be used in comment tags. It may vary from the auto-generated default! - # @param root_namespace You may choose your own root-level namespace hosting the namespace hierarchy of entity objects + # @param tag Defaults to the tag label to be used in comment + # tags. It may vary from the auto-generated default! + # @param root_namespace You may choose your own root-level + # namespace hosting the namespace hierarchy of entity objects :attribute {tag {[string trimleft [string tolower [namespace tail [current]]] @]}} :attribute {root_namespace "::nx::doc::entities"} namespace eval ::nx::doc::entities {} :public class-object method normalise {tagpath names} { + # puts stderr "tagpath $tagpath names $names" # 1) verify balancedness of if {[llength $tagpath] != [llength $names]} { return [list 1 "Imbalanced tag line spec: '$tagpath' vs. '$names'"] @@ -188,7 +193,21 @@ set entity_path [list] foreach axis $tagpath value $names { if {$entity eq ""} { - if {[QualifierTag info instances @$axis] eq "" && [Tag info instances @$axis] eq ""} { + set cmd [info command @$axis] + # + # TODO interp-aliasing objects under different command names + # is currently not transparent to some ::nsf::* helpers, + # such as ::nsf::isobject. Should this be changed? + # + if {$cmd ne ""} { + set cmd [namespace origin $cmd] + set target [interp alias {} $cmd] + if {$target ne ""} { + set cmd $target + } + } + + if {$cmd eq "" || ![::nsf::isobject $cmd] || ![$cmd info has type Tag]} { return [list 1 "The entity type '@$axis' is not available."] } set entity [@$axis id $value] @@ -238,7 +257,8 @@ set partof_name [string trimleft $partof_name :] return [join [list [:root_namespace] $subns $partof_name {*}$scope $name] ::] } else { - return "[:root_namespace]::${subns}$name" + set name [string trimleft $name :] + return "[:root_namespace]::${subns}::$name" } } @@ -495,8 +515,14 @@ # @command nx # # @use ::nsf::command - # @use {Object foo} - # @use command {Object foo} + + # or + + # class.method {X foo} + # + # @use {Class foo} + # @use object.method {Object foo} + lassign $value pathspec pathnames if {$pathnames eq ""} { set pathnames $pathspec @@ -602,12 +628,25 @@ Class create StructuredEntity -superclass Entity { - :public method owned_parts {} { + :public method part_attributes {} { set slots [:info lookup slots] - set r [dict create] -# puts stderr SLOTS=$slots + set attrs [list] foreach s $slots { if {![$s info has type ::nx::doc::PartAttribute] || ![$s eval {info exists :part_class}]} continue; + lappend attrs $s [$s part_class] + } + return $attrs + } + :public method owned_parts {} { + set r [dict create] + foreach {s cls} [:part_attributes] { + # + # TODO: there is no equivalent to mixinof/has mixin for the + # superclass-subclass axis: info superclassof | /cls/ has + # superclass | info subclassof | /cls/ has subclass; are info + # subclass and superclass sufficient? + # + # if {![$s info has type ::nx::doc::PartAttribute] || ![$s eval {info exists :part_class}] || [current class] ni [[$s eval {set :part_class}] info superclass -closure]} continue; set accessor [$s name] # puts stderr "PROCESSING ACCESSOR $accessor, [info exists :$accessor]" if {[info exists :$accessor]} { @@ -637,7 +676,7 @@ Class create [current]::Containable { # TODO: check the interaction of required, per-object attribute and ::nsf::assertion #:object attribute container:object,type=[:info parent],required - :class-object attribute container:object,type=[:info parent] + :attribute container:object,type=[:info parent] :method create args { # # Note: preserve the container currently set at this callstack @@ -655,6 +694,24 @@ next } } + :method create args { + # + # Note: preserve the container currently set at this callstack + # level. [next] will cause the container to change if another + # container entity is initialised in the following! + # + if {[info exists :container]} { + set cont ${:container} + set obj [next] + if {![$obj eval {info exists :partof}]} { + $cont register $obj + } + return $obj + } else { + next + } + } + } # Note: The default "" corresponds to the top-level namespace "::"! :attribute {@namespace ""} @@ -690,11 +747,14 @@ :method init {} { next + QualifierTag mixin add [current class]::Resolvable [current class]::Resolvable container [current] - QualifierTag mixin add [current class]::Containable - @package class-object mixin add [current class]::Containable - [current class]::Containable container [current] + + foreach {attr part_class} [:part_attributes] { + $part_class class-object mixin add [current class]::Containable + $part_class container [current] + } } :public method register {containable:object,type=::nx::doc::Entity} { @@ -710,6 +770,10 @@ :attribute license :attribute creationdate :attribute {version ""} + + :attribute @glossary -slotclass ::nx::doc::PartAttribute { + set :part_class ::nx::doc::@glossary + } :attribute @package -slotclass ::nx::doc::PartAttribute { set :part_class ::nx::doc::@package @@ -747,12 +811,11 @@ :method require_part {domain prop value} { set value [expr {![string match ":*" $value] ? "__out__: $value": "__out__$value"}] next [list $domain $prop $value] - #next $domain $prop "__out__ $value" } set :part_class ::nx::doc::@param } - :forward @sub-command %self @command + :public forward @sub-command %self @command :attribute @command -slotclass ::nx::doc::PartAttribute { :pretty_name "Subcommand" :pretty_plural "Subcommands" @@ -784,7 +847,7 @@ -mixin ContainerEntity::Containable { :attribute @author -slotclass ::nx::doc::PartAttribute - :forward @object %self @child-object + :public forward @object %self @child-object :attribute @child-object -slotclass ::nx::doc::PartAttribute { set :part_class ::nx::doc::@object :public method id {domain prop value} { @@ -798,7 +861,7 @@ } - :forward @class %self @child-class + :public forward @class %self @child-class :attribute @child-class -slotclass ::nx::doc::PartAttribute { set :part_class ::nx::doc::@class :public method id {domain prop value} { @@ -811,12 +874,12 @@ } } - :forward @method %self @object-method + :public forward @method %self @object-method :attribute @class-object-method -slotclass ::nx::doc::PartAttribute { set :part_class ::nx::doc::@method } - :forward @attribute %self @class-object-attribute + :public forward @attribute %self @class-object-attribute #:forward @param %self @object-param :attribute @class-object-attribute -slotclass ::nx::doc::PartAttribute { set :part_class ::nx::doc::@param @@ -840,14 +903,14 @@ -superclass @object { :attribute @superclass -slotclass ::nx::doc::PartAttribute - :forward @attribute %self @class-attribute + :public forward @attribute %self @class-attribute :attribute @class-attribute -slotclass ::nx::doc::PartAttribute { :pretty_name "Per-class attribute" :pretty_plural "Per-class attributes" set :part_class ::nx::doc::@param } - :forward @method %self @class-method + :public forward @method %self @class-method :attribute @class-method -slotclass ::nx::doc::PartAttribute { :pretty_name "Per-class method" :pretty_plural "Per-class methods" @@ -933,9 +996,9 @@ - :forward @class-method %self @method - :forward @class-object-method %self @method - :forward @sub-method %self @method + :public forward @class-method %self @method + :public forward @class-object-method %self @method + :public forward @sub-method %self @method :attribute @method -slotclass ::nx::doc::PartAttribute { set :part_class ::nx::doc::@method :public method id {domain prop name} { @@ -1123,6 +1186,19 @@ interp alias {} ::nx::doc::@attribute {} ::nx::doc::@param interp alias {} ::nx::doc::@parameter {} ::nx::doc::@param + # + # Providing interp-wide aliases for @glossary. For most processing + # steps, this is syntactic sugar, however, the aliases cause + # different rendering behaviour for glossary references and entries. + # + + interp alias {} ::nx::doc::@gls {} ::nx::doc::@glossary + interp alias {} ::nx::doc::@Gls {} ::nx::doc::@glossary + interp alias {} ::nx::doc::@glspl {} ::nx::doc::@glossary + interp alias {} ::nx::doc::@Glspl {} ::nx::doc::@glossary + interp alias {} ::nx::doc::@acr {} ::nx::doc::@glossary + interp alias {} ::nx::doc::@acrfirst {} ::nx::doc::@glossary + namespace export CommentBlockParser @command @object @class @package \ @project @method @attribute @parameter @ } @@ -1176,11 +1252,16 @@ } { # Here, we assume the -nonleaf mode being active for {{{[eval]}}}. set tmplscript [list subst [:read_tmpl $template]] + # + # TODO: This looks awkward, however, till all requirements are + # figured out (as for the origin mechanism) we so keep track + # of the actual rendered entity ... review later ... + # + $entity rendered_entity $entity $entity eval [subst -nocommands { $initscript $tmplscript }] - # $entity eval [list subst $template] } @@ -1263,28 +1344,38 @@ } set :markup_map(sub) { - "{{{" "\[:code \{" - "}}}" "\}\]" - "{{" "\[:link " - "}}" "\]" + "'''" "\[:listing \{" + "'''" "\}\]" + "<<" "\[:link " + ">>" "\]" } set :markup_map(unescape) { "\\{" "{" "\\}" "}" "\\#" "#" + "\\<" "<" + "\\>" ">" + "\\'" "'" } - :method map {line set} { - set line [string map [[::nsf::current class] eval [list set :markup_map($set)]] $line] + :method unescape {line} { + set line [string map [[::nsf::current class] eval [list set :markup_map(unescape)]] $line] } + :method map {line} { + regsub -all -- {('''([^']+?)''')} $line {[:listing {\2}]} line + regsub -all -- {(<<([^<]+?)>>)} $line {[:link \2]} line + return $line + } + + :method as_list {} { set preprocessed [list] set is_code_block 0 foreach line [next] { - if {[regsub -- {^\s*(\{\{\{)\s*$} $line "\[:code -inline false \{" line] || \ - (${is_code_block} && [regsub -- {^\s*(\}\}\})\s*$} $line "\}\]" line])} { + if {(!${is_code_block} && [regsub -- {^\s*(''')\s*$} $line "\[:listing -inline false \{" line]) || \ + (${is_code_block} && [regsub -- {^\s*(''')\s*$} $line "\}\]" line])} { set is_code_block [expr {!$is_code_block}] append line \n } elseif {${is_code_block}} { @@ -1305,8 +1396,8 @@ :public method as_text {} { set preprocessed [join [:as_list] " "] - set preprocessed [:map $preprocessed sub] - set preprocessed [:map $preprocessed unescape] + set preprocessed [:map $preprocessed] + set preprocessed [:unescape $preprocessed] return [subst $preprocessed] } @@ -1334,38 +1425,42 @@ set top_level_entities [:owned_parts] dict for {feature instances} $top_level_entities { if {[$feature name] eq "@package"} { - foreach {entity_type pkg_entities} [$feature owned_parts] { - dict lappend top_level_entities $entity_type {*}$pkg_entities + foreach pkg $instances { + dict for {pkg_feature pkg_feature_instances} [$pkg owned_parts] { + dict lappend top_level_entities $pkg_feature {*}$pkg_feature_instances + } } } } set init [subst { - set project [current object] + set project \[:current_project\] set project_entities \[list $top_level_entities\] }] set project_path [file join $outdir [string trimleft ${:name} :]] if {![catch {file mkdir $project_path} msg]} { - # puts stderr [list file copy -force -- [$renderer find_asset_path] $project_path/assets] set assets [lsearch -all -inline -glob -not [glob -directory [find_asset_path] *] *.tmpl] set target $project_path/assets file mkdir $target file copy -force -- {*}$assets $target set values [join [dict values $top_level_entities]] - # puts stderr "VALUES=$values" + + # + # Make sure that the @project entity is processed last. + # + lappend values [current object] foreach e $values { - #puts stderr "PROCESSING=$e render -initscript $init $tmpl" + # + # TODO: For now, in templates we (silently) assume that we act + # upon structured entities only ... + # + if {![$e info has type ::nx::doc::StructuredEntity]} continue; + $e current_project [current object] set content [$e render -initscript $init $tmpl] :write_data $content [file join $project_path "[$e filename].$ext"] puts stderr "$e written to [file join $project_path [$e filename].$ext]" } - - set index [:render -initscript $init $tmpl] - # puts stderr "we have [llength $entities] documentation entities ($entities)" - :write_data $index [file join $project_path "index.$ext"] - - } # 3) TODO: revoke the application of the mixin layer (for the sake of @@ -1377,6 +1472,30 @@ # MixinLayer::Mixin create [current]::Entity -superclass TemplateData { + # + # TODO: Would it be useful to allow attribute slots to describe + # a per-class-object state, while the accessor/mutator methods + # are defined on the per-class level. It feels like the class + # instance variables in Smalltalk ... + # + # TODO: Why is call protection barfing when the protected target + # is called from within a public forward. This should qualify as + # a valid call site (from "within" the same object!), shouldn't it? + # :protected class-object attribute current_project:object,type=::nx::doc::@project + :class-object attribute current_project:object,type=::nx::doc::@project + :public forward current_project [current] %method + + # + # TODO: For now, this acts as the counterweight to "origin", + # when @use aliasing is used, processed_entity can be used to + # refer to the actual entity at the upper end of the aliasing + # chain. Verify, whether this is an acceptable approach ... + # + :class-object attribute rendered_entity:object,type=::nx::doc::Entity + :public forward rendered_entity [current] %method + + :public forward print_name %current name + :method fit {str max {placeholder "..."}} { if {[llength [split $str ""]] < $max} { return $str; @@ -1400,7 +1519,7 @@ # @object instances. Untangle! set access [expr {[$inst eval {info exists :@modifier}]?[$inst @modifier]:""}] set host ${:name} - set name [$inst name] + set name [$inst print_name] set url "[:filename].html#[string trimleft [$feature name] @]_[$inst name]" set type [$feature name] lappend entries [subst $entry] @@ -1409,30 +1528,35 @@ return "\[[join $entries ,\n]\]" } - :method code {{-inline true} script} { + :method listing {{-inline true} script} { return [expr {$inline?"$script":"
        $script
        "}] } :method link {tag names} { - #puts stderr "RESOLVING tag $tag names $names" set tagpath [split [string trimleft $tag @] .] lassign [::nx::doc::Tag normalise $tagpath $names] err res if {$err} { - #puts stderr RES=$res + puts stderr RES=$res return "?"; } lassign [::nx::doc::Tag find -all -strict {*}$res] err path if {$err || $path eq ""} { - #puts stderr "FAILED res $path (err-$err-id-[expr {$path eq ""}])" + # puts stderr "FAILED res $path (err-$err-id-[expr {$path eq ""}])" return "?"; } set path [dict create {*}$path] set entities [dict keys $path] set id [lindex $entities end] - return [$id render_link $tag [current] $path] + return [$id render_link $tag [:rendered_entity] $path] } + :public method make_link {source} { + set path [dict create {*}[:get_upward_path -attribute {set :name}]] + set tag [[:info class] tag] + return [:render_link $tag $source $path] + } + :public method render_link {tag source path} { #puts stderr PATH=$path set id [current] @@ -1485,31 +1609,90 @@ } }; # NxDocTemplating::Entity + MixinLayer::Mixin create [current]::@project -superclass [current]::Entity { + :public method filename {} { + return "index" + } + } + MixinLayer::Mixin create [current]::@glossary -superclass [current]::Entity { - + :public method print_name {} { + return [expr {[info exists :@acronym]?${:@acronym}:${:@pretty_name}}] + } + + array set :tags { + @gls { + set print_name [string tolower ${:@pretty_name} 0 0] + set title ${:@pretty_name} + } + @Gls { + set print_name [string toupper ${:@pretty_name} 0 0] + set title ${:@pretty_name} + } + @glspl { + set print_name [string tolower ${:@pretty_plural} 0 0] + set title ${:@pretty_plural} + } + @Glspl { + set print_name [string toupper ${:@pretty_plural} 0 0] + set title ${:@pretty_plural} + } + @acr { + set acronym(short) 1 + } + @acrfirst { + set acronym(long) 1 + } + + } + + :public method href {-local:switch top_entity:optional} { + set fragments "#${:name}" + if {$local} { + return $fragments + } else { + return "[[:current_project] filename].html$fragments" + } + + } + :public method render_link {tag source path} { + # tag-specific rendering + set acronym(long) 0 + set acronym(short) 0 + set print_name ${:@pretty_name} + set title ${:@pretty_name} + if {[[current class] eval [list info exists :tags($tag)]]} { + eval [[current class] eval [list set :tags($tag)]] + } + if {[info exists :@acronym]} { + # + # First occurrance of an acronym entry! + # + if {!$acronym(short) && ($acronym(long) || ![info exists :refs] || \ + ![dict exists ${:refs} $source])} { + set print_name "$print_name (${:@acronym})" + set res "$print_name" + } else { + set title $print_name + set print_name ${:@acronym} + set anchor "$print_name" + set res "$anchor" + } + } else { + set res "$print_name" + } + + # record for reverse references if {![info exists :refs]} { set :refs [dict create] } dict incr :refs $source - # TODO: provide the project context here and render the - # glossary location accordingly, rather than hard-code "index.html". - return "[string tolower ${:@pretty_name}]" - } - # - # TODO: this should go into the appropriate template - # - :public method render_refs {} { - if {[info exists :refs]} { - dict for {entity count} ${:refs} { - } - } - } - + return $res + } } - }; # NxDocTemplating # @@ -2047,14 +2230,14 @@ return $parser_obj } - :forward has_next expr {${:idx} < [llength ${:comment_block}]} - :method dequeue {} { + :public forward has_next expr {${:idx} < [llength ${:comment_block}]} + :public method dequeue {} { set r [lindex ${:comment_block} ${:idx}] incr :idx return $r } - :forward rewind incr :idx -1 - :forward fastforward set :idx {% llength ${:comment_block}} + :public forward rewind incr :idx -1 + :public forward fastforward set :idx {% llength ${:comment_block}} :public method cancel {statuscode {msg ""}} { :fastforward @@ -2201,7 +2384,7 @@ } } - :forward event=parse %self {% subst {parse@${:current_comment_line_type}}} + :public forward event=parse %self {% subst {parse@${:current_comment_line_type}}} :method event=next {line} { set next_section [[${:block_parser} processed_section] next_comment_section] :on_exit $line @@ -2216,15 +2399,16 @@ # realise the sub-state (a variant of METHOD-FOR-STATES) and their # specific event handling + # set :lineproc {{tag args} {return [concat {*}$args]}} + set :lineproc {{tag args} {return [list $tag $args]}} :method parse@tag {line} { - set line [split [string trimleft $line]] - set tag [lindex $line 0] + lassign [apply [[current class] eval {set :lineproc}] {*}$line] tag line if {[:info lookup methods -source application $tag] eq ""} { set msg "The tag '$tag' is not supported for the entity type '[namespace tail [:info class]]" ${:block_parser} cancel INVALIDTAG $msg } -# puts stderr ":$tag [lrange $line 1 end]" - :$tag [lrange $line 1 end] + #:$tag [lrange $line 1 end] + :$tag $line } :method parse@text {line} { @@ -2279,61 +2463,9 @@ } } - # realise the parse events specific to the substates of description + set :lineproc {{tag name args} {return [list $tag $name $args]}} :method parse@tag {line} { - # - # When hitting this parsing step, we have an unresolved - # entity. The context section specifies the entity to create - # or to resolve for further processing. - # - set line [split [string trimleft $line]] - set args [lassign $line tag name] - lassign [:resolve_partof_entity $tag $name] nq_name partof_entity - if {$partof_entity ne ""} { - if {[$partof_entity info lookup methods -source application $tag] eq ""} { - ${:block_parser} cancel INVALIDTAG "The tag '$tag' is not supported for the entity type - '[namespace tail [$partof_entity info class]]'" - # [InvalidTag new -message [subst { - # The tag '$tag' is not supported for the entity type - # '[namespace tail [$partof_entity info class]]' - # }]] throw - } - # puts stderr "$partof_entity $tag $nq_name {*}$args" - set current_entity [$partof_entity $tag $nq_name {*}$args] - - } else { - # - # TODO: @object-method raises some issues (at least when - # processed without a resolved context = its partof entity). - # It is not an entity type, because it merely is a "scoped" - # @method. It won't resolve then as a proper instance of - # Tag, hence we observe an InvalidTag exception. For - # now, we just ignore and bypass this issue by allowing - # InvalidTag exceptions in analyze() - # - set qualified_tag [namespace qualifiers [current]]::$tag - ${:block_parser} cancel INVALIDTAG "The entity type '$tag' is not available" - # if {[Tag info instances -closure $qualified_tag] eq ""} { - # [InvalidTag new -message [subst { - # The entity type '$tag' is not available - # }]] throw - # } - # puts stderr "$tag new -name $nq_name {*}$args" - set current_entity [$tag new -name $nq_name {*}$args] - } - # - # make sure that the current_entity has parser capabilities - # and the relevant state of the previous entity before the - # context switch - # TODO: refactor later - ${:block_parser} current_entity $current_entity - ${:block_parser} processed_section [current class] - $current_entity current_comment_line_type ${:current_comment_line_type} - $current_entity block_parser ${:block_parser} - } - - :method parse@tag {line} { - set args [lassign $line axes names] + lassign [apply [[current class] eval {set :lineproc}] {*}$line] axes names args set entity ${:partof_entity} set axes [split [string trimleft $axes @] .] @@ -2368,13 +2500,38 @@ set entity $res if {$entity eq ""} { - if {[QualifierTag info instances @$leaf(axis)] eq "" && [Tag info instances @$leaf(axis)] eq ""} { + set cmd [info commands @$leaf(axis)] + + # TODO interp-aliasing objects under different command names + # is currently not transparent to some ::nsf::* helpers, + # such as ::nsf::isobject. Should this be changed? + # + if {$cmd ne ""} { + set cmd [namespace origin $cmd] + set target [interp alias {} $cmd] + if {$target ne ""} { + set cmd $target + } + } + + if {$cmd eq "" || ![::nsf::isobject $cmd] || \ + ![$cmd info has type Tag]} { + ${:block_parser} cancel INVALIDTAG "The entity type '@$leaf(axis)' is not available." } + + # VERIFY! Still an issue? TODO: @object-method raises some + # issues (at least when processed without a resolved + # context = its partof entity). It is not an entity type, + # because it merely is a "scoped" @method. It won't + # resolve then as a proper instance of Tag, hence we + # observe an InvalidTag exception. For now, we just ignore + # and bypass this issue by allowing InvalidTag exceptions + # in analyze() + set entity [@$leaf(axis) new -name $leaf(name) {*}$args] } else { if {[$entity info lookup methods -source application @$leaf(axis)] eq ""} { -okup()) ${:block_parser} cancel INVALIDTAG "The tag '$leaf(axis)' is not supported for the entity type '[namespace tail [$entity info class]]'" } set entity [$entity @$leaf(axis) [list $leaf(name) {*}$args]] Index: library/nx/nx.nxd =================================================================== diff -u -r18ff1444fef5c209dfb40cf2ae694206c0d10309 -r26ce746b45449fbff64f88c6d9e9050a63b89449 --- library/nx/nx.nxd (.../nx.nxd) (revision 18ff1444fef5c209dfb40cf2ae694206c0d10309) +++ library/nx/nx.nxd (.../nx.nxd) (revision 26ce746b45449fbff64f88c6d9e9050a63b89449) @@ -1,56 +1,61 @@ # -*- Tcl -*- + # @package ::nx # -# The Next Scripting Language is a compact and expressive object-oriented language -# extension for Tcl. The object system model is highly influenced by -# CLOS. This package provides the basic object system for the Next -# language. It defines the basic language entities {{@class ::nx::Object}} and -# {{@class ::nx::Class}}, as well as essential language primitives -# (e.g., {{@command ::nx::next}} and {{@command ::nx::current}}). +# The <<@glossary nx>> is a compact and expressive object-oriented +# language extension for <<@Gls tcl>>. The object system model is highly +# influenced by <<@glossary clos>> and its off-springs (e.g., +# <<@glossary flavors>>). This package provides the basic object system for +# <<@glossary nx>>. It defines the basic language entities <<@class +# ::nx::Object>> and <<@class ::nx::Class>>, as well as essential +# language primitives (in particular, <<@command ::nx::next>> and <<@command +# ::nx::current>>). # # @require Tcl # @version 1.0.0a # @namespace ::nx # @class Object # -# Next Scripting Language (NSL) programs are constructed out of +# Programs written in the <<@glossary nx>> are constructed out of # objects. This class describes common structural and behavioural -# features for all NSL objects. It is the root object-class in the -# NSL object system. +# features for all <<@glossary nx>> objects. It is the root class in the +# <<@glossary nx>> object system. # @class Class # -# A {{@glossary class}} defines a family of object types which own a common set of -# attributes (see {{@class ::nx::Attribute}}) and methods. Classes -# are organised according to their similarities and differences in -# classification hierarchies. This object represents the root -# meta-class in the "Next" object system. +# A <<@gls class>> defines a family of object implementations and +# <<@glspl objtype>>, sharing a common set of <<@glspl attribute>> +# attributes (see <<@class ::nx::Attribute>>) and methods. Classes are +# organised according to their similarities and differences in +# classification hierarchies. This object represents the root <<@gls +# metaclass>> in the <<@glossary nx>> object system. # # @superclass ::nx::doc::entities::class::nx::Object # @class.method {Class alloc} # -# Creates a bare object or class which is not -# fully initialized. {{{alloc}}} is used by {{@class.method "::nx::Class create"}} to -# request a memory object storage. In subsequent steps, -# {{{create}}} invokes {{{configure}}} and {{{init}}} to further -# set up the object. Only in rare situations, you may consider -# bypassing the overall {{{create}}} mechanism by just allocating -# uninitialized objects using {{{alloc}}}. +# Creates a bare object or class which is not fully +# initialized. '''alloc''' is used by <<@class.method "::nx::Class +# create">> to request a memory object storage. In subsequent steps, +# '''create''' invokes '''configure''' and '''init''' to further set +# up the object. Only in rare situations, you may consider bypassing +# the overall '''create''' mechanism by just allocating uninitialized +# objects using '''alloc'''. # # @properties interally-called -# @parameter name The object identifier assigned to the object storage to be allocated. +# @parameter name The object identifier assigned to the object storage +# to be allocated. # @return The name of the allocated, uninitialized object # @class.method {Class create} # # Provides for creating application-level classes and objects. If -# the method receiver is a meta-class, a class will be -# created. Otherwise, {{{create}}} yields an object. {{{create}}} +# the method receiver is a <<@gls metaclass>>, a <<@gls class>> will be +# created. Otherwise, '''create''' yields an object. '''create''' # is responsible a multi-phase object creation scheme. This # creation scheme involves three major steps: -# {{{ +# ''' # [Object create anObject] (1) # ---------------. .--------------. # -------------->|Class->create()|-->|Class->alloc()| @@ -61,34 +66,33 @@ # | (3) .------. # .........>|init()| # `------' -# }}} -# (1) A call to {{@class.method "::nx::Class alloc"}} to create a raw, +# ''' +# (1) A call to <<@class.method "::nx::Class alloc">> to create a raw, # uninitalized object. # # (2) The newly allocated object receives a method call upon -# {{@class.method "::nx::Object configure"}}. This will establish the -# object's initial state, by applying object parameter values +# <<@class.method "::nx::Object configure">>. This will establish the +# object's initial state, by applying <<@gls objparam>> values # provided at object creation time and default values defined at # object definition time. # -# (3) Finally, {{{create}}} emits a call to the initialization -# method {{{init}}} (i.e., the actual "constructor"), if -# available. An {{{init}}} method can be defined by a class on -# behalf of its objects, to lay out class-specific initialisation -# behaviour. Alternatively, each single object may define an -# {{{init}}} method on its own. +# (3) Finally, '''create''' emits a call to the initialization method +# '''init''', if available. An '''init''' method can be defined by a +# class on behalf of its objects, to lay out class-specific +# initialisation behaviour. Alternatively, each single object may +# define an '''init''' method on its own. # -# By overloading the method in a meta-class, you can refine or +# By overloading the method in a <<@gls metaclass>>, you can refine or # replace this default object creation scheme (e.g., for applying # application-specific naming schemes). # -# For creating an object or a class, you must name {{{create}}} +# For creating an object or a class, you must name '''create''' # explicitly, i.e.: -# {{{ +# ''' # ::nx::Object create anObject # ::nx::Class create AClass # ::nx::Class AnotherClass; # This fails: "Method 'AnotherClass' unknown for ::nx::Class." -# }}} +# ''' # # @parameter name The designated identifier on the class or the object to be created. # @parameter args arguments to be passed down to the object creation @@ -98,14 +102,14 @@ # @class.method {Class dealloc} # # Marks objects for physical deletion in memory. Beware the fact -# that calling {{{dealloc}}} does not necessarily cause the object +# that calling '''dealloc''' does not necessarily cause the object # to be deleted immediately. Depending on the lifecycle of the the -# object's environment (e.g., the {{{interp}}}, the containing +# object's environment (e.g., the '''interp''', the containing # namespace) and on call references down the callstack, the actual # memory freeing operation may occur time-shifted (that is, -# later). While {{{dealloc}}} itself cannot be redefined for -# {{{::nx::Class}}}, you may consider refining it in a subclass or -# mixin class for customizing the destruction process. +# later). While '''dealloc''' itself cannot be redefined for +# '''::nx::Class''', you may consider refining it in a subclass or +# <<@gls mixincls>> for customizing the destruction process. # # @properties interally-called # @parameter object The name of the object to be scheduled for deletion. @@ -116,28 +120,28 @@ # scheme for resolving object naming conflicts in the dynamic and # scripted programming environment of "Next": An object or class is # created while an object or class with an identical object identifier -# already exists. The method {{{recreate}}} performs standard object +# already exists. The method '''recreate''' performs standard object # initialization, per default, after re-setting the state and # relationships of the object under recreation. -# {{{ +# ''' # Object create Bar # \# ... # Object create Bar; # calls Object->recreate(::Bar, ...) -# }}} -# By refining {{{recreate}}} in an application-level subclass or mixin +# ''' +# By refining '''recreate''' in an application-level subclass or mixin # class, you can intercept the recreation process. In the pre-part the -# refined {{{recreate}}} method, the recreated object has its old -# state, after calling {{@command ::nx::next}} it is cleaned up. +# refined '''recreate''' method, the recreated object has its old +# state, after calling <<@command ::nx::next>> it is cleaned up. # # If the name conflict occurs between an existing class and a newly -# created object (or vice versa), {{{recreate}}} is not -# performed. Rather, a sequence of {{@class.method "::nx::Object -# destroy"}} and {{@class.method "::nx::Class create"}} is triggered: -# {{{ +# created object (or vice versa), '''recreate''' is not +# performed. Rather, a sequence of <<@class.method "::nx::Object +# destroy">> and <<@class.method "::nx::Class create">> is triggered: +# ''' # Object create Bar # \# ... # Class create Bar; # calls Bar->destroy() + Class->create(::Bar, ...) -# }}} +# ''' # # @properties interally-called # @parameter name The name (identifier) of the object under recreation @@ -161,33 +165,34 @@ # # This method participates in the object creation process. It is # automatically invoked after having produced a new object by -# {{@class.method "::nx::Class create"}}. Upon its invocation, the -# variable argument vector {{{args}}} contains a list of parameters +# <<@class.method "::nx::Class create">>. Upon its invocation, the +# variable argument vector '''args''' contains a list of parameters # and parameter values passed in from the call site of object -# creation. They are matched against an object parameter +# creation. They are matched against an <<@gls objparam>> # definition. This definition, and so the actual method parameter # definition of this method, is assembled from configuration values of -# the classes along the precedence order (see also {{@class.method -# "::nx::Object objectparameter"}}). The method {{{configure}}} +# the classes along the precedence order (see also <<@class.method +# "::nx::Object objectparameter">>). The method '''configure''' # can be called at arbitrary times to "re-set" an object. # # @properties interally-called -# @parameter args The variable argument vector stores the object parameters and their values +# @parameter args The variable argument vector stores the object +# parameters and their values # # # # @class.method {Object destroy} # -# The standard destructor for an object. The method {{@class.method -# "::nx::Object destroy"}} triggers the physical destruction of -# the object. The method {{{destroy}}} can be refined by subclasses or -# mixin classes to add additional (class specific) destruction -# behavior. Note that in most cases, the class specific {{{destroy}}} -# methods should call {{@command ::nx::next}} to trigger physical -# destruction. -# {{{ +# The standard shutdown handler for any object which, finally, +# commands the physical destruction of the object. The method +# '''destroy''' can be refined by subclasses or <<@glspl mixincls>> to +# add additional (class-specific) shutdown behaviour. Note that, in +# most cases, the class-specific '''destroy''' methods are expected to +# call <<@command ::nx::next>> to ascertain the the physical +# destruction is requested. +# ''' # nx::Class create Foo { # :method destroy {} { # puts "destroying [self]" @@ -196,19 +201,19 @@ # } # Foo create f1 # f1 destroy -# }}} -# Technical details: The method {{@class.method "::nx::Object destroy"}} -# delegates the actual destruction to {{@class.method "::nx::Class -# dealloc"}} which clears the memory object storage. Essentially, the +# ''' +# Technical details: The method <<@class.method "::nx::Object destroy">> +# delegates the actual destruction to <<@class.method "::nx::Class +# dealloc">> which clears the memory object storage. Essentially, the # behaviour could be scripted as: -# {{{ +# ''' # Object method destroy {} { # [:info class] dealloc [self] # } -# }}} -# Note, however, that {{{destroy}}} is protected against +# ''' +# Note, however, that '''destroy''' is protected against # application-level redefinition. You must refine it in a subclass -# or mixin class. +# or a <<@gls mixincls>>. # @class.method {Object uplevel} @@ -217,7 +222,7 @@ # another callstack level (i.e., callstack frame). # # @parameter level:optional The starting callstack level (defaults to the -# value of {{{[current callinglevel]}}}) +# value of '''[current callinglevel]''') # @parameter script:list The script to be evaluated in the targeted # callstack level @@ -227,265 +232,233 @@ # residing at a different callstack level (frame). # # @parameter level:optional The starting callstack level (defaults to the -# value of {{{[current callinglevel]}}}) +# value of '''[current callinglevel]''') # # @parameter sourceVar A variable which should be linked to a ... # @parameter targetVar ... which is a local variable in a method scope # @see ... # @class.method {Object attribute} # -# This is a helper method which provides a convenient facade to -# definite attribute slots (with standard settings) on the object or -# class. +# This is a helper method which provides a convenient facade to define +# <<@glspl attribute>> (with standard settings) on the given object +# or the given class. # @class.method {Object volatile} # # By calling on this method, the object is bound in its lifetime to -# the one of call site (e.g., the given Tcl proc or method scope): -# {{{ +# the one of the active call site (e.g., the given <<@acr tcl>> proc or method +# scope): +# ''' # proc foo {} { # info vars; # shows "" # set x [Object create Bar -volatile] # info vars; # shows "x Bar" # } -# }}} -# Behind the scenes, {{{volatile}}} registers a C-level variable trace -# ({{{Tcl_TraceVar()}}}) on the hiddenly created local variable (e.g., -# {{{Bar}}}), firing upon unset events and deleting the referenced -# object ({{{Bar}}}). That is, once the callframe context of {{{foo}}} -# is left, the local variable {{{Bar}}} is unset and so the bound -# object is destroyed. +# ''' +# Behind the scenes, '''volatile''' registers a C-level variable trace +# ('''Tcl_TraceVar()''') on the hiddenly created local variable (e.g., +# '''Bar'''), firing upon unset events and deleting the referenced +# object ('''Bar'''). That is, once the callframe context of '''foo''' +# is left, the local variable '''Bar''' is unset and so the bound +# object destruction is triggered. # @class.method {Class new} # -# A convenience method to create auto-named objects and classes. It is -# a front-end to {{@class.method "::nx::Class create"}}. For instance: -# {{{ +# A convenience method to create auto-named objects and <<@glspl +# class>>. It is a front-end to <<@class.method "::nx::Class +# create">>. For instance: +# ''' # set obj [Object new] # set cls [Class new] -# }}} +# ''' # # This will provide object identifiers of the form -# e.g. {{{::nsf::__#0}}}. The uniqueness of auto-generated identifiers -# is guaranteed for the scope of the current {{{interp}}}. +# e.g. '''::nsf::__#0'''. The uniqueness of auto-generated identifiers +# is guaranteed for the scope of the current '''interp'''. # # @parameter -childof If provided, the new object is created as a child of # the specified object. -# @parameter args The variable arguments passed down to {{@class.method -# "::nx::Class create"}}. +# @parameter args The variable arguments passed down to <<@class.method +# "::nx::Class create">>. # @class.method {Class method} # -# Defines a per-class method, similarly to Tcl specifying -# {{{procs}}}. Optionally assertions may be specified by two -# additional arguments. Therefore, to specify only post-assertions -# an empty pre-assertion list must be given. All assertions are a -# list of ordinary Tcl {{{expr}}} statements. When {{{method}}} is -# called with an empty argument list and an empty body, the -# specified method is deleted. -# {{{ +# Defines a per-class method, similarly to <<@acr tcl>> specifying +# '''procs'''. Optionally, <<@glspl assert>> may be specified by two +# additional arguments. Therefore, to specify only post-assertions an +# empty pre-assertion list must be given. All assertions are a list of +# ordinary <<@Gls tcl>> '''expr''' statements. When '''method''' is called +# with an empty argument list and an empty body, the specified method, +# if existing, is deleted. +# ''' # Class create AClass { # :method foo args {;} # } # # AClass create anInstance # anInstance foo; # invokes "foo" -# }}} # +# AClass method foo {} {}; # deletes "foo" +# ''' +# # @parameter name The method name -# @parameter arguments:list A list specifying non-positional and positional parameters +# @parameter arguments:list A list specifying non-positional and +# positional parameters # @parameter body The script which forms the method body -# @parameter preAssertion Optional assertions that must hold before the proc executes -# @parameter postAssertion Optional assertions that must hold after the proc executes +# @parameter preAssertion Optional assertions that must hold before +# the proc executes +# @parameter postAssertion Optional assertions that must hold after +# the proc executes # @class.method {Object method} # -# Defines a per-object method, similarly to Tcl specifying -# {{{procs}}}. Optionally assertions may be specified by two +# Defines a per-object method, similarly to creating <<@tcl tcl>> +# '''procs'''. Optionally, <<@glspl assert>> may be specified by two # additional arguments. Therefore, to specify only post-assertions # an empty pre-assertion list must be given. All assertions are a -# list of ordinary Tcl {{{expr}}} statements. When {{{method}}} is +# list of ordinary <<@acr tcl>> '''expr''' statements. When '''method''' is # called with an empty argument list and an empty body, the # specified method is deleted. -# {{{ +# ''' # Object create anObject { # :method foo args {;} # } # anObject foo; # invokes "foo" -# }}} # -# @parameter name The method name -# @parameter arguments:list A list specifying non-positional and positional parameters -# @parameter body The script which forms the method body -# @parameter preAssertion Optional assertions that must hold before the proc executes -# @parameter postAssertion Optional assertions that must hold after the proc executes +# anObject method foo {} {}; # deletes "foo" +# ''' +# +# @parameter name The method name +# @parameter arguments:list A list specifying non-positional and +# positional parameters +# @parameter body The script which forms the method body +# @parameter preAssertion Optional assertions that must hold before +# the proc executes +# @parameter postAssertion Optional assertions that must hold after +# the proc executes # @class.method {Object forward} # -# Register a per-object method (similar to a {{{proc}}}) for -# forward-delegating calls to a callee (target Tcl command, other -# object). When the forwarder method is called, the actual arguments -# of the invocation are appended to the specified arguments. In -# callee an arguments certain substitutions can take place: +# Register a special-purpose per-object method (similar to a +# '''proc'''), referred to as a <<@gls forwarder>>, for +# forward-delegating calls to a callee (a <<@acr tcl>> command, a method owned +# by another object). When the <<@gls forwarder>> method is called, +# the actual arguments of the invocation are appended to the specified +# arguments. Certain manipulations can be applied on the +# forward-passed argument vector: # -# {{{%proc}}} substituted by name of the forwarder method +# '''%proc''' substituted by name of the forwarder method # -# {{{%self}}} substitute by name of the object +# '''%self''' substitute by name of the object # -# {{{%1}}} substitute by first argument of the invocation +# '''%1''' substitute by first argument of the invocation # -# {{{ {%@POS value} }}} substitute the specified value in the +# ''' {%@POS value} ''' substitute the specified value in the # argument list on position POS, where POS can be a positive or # negative integer or end. Positive integers specify the position # from the begin of the list, while negative integer specify the # position from the end. # -# {{{ {%argclindex LIST} }}} take the nth argument of the specified +# ''' {%argclindex LIST} ''' take the nth argument of the specified # list as substitution value, where n is the number of arguments # from the invocation. # -# {{{%%}}} a single percent. +# '''%%''' a single percent. # -# {{{%Tcl-command}}} command to be executed; substituted by result. +# '''%Tcl-command''' The command to be executed; the result of the +# command evaluation is substituted for the placeholding statement. # -# Additionally each argument can be prefixed by the positional prefix +# Additionally, each argument can be prefixed by the positional prefix # %@POS (note the delimiting space at the end) that can be used to # specify an explicit position. POS can be a positive or negative # integer or the word end. The positional arguments are evaluated from # left to right and should be used in ascending order. # -# @parameter name The name of the delegating or forward method -# @parameter -objscope:optional Causes the target to be evaluated in the scope of the object. -# @parameter -methodprefix Prepends the specified prefix to the second argument of the invocation. -# @parameter -default Is used for default method names (only in connection -# with %1) -# -# @parameter -earlybinding Look up the function pointer of the called Tcl -# command at definition time of the forwarder instead of invocation -# time. This option should only be used for calling C-implemented Tcl -# commands, no scripted procs -# -# @parameter -verbose Print the substituted command to stderr before -# executing - -# @parameter callee -# @parameter args - -# @class.method {Class forward} -# -# Register a per-class method (similar to a {{{proc}}}) for -# forward-delegating calls to a callee (target Tcl command, other -# object). When the forwarder method is called on an instance of the -# class, the actual arguments of the invocation are appended to the -# specified arguments. In callee an arguments certain substitutions -# can take place: -# -# {{{%proc}}} substituted by name of the forwarder method -# -# {{{%self}}} substitute by name of the object -# -# {{{%1}}} substitute by first argument of the invocation -# -# {{{ {%@POS value} }}} substitute the specified value in the -# argument list on position POS, where POS can be a positive or -# negative integer or end. Positive integers specify the position -# from the begin of the list, while negative integer specify the -# position from the end. -# -# {{{ {%argclindex LIST} }}} take the nth argument of the specified -# list as substitution value, where n is the number of arguments -# from the invocation. -# -# {{{%%}}} a single percent. -# -# {{{%Tcl-command}}} command to be executed; substituted by result. -# -# Additionally each argument can be prefixed by the positional prefix -# %@POS (note the delimiting space at the end) that can be used to -# specify an explicit position. POS can be a positive or negative -# integer or the word end. The positional arguments are evaluated from -# left to right and should be used in ascending order. -# -# @parameter name The name of the delegating or forward method -# @parameter -objscope:optional Causes the target to be evaluated in the -# scope of the object. +# @parameter name The name of the delegating or forwarder method +# @parameter -objscope:optional Causes the target to be evaluated in +# the scope of the object. # @parameter -methodprefix Prepends the specified prefix to the second # argument of the invocation. # @parameter -default Is used for default method names (only in # connection with %1) -# @parameter -earlybinding Look up the function pointer of the called -# Tcl command at definition time of the forwarder instead of -# invocation time. This option should only be used for calling -# C-implemented Tcl commands, no scripted procs +# @parameter -earlybinding Look up the function pointer of the called <<@acr tcl>> +# command at definition time of the forwarder rather than at invocation +# time. This option should only be used for calling C-implemented +# commands, e.g., a <<@Gls cim>>, not scripted ones. # @parameter -verbose Print the substituted command to stderr before # executing # @parameter callee # @parameter args +# @class.method {Class forward} +# +# @use class.method {Object forward} + # @class.method {Object info} # # Provides introspection on objects. A variety of introspection -# options exists. {{{info}}} is implemented as en ensemble -# object. Hence, the introspection options turn into proper -# sub-methods. +# options exists. '''info''' is implemented as an <<@gls +# ensemble>>. Hence, the introspection options turn into proper +# submethods. # -# @sub-method callable -# @sub-method has -# @sub-method filter -# @sub-method is Binds all introspection facilities offered by -# {{{::nsf::is}}} to the object, i.e., the object is automatically -# folded in as the first argument passed to {{{::nsf::is}}} -# @sub-method mixin +# @sub-method callable +# @sub-method has +# @sub-method filter +# @sub-method is Binds all introspection facilities offered by +# '''::nsf::is''' to the object, i.e., +# the object is automatically folded in +# as the first argument passed +# to '''::nsf::is''' +# @sub-method mixin # @class.method {Object "info callable method"} # -# Verifies whether there is a method under a given name available -# for invocation upon the object. In case, the introspective call -# returns the corresponding method handle. If there is no so named +# Verifies whether there is a method under a given name available for +# invocation upon the object. In case, the introspective call returns +# the corresponding <<@gls method_handle>>. If there is no so-named # method available, an empty string is returned. # @class.method {Object "info callable filter"} # # Search for a method which is currently registered as a filter (in # the invocation scope of the given object). If found, the -# corresponding method handle is returned. +# corresponding <<@gls method_handle>> is returned. # @class.method {Object "info children"} # # Computes the list of aggregated (or nested) objects. The resulting -# list reports the fully qualified object names. If a name pattern -# was specified, all matching child objects are returned. Otherwise, -# all children are reported. +# list reports the fully qualified object names. If a <<@gls +# namepattern>> was specified, all matching child objects are +# returned. Otherwise, all children are reported. - # @class.method {Object "info class"} # # Gives the name of the class of the current object. # @class.method {Object "info filter guard"} # -# Returns the guards for filter identified by a filter name +# Returns the guards for filter identified by a <<@gls filter>> name # @class.method {Object "info filter methods"} # -# Returns a list of methods registered as filters. +# Returns a list of methods registered as <<@glspl filter>>. # @class.method {Object "info forward"} # -# Provides you with the list of forwarders defined for the given +# Provides you with the list of <<@glspl forwarder>> defined for the given # object. # @class.method {Object "info has mixin"} # -# Verifies in a boolean test whether the object has the given class -# registered as a mixin class. +# Verifies in a boolean test whether the object has the given <<@gls class>> +# registered as a <<@gls mixincls>>. -# @class.method {Object "info has namespace"} Some words on info has type +# @class.method {Object "info has namespace"} # -# Tells you whether the object has a companion, per-object Tcl +# Tells you whether the object has a companion, per-object <<@acr tcl>> # namespace. Note that the results do not necessarily correspond to -# those yielded by {{{[namespace exists /obj/]}}}. +# those yielded by '''[namespace exists /obj/]'''. # @class.method {Object "info has type"} # @@ -500,12 +473,12 @@ # @class.method {Object "info mixin guard"} # -# Retrieves the guards applied to the mixin class idenitified by the -# mixin class name +# Retrieves the <<@glspl guard>> applied to the mixin class +# idenitified by the mixin class name # @class.method {Object "info mixin classes"} # -# The list of per-object mixin classes currently registered for the +# The list of per-object <<@glspl mixincls>> currently registered for the # object is returned. # @class.method {Object "info parent"} @@ -516,29 +489,31 @@ # @class.method {Object "info precedence"} # # Presents to you the list of classes the object is inheriting -# attributes and methods, ordered according to their precedence. +# attributes and methods, ordered according to their <<@gls +# precedence>>. # @class.method {Object "info slotobjects"} # # Assembles the list of slot objects which apply the given -# object. They are resolved by following the class precedence list -# upward and coercing the lists of slots provided by these classes. +# object. They are resolved by following the <<@gls class>> <<@gls +# precedence>> upward and coercing the lists of slots provided by +# these <<@glspl class>>. # @class.method {Object "info vars"} # # Yields a list of variable names created and defined on the object. # @class Slot # -# A slot is a meta-object that manages property changes of +# A <<@gls slot>> is a meta-object that manages property changes of # objects. A property is either an attribute or a role taken by an # object in an inter-object relation (e.g., in system slots). The -# predefined system slots are {{{class}}}, {{{superclass}}}, -# {{{mixin}}}, and {{{filter}}}. These slots appear as methods of -# {{@class ::nx::Object}} or {{@class ::nx::Class}}. The slots +# predefined system slots are '''class''', '''superclass''', +# '''mixin''', and '''filter'''. These slots appear as methods of +# <<@class ::nx::Object>> or <<@class ::nx::Class>>. The slots # provide a common getter and setter interface. Every multivalued -# slot provides e.g. a method {{{add}}} to append a value to the -# list of values, and a method {{{delete}}} which removes it. +# slot provides e.g. a method '''add''' to append a value to the +# list of values, and a method '''delete''' which removes it. # # @superclass ::nx::doc::entities::class::nx::Object @@ -548,7 +523,8 @@ # @class.attribute {Slot name} # -# Name of the slot which can be used to access the slot from an object +# Name of the <<@gls slot>> which can be used to access the <<@gls +# slot>> data from an object # @class.attribute {Slot multivalued} # @@ -564,21 +540,23 @@ # @class.attribute {Slot type} # -# You may specify a type constraint on the value range to managed by the slot +# You may specify a type constraint on the value range to managed by +# the <<@gls slot>> # @class.attribute {ObjectParameterSlot name} # -# Name of the slot which can be used to access the slot from an -# object. It defaults to unqualified name of an instance. +# Name of the <<@gls slot>> which can be used to access the <<@gls +# slot>> data of an object. It defaults to unqualified name of an +# instance. # @class.attribute {ObjectParameterSlot methodname} # # The name of the accessor methods to be registed on behalf of the -# slot object with its domains can vary from the slot name. +# <<@gls slot>> object with its domains can vary from the slot name. # @class.attribute {ObjectParameterSlot domain} # -# The domain (object or class) of a slot on which it can be used +# The domain (object or class) of a <<@gls slot>> on which it can be used # @class.attribute {ObjectParameterSlot defaultmethods} # @@ -587,13 +565,13 @@ # @class.attribute {ObjectParameterSlot manager} # -# The manager object of the slot (per default, the slot object takes -# this role, i.e. {{{[self]}}}) +# The manager object of the <<@gls slot>> (per default, the slot object takes +# this role, i.e. '''[self]''') # @class.attribute {ObjectParameterSlot per-object} # -# If set to {{{true}}}, the accessor methods are registered with the -# domain object scope only. It defaults to {{{false}}}. +# If set to '''true''', the accessor methods are registered with the +# domain object scope only. It defaults to '''false'''. # @class.method {Object objectparameter} @@ -603,104 +581,242 @@ # generell: setter kann hier mit der methode namens "setter" # verwechselt werden; wir sollten hier die parameter syntax # anfuehren, die allerdings in zwei varianten kommt: -#{{{ +#''' # obj superclass ?value? # obj superclass add|assign|delete|get value -#}}} +#''' # Das gilt allgemein, nicht nur für die relation-slots, sondern # für alle incremental slots. -# **** {{{superclass}}} changes the list +# **** '''superclass''' changes the list # of superclasses. When used as a getter, the method returns the # current superclasses. # # @return :list If called as a getter (without arguments), -# {{{superclass}}} returns the current superclasses of the object +# '''superclass''' returns the current superclasses of the object # @class.attribute {Object class} # -# Sets or retrieves the class of an object. When {{{class}}} is +# Sets or retrieves the <<@gls class>> of an object. When '''class''' is # called without arguments, it returns the current class of the -# object. An introspective alternative is {{@class.method {Object -# "info class"}}} +# object. An introspective alternative is <<@class.method {Object +# "info class"}>> # -# @return If called as a getter (without arguments), {{{class}}} -# returns the current class of the object +# @return If called as a getter (without arguments), '''class''' +# returns the current <<@gls class>> of the object # @class.attribute {Object mixin} # -# As a setter, {{{mixin}}} specifies a list of mixins to set. Every -# mixin must be an existing class. In getter mode, you can retrieve -# the list of mixins active for the given object. As for introspecting -# mixin classes, consider {{@class.method {Object "info mixin classes"}}} +# As a setter, '''mixin''' specifies a list of <<@glspl mixincls>> to +# set. Every mixin must be an existing class. In getter mode, you can +# retrieve the list of <<@glspl mixincls>> active for the given object. As for +# introspecting <<@glspl mixincls>>, consider <<@class.method {Object "info +# mixin classes"}>> # # @return :list If called as a getter (without arguments), -# {{{mixin}}} returns the list of current mixin classes registered +# '''mixin''' returns the list of current <<@glspl mixincls>> registered # with the object # @class.attribute {Object filter} # -# In its setter mode, {{{filter}}} allows you to register methods as -# per-object filters. Every filter must be an existing method in the -# scope of the object. When acting as a getter, you can retrieve the -# list of filter methods active for the given object. See also -# {{@class.method {Object "info filter methods"}}}. +# In its setter mode, '''filter''' allows you to register methods as +# per-object <<@glspl filter>>. Every <<@gls filter>> must be an +# existing method in the scope of the object. When acting as a getter, +# you can retrieve the list of filter methods active for the given +# object. See also <<@class.method {Object "info filter methods"}>>. # # @return :list If called as a getter (without arguments), -# {{{filter}}} returns the list of current filters +# '''filter''' returns the list of current filters # registered with the object # @class.attribute {Class mixin} # -# As a setter, {{{mixin}}} specifies a list of mixins to set for -# the class. Every mixin must be an existing class. In getter -# mode, you can retrieve the list of mixins active for the given -# class. +# As a setter, '''mixin''' specifies a list of <<@glspl mixincls>> to +# set for the class. Every <<@gls mixincls>> must be an existing +# class. In getter mode, you can retrieve the list of <<@glspl +# mixincls>> active for the given class. # -# @return :list If called as a getter (without arguments), {{{mixin}}} -# returns the list of current mixin classes registered with the class +# @return :list If called as a getter (without arguments), '''mixin''' +# returns the list of current <<@glspl mixincls>> registered with the class # @class.attribute {Class filter} # -# In its setter mode, {{{filter}}} allows you to register methods -# as per-class filters. Every filter must be an existing method +# In its setter mode, '''filter''' allows you to register methods +# as per-class <<@glspl filter>>. Every filter must be an existing method # in the scope of the class. When acting as a getter, you can -# retrieve the list of filter methods active for the given class. +# retrieve the list of <<@gls filter>> methods active for the given class. # # @return :list If called as a getter (without arguments), -# {{{filter}}} returns the list of current filters +# '''filter''' returns the list of current filters # registered with the class # @class Attribute # -# Attribute slots are used to manage the access, mutation, and -# querying of instance variables. One defines Attribute slots for -# objects and classes usually via the helper method {{@class.method -# "::nx::Object attribute"}} **** TODO STEFAN, kein Link? GEPLANT? -# MIT 2 GESCHWEIFTEN KLAMMER UM SALARY GIBT ES EINEN LAUFZEITFEHLER??? -# ******** The following example defines a class with three attribute -# slots. The attribute {salary} has a default of {0}, the attribute -# {projects} has the empty list as default and is defined as -# multivalued. -# {{{ +# Attribute <<@glspl slot>> are used to manage the access, mutation, +# and querying of instance variables. One defines attribute slots for +# objects and classes usually via the helper method <<@class.method +# "::nx::Object attribute">> The following example defines a class +# with three attribute slots. The attribute '''salary''' has a default +# of '''0''', the attribute '''projects''' has the empty list as +# default and is defined as multivalued. +# ''' # Class create Person { # :attribute name # :attribute {salary:integer 0} # :attribute {projects:multivalued ""} { # set :incremental true # } # } -# }}} +# ''' # # @parameter incremental A boolean value, only useful for multivalued # slots. When set, one can add/delete incrementally values to the -# multivalued set (e.g., through an incremental {{{add}}}) -# @parameter valuecmd A Tcl command to be executed whenever the managed +# multivalued set (e.g., through an incremental '''add''') +# @parameter valuecmd A <<@acr tcl>> command to be executed whenever the managed # object variable is read -# @parameter valuechangedcmd A Tcl command to be executed whenever the +# @parameter valuechangedcmd A <<@acr tcl>> command to be executed whenever the # value of the managed object variable changes # @parameter arg # @superclass ::nx::doc::entities::class::nx::ObjectParameterSlot +# @glossary tcl +# +# @acronym Tcl +# @pretty_name Tool Command Language + +# @glossary clos +# +# @pretty_name Common Lisp Object System +# @acronym CLOS + +# @glossary flavors +# +# @pretty_name Flavors + +# @glossary nx +# +# The Next Scripting Language (Nx) is one of the languages hosted by +# and implemented on top of the Next Scripting Framework (NSF). +# +# @pretty_name Next Scripting Language +# @acronym Nx + +# @glossary objtype +# +# The type of an object is given by its signature interface. While <<@acr tcl>> +# and so NSF object systems are mono-typed (i.e., everything has a +# string representation to the interpreter), object-types are lately +# checked and verified (e.g., upon method lookup). +# +# @pretty_name Object-type +# @pretty_plural Object-types + + +# @glossary metaclass +# +# A meta-class defines a minimal set of shared state structure and +# behaviour for a family of classes. +# +# @pretty_name Meta-class +# @pretty_plural Meta-classes + +# @glossary attribute +# +# An attribute describes a structural feature of a class or an +# object. An attribute has different runtime representations: An +# attribute slot acts as a managing object, there are same-named +# accessor and mutator methods and, finally, object variables carrying +# the actual attribute data. +# +# @pretty_name Attribute +# @pretty_plural Attributes + +# @glossary mixincls +# +# A mixin is realised by an otherwise ordinary class which is put in a +# dedicated mixin relation to another object or class. Hence, we refer +# to such classes as mixin-classes. If the mixing target is another +# mixin-class, we refer to the source mixin-class as a transitive +# mixin-class. +# +# @pretty_name Mixin-class +# @pretty_plural Mixin-classes + +# @glossary objparam +# +# @pretty_name Object parameter +# @pretty_plural Object parameters + +# @glossary assert +# +# Following a Design-by-Contract approach, you may define pre- and +# post-conditions on per-object and per-class methods. +# +# @pretty_name Assertion +# @pretty_plural Assertions + +# @glossary forwarder +# +# A forwarder is a method-level delegation mechanism to realise a +# variety of programming techniques (e.g., signature adapters, method +# decorators). The forward-owning object (or class) exposes the +# forwarder as a method (e.g., in its signature interface and through +# method-level introspection). Delegation targets are not limited to +# other methods, arbitrary <<@acr tcl>> command statements can be +# used. Forwarders come with a filtering protocol which allows to +# manipulate the argument vector processed by the forwarder. +# +# @pretty_name Forwarder +# @pretty_plural Forwarders + +# @glossary ensemble +# +# An ensemble is an auxiliary object which acts as a single method of +# another object. The ensemble's per-object methods (the so-called +# ensemble methods), however, so appear as submethods of this +# top-level method. This ressembles the ideas of subcommands and +# namespace ensembles in <<@acr tcl>>. When sending a message to an +# object, methods are identified as message receivers by name. This +# name can be simple (i.e., a single <<@acr tcl>> word) or composite +# (i.e., multiple <<@acr tcl>> words) in the case of +# submethods. Submethods are identified by their composite method +# names. +# +# @pretty_name Ensemble +# @pretty_plural Ensembles + +# @glossary filter +# +# An object filter implementes the idea of a composition filters in NSF. +# +# @pretty_name Filter +# @pretty_plural Filters + +# @glossary namepattern +# +# @pretty_name Name pattern +# @pretty_plural Name patterns + +# @glossary guard +# +# A guard acts as ... +# +# @pretty_name Guard +# @pretty_plural Guards + +# @glossary precedence +# +# ... +# +# @pretty_name Precedence order +# @pretty_plural Precedence orders + +# @glossary slot +# +# ... +# +# @pretty_name Slot +# @pretty_plural Slots + # @glossary class # # A class represents a family of object sharing a minimal common @@ -716,7 +832,6 @@ # @pretty_name Method handle # @pretty_plural Method handles - # @glossary cim # # In Tcl/XOTcl/NSF, methods can either be scripted or implemented as a @@ -725,10 +840,3 @@ # @acronym CIM # @pretty_name C-implemented method # @pretty_plural C-implemented methods - -# {{@gls class}} -# {{@Gls class}} -# {{@glspl class}} -# {{@Glspl class}} -# {{@acr cim}} -> CIM -# {{@acrpl cim}} -> CIMs \ No newline at end of file