From ce99e872780d84b8424d359cc0bc3d9e2f131110 Mon Sep 17 00:00:00 2001 From: Matthias Kruk Date: Sat, 17 Dec 2022 13:50:31 +0900 Subject: [PATCH] include/opt: Add array options Options with multiple values stored in an array can be implemented using callbacks, but it is somewhat hacky and would be nicer if the opt module had explicit support for options with multiple values. This commit adds the "a" attribute, allowing options to be declared as arrays. The default value of an array option must be the name of the array that values shall be appended to. --- include/opt.sh | 25 ++++++++++++++++++++- test/opt_spec.sh | 57 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 79 insertions(+), 3 deletions(-) diff --git a/include/opt.sh b/include/opt.sh index 9129933..bb9f222 100644 --- a/include/opt.sh +++ b/include/opt.sh @@ -23,10 +23,12 @@ __init() { declare -xgir __opt_flag_required=1 declare -xgir __opt_flag_has_value=2 + declare -xgir __opt_flag_is_array=6 # is_array implies has_value declare -xgAr __opt_flags_map=( ["r"]="$__opt_flag_required" ["v"]="$__opt_flag_has_value" + ["a"]="$__opt_flag_is_array" ) declare -Axg __opt_short @@ -109,6 +111,12 @@ opt_add_arg() { return 1 fi + if (( ( parsed_flags & __opt_flag_is_array ) == __opt_flag_is_array )) && + ! declare -p "$default" &>/dev/null; then + log_error "Default value of array options must be the name of an array" + return 1 + fi + __opt_short["$long"]="$short" __opt_flags["$long"]="$parsed_flags" __opt_desc["$long"]="$desc" @@ -148,7 +156,17 @@ opt_print_help() { "$short" "$long" "${__opt_desc[$long]}" if (( ${__opt_flags["$long"]} & __opt_flag_has_value )) && array_contains "$long" "${!__opt_default[@]}"; then - printf '\t\t\t(Default: %s)\n' "${__opt_default[$long]}" + if (( ${__opt_flags["$long"]} & __opt_flag_is_array )); then + local -n __opt_print_help_array="${__opt_default[$long]}" + + if (( ${#__opt_print_help_array[@]} > 0 )); then + printf '\t\t\t(Default:\n' + printf '\t\t\t %s\n' "${__opt_print_help_array[@]}" + printf '\t\t\t)\n' + fi + else + printf '\t\t\t(Default: %s)\n' "${__opt_default[$long]}" + fi fi done | column -s $'\t' -t @@ -216,6 +234,11 @@ opt_parse() { log_error "Value \"$value\" doesn't match \"$regex\"" return 1 fi + + if (( ( flags & __opt_flag_is_array ) == __opt_flag_is_array )); then + local -n __opt_parse_array="${__opt_default[$long]}" + __opt_parse_array+=("$value") + fi else value=$(( __opt_value[$long] + 1 )) fi diff --git a/test/opt_spec.sh b/test/opt_spec.sh index c4a3ad0..50d8d66 100644 --- a/test/opt_spec.sh +++ b/test/opt_spec.sh @@ -28,20 +28,26 @@ Describe "opt_add_arg() - Attributes" Parameters "r" 0 "accepts" "v" 0 "accepts" + "a" 0 "accepts" "array" "rv" 0 "accepts" + "rva" 0 "accepts" "array" "vr" 0 "accepts" "rvrv" 0 "accepts" "x" 1 "does not accept" + "a" 1 "does not accept" End _test_opt_add_arg_attr() ( local attr="$1" + local default="$2" - opt_add_arg "o" "opt" "$attr" 2>/dev/null + declare -a array + + opt_add_arg "o" "opt" "$attr" "$default" 2>/dev/null ) It "$3 the attribute '$1'" - When call _test_opt_add_arg_attr "$1" + When call _test_opt_add_arg_attr "$1" "$4" The status should equal "$2" End End @@ -143,6 +149,53 @@ Describe "opt_parse()" When call _test_opt_parse_callback_retval The status should equal 123 End + + It "adds elements to an array" + _test_opt_parse_array_append() ( + declare -a array + declare -a expected + + expected=( + 123 + ) + + opt_add_arg "o" "opt" "a" "array" + opt_parse "-o" "123" + + array_identical array expected + return "$?" + ) + + When call _test_opt_parse_array_append + The status should equal 0 + End + + It "does not overwrite existing elements" + _test_opt_parse_array_no_overwrite() ( + declare -a array + declare -a expected + + array=( + 123 + 234 + ) + expected=( + 123 + 234 + 345 + 456 + ) + + opt_add_arg "o" "opt" "a" "array" + opt_parse "-o" "345" "--opt" "456" + + array_identical array expected + return "$?" + ) + + When call _test_opt_parse_array_no_overwrite + The status should equal 0 + End End Describe "opt_get()" -- 2.47.3