You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

141 lines
8.4 KiB

[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 <capname> <capnamespace>
[para][term {capability provider}] - a package which registers as providing one or more capablities.
[para]registered using register_package <pkg> <capabilitylist>
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 <capname>
[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]