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
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]
|
|
|