[comment {--- punk::docgen generated from inline doctools comments ---}] [comment {--- punk::docgen DO NOT EDIT DOCS HERE UNLESS YOU REMOVE THESE COMMENT LINES ---}] [comment {--- punk::docgen overwrites this file ---}] [manpage_begin punkshell_module_punk::cap 0 0.1.0] [copyright "2023 JMNoble - BSD licensed"] [titledesc {capability provider and handler plugin system}] [moddesc {punk capabilities plugin system}] [require punk::cap] [description] [keywords module capability plugin] [section Overview] [para]punk::cap provides management of named capabilities and the provider packages and handler packages that implement a pluggable capability. [para]see also [uri https://core.tcl-lang.org/tcllib/doc/trunk/embedded/md/tcllib/files/modules/pluginmgr/pluginmgr.md {tcllib pluginmgr}] for an alternative which uses safe interpreters [subsection Concepts] [para]A [term capability] may be something like providing a folder of files, or just a data dictionary, and/or an API [para][term {capability handler}] - a package/namespace which may provide validation and standardised ways of looking up provider data registered (or not) using register_capabilityname [para][term {capability provider}] - a package which registers as providing one or more capablities. [para]registered using register_package the capabilitylist is a list of 2-element lists where the first element is the capabilityname and the second element is a (possibly empty) dict of data relevant to that capability A capabilityname may appear multiple times. ie a package may register that it provides the capability with multiple datasets. [section API] [subsection {Namespace punk::cap::class}] [para] class definitions [list_begin itemized] [comment {- punk::cap::class groupings -}] [item] [para] [emph {handler_classes}] [list_begin enumerated] [enum] CLASS [class interface_caphandler.registry] [list_begin definitions] [para] [emph METHODS] [call class::interface_caphandler.registry [method pkg_register] [arg pkg] [arg capname] [arg capdict] [arg fullcapabilitylist]] handler may override and return 0 (indicating don't register)e.g if pkg capdict data wasn't valid overridden handler must be able to handle multiple calls for same pkg - but it may return 1 or 0 as it wishes. [call class::interface_caphandler.registry [method pkg_unregister] [arg pkg]] [list_end] [enum] CLASS [class interface_caphandler.sysapi] [list_begin definitions] [para] [emph METHODS] [list_end] [list_end] [comment {- end enumeration handler classes -}] [item] [para] [emph {provider_classes}] [list_begin enumerated] [enum] CLASS [class interface_cappprovider.registration] [para]Your provider package will need to instantiate this object under a sub-namespace called [namespace capsystem] within your package namespace. [para]If your package namespace is mypackages::providerpkg then the object command would be at mypackages::providerpkg::capsystem::capprovider.registration [para]Example code for your provider package to evaluate within its namespace: [example { namespace eval capsystem { if {[info commands capprovider.registration] eq ""} { punk::cap::class::interface_capprovider.registration create capprovider.registration oo::objdefine capprovider.registration { method get_declarations {} { set decls [list] lappend decls [list punk.templates {relpath ../templates}] lappend decls [list another_capability_name {somekey blah key2 etc}] return $decls } } } } }] [para] The above example declares that your package can be registered as a provider for the capabilities named 'punk.templates' and 'another_capability_name' [list_begin definitions] [para] [emph METHODS] [list_end] [enum] CLASS [class interface_capprovider.provider] [para] Your provider package will need to instantiate this directly under it's own namespace with the command name of [emph {provider}] [example { namespace eval mypackages::providerpkg { punk::cap::class::interface_capprovider.provider create provider mypackages::providerpkg } }] [list_begin definitions] [para] [emph METHODS] [call class::interface_capprovider.provider [method constructor] [arg providerpkg]] [comment {- -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---}] [call class::interface_capprovider.provider [method register] [opt capabilityname_glob]] [para]This is the mechanism by which a user of your provider package will register your package as a provider of the capability named. [para]A user of your provider may elect to register all your declared capabilities: [example { package require mypackages::providerpkg mypackages::providerpkg::provider register * }] [para] Or a specific capability may be registered: [example { package require mypackages::providerpkg mypackages::providerpkg::provider register another_capability_name }] [comment {- -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---}] [call class::interface_capprovider.provider [method capabilities]] [para] return a list of capabilities supported by this provider package [list_end] [comment {- end class definitions -}] [list_end] [comment {- end enumeration provider_classes }] [list_end] [comment {- end itemized list punk::cap::class groupings -}] [subsection {Namespace punk::cap}] [para] Main punk::cap API for client programs interested in using capability handler packages and associated (registered) provider packages [list_begin definitions] [call [fun capability_exists] [arg capname]] Return a boolean indicating if the named capability exists (0|1) [call [fun capability_has_handler] [arg capname]] Return a boolean indicating if the named capability has a handler package installed (0|1) [call [fun capability_get_handler] [arg capname]] Return the base namespace of the active handler package for the named capability. [para] The base namespace for a handler will always be the package name, but prefixed with :: [list_end] [comment {- end definitions for namespace punk::cap -}] [subsection {Namespace punk::cap::advanced}] [para] punk::cap::advanced API. Functions here are generally not the preferred way to interact with punk::cap. [para] In some cases they may allow interaction in less safe ways or may allow use of features that are unavailable in the base namespace. [para] Some functions are here because they are only marginally or rarely useful, and they are here to keep the base API simple. [list_begin definitions] [call advanced::[fun promote_provider] [arg pkg]] [para]Move the named provider package to the preferred end of the list (tail). [para]The active handler may or may not utilise this for preferencing. See documentation for the specific handler package to confirm. [para] [para] promote/demote doesn't always make a lot of sense .. should preferably be configurable per capapbility for multicap provider pkgs [para]The idea is to provide a crude way to preference/depreference packages independently of order the packages were loaded e.g a caller or cap-handler can ascribe some meaning to the order of the 'providers' key returned from punk::cap::capabilities [para]The order of providers will be the order the packages were loaded & registered [para]the naming: "promote vs demote" operates on a latest-package-in-list has higher preference assumption (matching last pkg loaded) [para]Each capability handler could and should implement specific preferencing methods within its own API if finer control needed. In some cases the preference/loading order may be inapplicable/irrelevant to a particular capability anyway. [para]As this is just a basic mechanism, which can't support independent per-cap preferencing for multi-cap packages - it only allows putting the pkgs to the head or tail of the lists. [para]Whether particular caps or users of caps do anything with this ordering is dependent on the cap-handler and/or calling code. [call advanced::[fun demote_provider] [arg pkg]] [para]Move the named provider package to the preferred end of the list (tail). [para]The active handler may or may not utilise this for preferencing. See documentation for the specific handler package to confirm. [list_end] [section Internal] [subsection {Namespace punk::cap::capsystem}] [para] Internal functions used to communicate between punk::cap and capability handlers [list_begin definitions] [list_end] [manpage_end]