From: Matthias Kruk Date: Mon, 9 Jan 2023 05:13:26 +0000 (+0900) Subject: toolbox.sh: Allow modules to implement their own interface X-Git-Url: https://git.corax.cc/?a=commitdiff_plain;h=55eeb4218a9bf2cab4d947d05b9314e18273d286;p=toolbox toolbox.sh: Allow modules to implement their own interface The interface/implements mechanism does not allow a module to implement methods of the interface that it declares. This makes it impossible to write modules that extend other modules. This commit changes the interface mechanism so that a module may provide methods of the interface that it declares. This is done by renaming module functions if they clash with names of the interface's method stubs. --- diff --git a/toolbox.sh b/toolbox.sh index 71e5725..c3dd29a 100644 --- a/toolbox.sh +++ b/toolbox.sh @@ -182,6 +182,40 @@ method_not_implemented() { return 127 } +have_method() { + local name="$1" + + if ! declare -f "$name" &> /dev/null; then + return 1 + fi + + return 0 +} + +rename_method() { + local old_name="$1" + local new_name="$2" + + local old_definition + local new_definition + + if ! old_definition=$(declare -f "$old_name"); then + return 1 + fi + + new_definition="$new_name${old_definition#* }" + + if ! unset -f "$old_name"; then + return 1 + fi + + if ! source <(echo "$new_definition"); then + return 1 + fi + + return 0 +} + interface() { local methods=("$@") @@ -211,6 +245,21 @@ interface() { # shellcheck disable=SC2016 # Reason: Don't want expansion in the format string call_stubs+=$(printf '\n%s() {\n\t"${%s["%s"]}" "$@"\n\treturn "$?"\n}' \ "${name}_$method" "$vtable_name" "$method") + interface["$method"]=method_not_implemented + done + + # Rename existing functions if they clash with the call stubs + for method in "${methods[@]}"; do + if ! have_method "${name}_$method"; then + continue + fi + + if ! rename_method "${name}_$method" "___${name}_$method"; then + echo "ERROR: Could not rename function ${name}_$method. Is it readonly?" 1>&2 + return 1 + fi + + interface["$method"]="___${name}_$method" done # shellcheck disable=SC1090 # Reason: Dynamically generated call-stubs can't be checked @@ -219,11 +268,6 @@ interface() { return 1 fi - # Set the entries in the vtable - for method in "${methods[@]}"; do - interface["$method"]=method_not_implemented - done - return 0 }