Skip to content

Commit 73d36b3

Browse files
committed
core: Add @go.select_option function and demo
While starting to write my first "real" application/plugin, I realized that this function would eliminate a lot of repetitive boilerplate between scripts for the common single-option selection case.
1 parent a9079ee commit 73d36b3

File tree

4 files changed

+219
-0
lines changed

4 files changed

+219
-0
lines changed

go-core.bash

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,43 @@ declare _GO_INJECT_MODULE_PATH="$_GO_INJECT_MODULE_PATH"
215215
return "$result"
216216
}
217217

218+
# Prompts the user to select one item from a list of options.
219+
#
220+
# This is a thin wrapper around the `select` builtin command for
221+
# straightforward, single-option user prompts. If you need to do anything more
222+
# complex, use the `select` builtin command directly.
223+
#
224+
# This will prompt the user for a single input, returned in the caller-declared
225+
# variable identified by `result_var`. If the user enters an invalid option,
226+
# this will notify the user and prompt again. If the user terminates input (via
227+
# EOF, i.e. Ctrl-D), `result_var` will remain unchanged and the function will
228+
# return nonzero.
229+
#
230+
# Globals:
231+
# PS3 environment variable defining the selection prompt
232+
#
233+
# Arguments:
234+
# result_var: Name of the caller-declared variable used to store the option
235+
# ...: Strings representing options available for the user to select
236+
#
237+
# Returns:
238+
# zero if `result_var` contains the user's selection, nonzero otherwise
239+
@go.select_option() {
240+
local __go_selected_option
241+
select __go_selected_option in "${@:2}"; do
242+
case "$__go_selected_option" in
243+
'')
244+
@go.printf '"%s" is not a valid option.\n' "$REPLY" >&2
245+
;;
246+
*)
247+
printf -v "$1" -- '%s' "$__go_selected_option"
248+
break
249+
;;
250+
esac
251+
done
252+
[[ -n "$__go_selected_option" ]]
253+
}
254+
218255
# Searches through plugin directories using a helper function
219256
#
220257
# The search will begin in `_GO_SCRIPTS_DIR/plugins`. As long as `search_func`

libexec/demo-core.d/select-option

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#! /usr/bin/env bash
2+
#
3+
# Demonstration of the `@go.select_option` function
4+
#
5+
# Usage:
6+
# [PS3=<VALUE>] {{go}} {{cmd}} [option...]
7+
#
8+
# Where:
9+
# PS3 environment variable defining the selection prompt
10+
# option... (Optional) list of user-selectable options, overriding defaults
11+
#
12+
# Use this program to get a feel for the core `@go.select_option` function, and
13+
# for an example of how to use it in your own scripts.
14+
15+
select_option_demo() {
16+
local options=("$@")
17+
local selected
18+
local finish
19+
20+
if [[ "${#options[@]}" -eq '0' ]]; then
21+
options=('Hello, World!' 'Goodbye, World!')
22+
fi
23+
24+
while [[ -z "$finish" ]]; do
25+
@go.printf 'Please select one of the following options:\n'
26+
27+
if @go.select_option 'selected' "${options[@]}"; then
28+
@go.printf 'You selected: "%s"\n\n' "$selected"
29+
else
30+
@go.printf 'You declined to select an option.\n\n'
31+
fi
32+
33+
@go.printf 'Would you like to select another option?\n'
34+
35+
if @go.select_option 'selected' 'Yes' 'No'; then
36+
if [[ "$selected" == 'No' ]]; then
37+
@go.printf 'Exiting...\n'
38+
finish='true'
39+
else
40+
printf '\n'
41+
fi
42+
else
43+
@go.printf 'You declined to select an option. Exiting...\n'
44+
finish='true'
45+
fi
46+
done
47+
}
48+
49+
select_option_demo "$@"

tests/core/select-option.bats

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#! /usr/bin/env bats
2+
3+
load ../environment
4+
5+
setup() {
6+
test_filter
7+
@go.create_test_go_script 'declare selection' \
8+
'if @go.select_option "selection" "$@"; then' \
9+
' printf "\nSelection: \"%s\"\n" "$selection"' \
10+
'else' \
11+
' exit 1' \
12+
'fi'
13+
export PS3='Selection> '
14+
}
15+
16+
teardown() {
17+
@go.remove_test_go_rootdir
18+
}
19+
20+
@test "$SUITE: no options exits instantly" {
21+
run "$TEST_GO_SCRIPT"
22+
assert_failure ''
23+
}
24+
25+
@test "$SUITE: single option selection" {
26+
run "$TEST_GO_SCRIPT" 'foo' <<<"1"
27+
assert_success '1) foo' \
28+
"$PS3" \
29+
'Selection: "foo"'
30+
}
31+
32+
@test "$SUITE: multiple option selection" {
33+
run "$TEST_GO_SCRIPT" 'foo' 'bar' 'baz' <<<"2"
34+
assert_success '1) foo' \
35+
'2) bar' \
36+
'3) baz' \
37+
"$PS3" \
38+
'Selection: "bar"'
39+
}
40+
41+
@test "$SUITE: select valid option after invalid option" {
42+
run "$TEST_GO_SCRIPT" 'foo' 'bar' 'baz' <<<$'0\n3'
43+
assert_success '1) foo' \
44+
'2) bar' \
45+
'3) baz' \
46+
"$PS3\"0\" is not a valid option." \
47+
"$PS3" \
48+
'Selection: "baz"'
49+
}
50+
51+
@test "$SUITE: no selection with invalid option followed by end-of-file" {
52+
printf '4\n' >"$TEST_GO_ROOTDIR/input.txt"
53+
run "$TEST_GO_SCRIPT" 'foo' 'bar' 'baz' <"$TEST_GO_ROOTDIR/input.txt"
54+
assert_failure '1) foo' \
55+
'2) bar' \
56+
'3) baz' \
57+
"$PS3\"4\" is not a valid option." \
58+
"$PS3"
59+
}

tests/demo-core/select-option.bats

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#! /usr/bin/env bats
2+
3+
load ../environment
4+
5+
setup() {
6+
test_filter
7+
export PS3='Selection> '
8+
}
9+
10+
teardown() {
11+
@go.remove_test_go_rootdir
12+
}
13+
14+
@test "$SUITE: use default selection options" {
15+
run "$_GO_SCRIPT" demo-core select-option <<<$'1\n1\n2\n2\n'
16+
assert_success
17+
split_bats_output_into_lines
18+
assert_lines_equal 'Please select one of the following options:' \
19+
'1) Hello, World!' \
20+
'2) Goodbye, World!' \
21+
"${PS3}You selected: \"Hello, World!\"" \
22+
'' \
23+
'Would you like to select another option?' \
24+
'1) Yes' \
25+
'2) No' \
26+
"${PS3}" \
27+
'Please select one of the following options:' \
28+
'1) Hello, World!' \
29+
'2) Goodbye, World!' \
30+
"${PS3}You selected: \"Goodbye, World!\"" \
31+
'' \
32+
'Would you like to select another option?' \
33+
'1) Yes' \
34+
'2) No' \
35+
"${PS3}Exiting..."
36+
}
37+
38+
@test "$SUITE: use user-provided selection options" {
39+
run "$_GO_SCRIPT" demo-core select-option foo bar baz <<<$'2\n2\n'
40+
assert_success
41+
split_bats_output_into_lines
42+
assert_lines_equal 'Please select one of the following options:' \
43+
'1) foo' \
44+
'2) bar' \
45+
'3) baz' \
46+
"${PS3}You selected: \"bar\"" \
47+
'' \
48+
'Would you like to select another option?' \
49+
'1) Yes' \
50+
'2) No' \
51+
"${PS3}Exiting..."
52+
}
53+
54+
@test "$SUITE: exit both prompts on empty input" {
55+
mkdir "$TEST_GO_ROOTDIR"
56+
printf '' >"$TEST_GO_ROOTDIR/input.txt"
57+
run "$_GO_SCRIPT" demo-core select-option foo bar baz \
58+
<"$TEST_GO_ROOTDIR/input.txt"
59+
60+
assert_success
61+
split_bats_output_into_lines
62+
assert_lines_equal 'Please select one of the following options:' \
63+
'1) foo' \
64+
'2) bar' \
65+
'3) baz' \
66+
"${PS3}" \
67+
'You declined to select an option.' \
68+
'' \
69+
'Would you like to select another option?' \
70+
'1) Yes' \
71+
'2) No' \
72+
"${PS3}" \
73+
'You declined to select an option. Exiting...'
74+
}

0 commit comments

Comments
 (0)