Skip to content

Commit

Permalink
Dispatch function is added with test cases.
Browse files Browse the repository at this point in the history
  • Loading branch information
vlisivka committed Jul 21, 2021
1 parent 3e5df55 commit eaf8e06
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 3 deletions.
7 changes: 6 additions & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,13 @@
* [x] Update path to modules and configuration in import.sh during installation.
* [x] Add support for configuration file in other places than /etc.
* [x] Add an Install section to README.
* [x] Add dispatch function.
* [ ] Add path module.
* [ ] Add lock module.
* [ ] Add is module.
* [ ] Publish an article in Fedora Magazine.
* [ ] Report bug in bash 5.1.0.
* [ ] Ask bash developers for strict mode support, like in zsh, because it's critical for this project.
* [ ] Add path module.
* [ ] Use realpath instead of readlink -f, when possible.
* [ ] Write a package manager for bash: bapt, for strict bash code only.
* [ ] SPDX-License-Identifier: LGPL-2.1-or-later
4 changes: 2 additions & 2 deletions bash-modules/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ main() {
echo "Bin directory: \"$BIN_DIR\"."

mkdir -p "$MODULES_DIR" || { echo "ERROR: Cannot create directory \"$MODULES_DIR\"." >&2 ; return 1 ;}
install -vt "$MODULES_DIR" src/bash-modules/*.sh || { echo "ERROR: Cannot install modules to directory \"$MODULES_DIR\"." >&2 ; return 1 ;}
install -t "$MODULES_DIR" src/bash-modules/*.sh || { echo "ERROR: Cannot install modules to directory \"$MODULES_DIR\"." >&2 ; return 1 ;}

mkdir -p "$BIN_DIR" || { echo "ERROR: Cannot create directory \"$BIN_DIR\"." >&2 ; return 1 ;}
install -vD src/import.sh "$BIN_DIR/import.sh" || { echo "ERROR: Cannot install import.sh script to \"$MODULES_DIR\"." >&2 ; return 1 ;}
install -D src/import.sh "$BIN_DIR/import.sh" || { echo "ERROR: Cannot install import.sh script to \"$MODULES_DIR\"." >&2 ; return 1 ;}

# Update hardcoded path to directory with modules
sed -i "s@/usr/share/bash-modules@$MODULES_DIR@g" "$BIN_DIR/import.sh" \
Expand Down
30 changes: 30 additions & 0 deletions bash-modules/src/bash-modules/meta.sh
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,33 @@ function $FUNCTION_NAME() {
meta::functions_with_prefix() {
compgen -A function "$1"
}

#>>
#>> * meta::is_function FUNC_NAME Checks is given name corresponds to a function.
meta::is_function() {
declare -F "$1" >/dev/null
}

#>>
#>> * meta::dispatch PREFIX COMMAND [ARGUMENTS...] - execute function `PREFIX__COMMAND [ARGUMENTS]`
#>
#> For example, it can be used to execute functions (commands) by name, e.g.
#> `main() { meta::dispatch command__ "$@" ; }`, when called as `man hw world` will execute
#> `command_hw "$world"`. When command handler function is not found, dispatcher will try
#> to call `PREFIX__DEFAULT` function instead, or return error code, if defaulf handler is not found.
meta::dispatch() {
local prefix="${1:?Prefix is required.}"
local command="${2:?Command is required.}"
shift 2

local fn="${prefix}${command}"

# Is handler function exists?
meta::is_function "$fn" || {
# Is default handler function exists?
meta::is_function "${prefix}__DEFAULT" || { echo "ERROR: Function \"$fn\" is not found." >&2; return 1; }
fn="${prefix}__DEFAULT"
}

"$fn" "${@:+$@}" || return $?
}
52 changes: 52 additions & 0 deletions bash-modules/test/test_meta.sh
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,56 @@ pr_3"
unit::assert_equal "$output" "$expected_output" "Unexpected output from meta::functions_with_prefix."
}

test_is_function() {
unit::assert "is_function FUNCTION must return true" meta::is_function test_is_function
unit::assert "is_function FUNCTION must return true" meta::is_function meta::is_function

local a_var="foo"
unit::assert "is_function VAR must return false" ! meta::is_function a_var

unit::assert "is_function SHELL_BUILTIN must return false" ! meta::is_function cd
unit::assert "is_function COMMAND must return false" ! meta::is_function /usr/bin/ls
}

test_dispatch() {

local fresult=""

f1() {
fresult="f1 $*"
}
f2() {
fresult="f2 $*"
}

meta::dispatch f 1 foo bar || unit::fail "Cannot dispatch to function."
unit::assert_equal "$fresult" "f1 foo bar" "Unexpected result of call to f1 via dispatch."

meta::dispatch f 2 bar baz || unit::fail "Cannot dispatch to function."
unit::assert_equal "$fresult" "f2 bar baz" "Unexpected result of call to f2 via dispatch."

meta::dispatch f 3 bar baz 2>/dev/null && unit::fail "Dispatch function must not call an non-existing function or a command." || :
meta::dispatch l s bar baz 2>/dev/null && unit::fail "Dispatch function must not call an non-existing function or a command." || :
meta::dispatch c d bar baz 2>/dev/null && unit::fail "Dispatch function must not call an non-existing function or a command." || :
}


test_dispatch_with_default_handler() {

local fresult=""

f1() {
fresult="f1 $*"
}
f__DEFAULT() {
fresult="fD $*"
}

meta::dispatch f 1 foo bar || unit::fail "Cannot dispatch to function."
unit::assert_equal "$fresult" "f1 foo bar" "Unexpected result of call to f1 via dispatch."

meta::dispatch f 2 bar baz || unit::fail "Cannot dispatch to function."
unit::assert_equal "$fresult" "fD bar baz" "Unexpected result of call to f__DEFAULT via dispatch."
}

unit::run_test_cases "$@"

0 comments on commit eaf8e06

Please sign in to comment.