api_proc_documentation (public)
api_proc_documentation [ -format format ] [ -script ] [ -source ] \ [ -xql ] [ -label label ] [ -first_line_tag first_line_tag ] \ [ -proc_type proc_type ] proc_name
Defined in packages/acs-api-browser/tcl/acs-api-documentation-procs.tcl
Generates formatted documentation for a procedure.
- Switches:
- -format (optional)
- the type of documentation to generate. This parameter is deprecated and has no effect.
- -script (optional, boolean)
- include information about what script this proc lives in?
- -source (optional, boolean)
- include the source code for the script?
- -xql (optional, boolean)
- include the source code for the related xql files?
- -label (optional)
- the label printed for the proc in the header line
- -first_line_tag (optional, defaults to
"<h3>"
)- tag for the markup of the first line
- -proc_type (optional)
- Parameters:
- proc_name (required)
- the name of the procedure for which to generate documentation.
- Returns:
- the formatted documentation string.
- Error:
- if the procedure is not defined.
- Partial Call Graph (max 5 caller/called nodes):
- Testcases:
- acs_api_browser_api_proc_documentation
Source code: # # Sanitize input # if {[string match *::::* $proc_name]} { ad_log warning "api_proc_documentation: received invalid proc_name <$proc_name>, try to sanitize" regsub -all -- {::::} $proc_name :: proc_name } if {[info exists format] && ![aa_test_running_p]} { ad_log warning "-format flag is deprecated and has no effect" } array set doc_elements { flags "" default_values "" switches0 "" switches1 "" positionals "" varargs_p 0 script "" deprecated_p 0 main "" } array set doc_elements [nsv_get api_proc_doc $proc_name] array set flags $doc_elements(flags) array set default_values $doc_elements(default_values) if {![info exists label]} { if {[llength $proc_name] > 1 && [namespace which ::xo::api] ne ""} { set label [::xo::api method_label $proc_name] } else { set label $proc_name } } if { $script_p } { set pretty_name [api_proc_pretty_name -include_debug_controls -proc_type $proc_type -label $label $proc_name] } else { set pretty_name [api_proc_pretty_name -include_debug_controls -link -proc_type $proc_type -label $label $proc_name] } if {[regexp {<([^ >]+)} $first_line_tag match tag]} { set end_tag "</$tag>" } else { set first_line_tag "<h3>" set end_tag "</h3>" } append out $first_line_tag$pretty_name$end_tag if {[regexp {^(.*) (inst)?proc (.*)$} $proc_name match cl prefix method] && [namespace which ::xo::api] ne "" } { set xotclArgs 1 set scope "" # # Since we get "method" via regexp, we have to remove the # curly brackets for ensemble methods # set method [lindex $method 0] regexp {^(.+) (.+)$} $cl match scope cl if {$prefix eq ""} { set pretty_proc_name "[::xo::api object_link $scope $cl] $method" } else { set pretty_proc_name [subst {<i><instance of [::xo::api object_link $scope $cl]></i> $method}] } # # Make sure we have the newest update in the nsv # ::xo::api update_object_doc $scope [expr {[string match ::* $cl] ? $cl :"::$cl"}] "" } else { set xotclArgs 0 if {[namespace which ::xo::api] ne "" && [::xo::api isobject "" [lindex $proc_name 1]]} { set name [lindex $proc_name 1] set pretty_proc_name "[$name info class] [::xo::api object_link {} $name]" } else { set pretty_proc_name $proc_name } } lappend command_line $pretty_proc_name foreach switch $doc_elements(switches0) { lappend command_line [api_proc_format_switch $xotclArgs $flags($switch) $switch] } set counter 0 foreach positional $doc_elements(positionals) { if { [info exists default_values($positional)] } { lappend command_line "\[ <i>$positional</i> \]" } else { lappend command_line "<i>$positional</i>" } } if { $doc_elements(varargs_p) } { lappend command_line "\[ <i>args</i>... \]" } foreach switch $doc_elements(switches1) { lappend command_line [api_proc_format_switch $xotclArgs $flags($switch) $switch] } append out [util_wrap_list $command_line] set intro_out "" if { $script_p } { append intro_out [subst {<p>Defined in <a href="/api-doc/procs-file-view?path=[ns_urlencode $doc_elements(script)]">$doc_elements(script)</a> <p>}] } if { $doc_elements(deprecated_p) } { append intro_out "<b><i>Deprecated." if { $doc_elements(warn_p) } { append intro_out " Invoking this procedure generates a warning." } append intro_out "</i></b><p>\n" } set main [lindex $doc_elements(main) 0] if {$main ne ""} { append intro_out "<p>[lindex $doc_elements(main) 0]\n<p>\n" } set blocks_out "<dl>\n" if { [info exists doc_elements(param)] } { foreach param $doc_elements(param) { if { [regexp {^([^ \t\n]+)[ \t\n]+(.*)$} $param "" name value] } { set params($name) $value } } } set switches [concat $doc_elements(switches0) $doc_elements(switches1)] if { [llength $switches] > 0 } { append blocks_out "<dt>Switches:</dt><dd><dl class='api-doc-parameter-list'>\n" foreach switch $switches { #ns_log notice "==== switch '$switch': flags <$flags($switch)>" set details [api_proc_pretty_param_details -flags $flags($switch) {*}[expr {[info exists default_values($switch)] ? [list -default_value $default_values($switch)] : {}}] ] append blocks_out "<dt>-$switch <i style='font-weight: normal;'>$details</i></dt>" if { [info exists params($switch)] } { append blocks_out "<dd>$params($switch)</dd>" } } append blocks_out "</dl></dd>\n" } if { [llength $doc_elements(positionals)] > 0 } { append blocks_out "<dt>Parameters:</dt><dd><dl class='api-doc-parameter-list'>\n" foreach positional $doc_elements(positionals) { #ns_log notice "==== parameter '$positional': info exists flags($positional): [info exists flags($positional)]" set pflags [expr {[info exists flags($positional)] ? $flags($positional) : {}}] if {![info exists default_values($positional)]} { lappend pflags required } set details [api_proc_pretty_param_details -flags $pflags {*}[expr {[info exists default_values($positional)] ? [list -default_value $default_values($positional)] : {}}] ] append blocks_out "<dt>$positional <i style='font-weight: normal;'>$details</i></dt><dd>" if { [info exists params($positional)] } { append blocks_out $params($positional) } append blocks_out "</dd>\n" } append blocks_out "</dl></dd>\n" } # @option is used in template:: and cms:: (and maybe should be used in some other # things like ad_form which have internal arg parsers. although an option # and a switch are the same thing, just one is parsed in the proc itself rather than # by ad_proc. if { [info exists doc_elements(option)] } { append blocks_out "<b>Options:</b><dl>" foreach param $doc_elements(option) { if { [regexp {^([^ \t]+)[ \t](.+)$} $param "" name value] } { append blocks_out "<dt>-$name</dt><dd>$value<br></dd>" } } append blocks_out "</dl>" } if { [info exists doc_elements(return)] } { append blocks_out "<dt>Returns:</dt><dd>[join $doc_elements(return) "<br>"]</dd>\n" } if { [info exists doc_elements(error)] } { append blocks_out "<dt>Error:</dt><dd>[join $doc_elements(error) "<br>"]</dd>\n" } append blocks_out [::apidoc::format_common_elements doc_elements] set css { /*svg g a:link {text-decoration: none;}*/ div.inner svg {width: 100%; margin: 0 auto;} svg g polygon {fill: transparent;} svg g g ellipse {fill: #eeeef4;} svg g g polygon {fill: #f4f4e4;} } if {![regexp { (Class|Object) } $proc_name]} { if {![regexp { (inst)?proc } $proc_name]} { #ns_log notice "Compute call graph from <$proc_name>" set callgraph [util::inline_svg_from_dot -css $css [api_call_graph_snippet -proc_name $proc_name -maxnodes 5]] if {$callgraph ne ""} { append blocks_out "<p><dt>Partial Call Graph (max 5 caller/called nodes):</dt><dd>$callgraph</dd>\n" } } } else { set objName [::xo::api object_from_proc_index $proc_name] if {[nsf::is object,type=::nx::Object $objName] && ![nsf::is object,type=::nx::Class $objName]} { append blocks_out <blockquote><ul> foreach m [$objName info lookup methods -callprotection public -source application] { set definition [nx::Object info method definition [$objName info lookup method $m]] # # Currently, "info lookup syntax" does not work for aliases # if {[lindex $definition end-2] eq "alias"} { set targetMethod [lindex $definition end] unset -nocomplain methodSyntax if {[nsf::cmd::info type $targetMethod] eq "cmd"} { # # We have an alias to a plain command. Try # executing the plain command and let's hope, # it gives us a syntax. # try { $targetMethod } on error {errorMsg} { if {[regexp {"([^\"]+)"} [lindex [split $errorMsg \n] 0] . syntax]} { set methodSyntax "$objName $m [lrange $syntax 1 end]" } } } else { ns_log notice "unknown type '[nsf::cmd::info type $targetMethod]'" "for alias for '$targetMethod'" "used in [list $objName info lookup syntax $m]" } if {![info exists methodSyntax]} { set methodSyntax "$objName $m ..." } } else { set methodSyntax "$objName $m [$objName info lookup syntax $m]" } set containerObject [lindex $definition 0] if {$containerObject ne $objName} { # # The method is defined on a class # set methodSyntax [xo::api method_link -label $methodSyntax $containerObject instproc $m] } else { set methodSyntax [xo::api method_link -label $methodSyntax $containerObject proc $m] } append blocks_out "<li><i>$methodSyntax</i></li>\n" } append blocks_out </ul></blockquote> } } append blocks_out "<p><dt>Testcases:</dt><dd>\n" if {[info exists doc_elements(testcase)]} { set cases {} foreach testcase_pair $doc_elements(testcase) { set url [api_test_case_url $testcase_pair] lappend cases [subst {<a href="[ns_quotehtml $url]">[ns_quotehtml [lindex $testcase_pair 0]]</a>}] } append blocks_out [join $cases {, }] } else { append blocks_out "No testcase defined." } append blocks_out "</dd>\n</dl>\n" if { $source_p } { if {[parameter::get_from_package_key -package_key acs-api-browser -parameter FancySourceFormattingP -default 1]} { set source_out [subst {<dt>Source code:</dt><dd> <pre class="code">[::apidoc::tcl_to_html $proc_name]</pre> </dd> }] } else { set source_out [subst {<dt>Source code:</dt><dd> <pre class="code">[ns_quotehtml [api_get_body $proc_name]]</pre> </dd> }] } } else { set source_out "" } set xql_base_name $::acs::rootdir/ append xql_base_name [file rootname $doc_elements(script)] if { $xql_p } { set there {} set missing {} set xql_fn [file rootname $doc_elements(script)].xql if { [file exists $::acs::rootdir/$xql_fn] } { set content [apidoc::get_xql_snippet -proc_name $proc_name -xql_file $xql_fn] if {$content ne ""} {set content "<pre class='code'>$content</pre>"} append there [subst {<dt>Generic XQL file:</dt> <dd>$content <a href="[ns_quotehtml [export_vars -base content-page-view {{source_p 1} {path $xql_fn}}]]">$xql_fn</a> <p> </dd> }] } else { lappend missing Generic } set xql_fn [file rootname $doc_elements(script)]-postgresql.xql if { [file exists $::acs::rootdir/$xql_fn] } { set content [apidoc::get_xql_snippet -proc_name $proc_name -xql_file $xql_fn] if {$content ne ""} {set content "<pre class='code'>$content</pre>"} set href [export_vars -base content-page-view {{source_p 1} {path $xql_fn}}] append there [subst {<dt>PostgreSQL XQL file:</dt> <dd>$content <a href="[ns_quotehtml $href]">$xql_fn</a> <p> </dd> }] } else { lappend missing PostgreSQL } set xql_fn [file rootname $doc_elements(script)]-oracle.xql if { [file exists $::acs::rootdir/$xql_fn] } { set content [apidoc::get_xql_snippet -proc_name $proc_name -xql_file $xql_fn] if {$content ne ""} {set content "<pre class='code'>$content</pre>"} set href [export_vars -base content-page-view {{source_p 1} {path $xql_fn}}] append there [subst {<dt>Oracle XQL file:</dt> <dd>$content <a href="[ns_quotehtml $href]">$xql_fn</a> <p> </dd> }] } else { lappend missing Oracle } if {[llength $missing] > 0} { set xql_out [subst {<dt>XQL Not present:</dt><dd>[join $missing ", "]</dd>}] } append xql_out $there } else { set xql_out "" } set out_sections $intro_out$blocks_out$source_out$xql_out if {$out_sections ne ""} { append out <blockquote>$out_sections</blockquote> } # No "see also" yet. return $outXQL Not present: Generic, PostgreSQL, Oracle