Context
wedow/harness uses local -n extensively to pass associative arrays and indexed arrays by reference into helper functions. The existing nameref spec tests (13 pass, 1 skip) cover basic patterns, but harness uses more complex patterns that need validation:
- Nameref to associative array — iterate keys with
${!ref[@]}
- Nameref to associative array — assign new keys via
ref["key"]="value"
- Nameref to indexed array — append via
ref+=("value")
- Multiple namerefs in the same function (map + order array)
local arr=(...) syntax (currently skipped in spec tests — parser limitation)
The key harness function pattern:
# From bin/harness — _collect_hooks_from()
_collect_hooks_from() {
local dir="$1"
local -n map_ref="$2" # nameref → associative array
local -n order_ref="$3" # nameref → indexed array
for f in "${dir}"/*; do
[[ -x "${f}" ]] || continue
local base="$(basename "${f}")"
map_ref["${base}"]="${f}" # assign key in caller's assoc array
order_ref+=("${base}") # append to caller's indexed array
done
}
declare -A hook_map
hook_order=()
_collect_hooks_from "/plugins/hooks.d/assemble" hook_map hook_order
Test cases
1. Nameref assign key to caller's associative array
add_entry() {
local -n ref="$1"
ref["hello"]="world"
ref["foo"]="bar"
}
declare -A mymap
add_entry mymap
echo "${mymap[hello]}"
echo "${mymap[foo]}"
# Expected stdout:
# world
# bar
2. Nameref iterate keys of associative array
show_keys() {
local -n ref="$1"
for key in "${!ref[@]}"; do
echo "${key}=${ref[$key]}"
done | sort
}
declare -A colors=([red]=ff0000 [green]=00ff00 [blue]=0000ff)
show_keys colors
# Expected stdout:
# blue=0000ff
# green=00ff00
# red=ff0000
3. Nameref append to caller's indexed array
collect() {
local -n arr_ref="$1"
arr_ref+=("alpha")
arr_ref+=("beta")
arr_ref+=("gamma")
}
items=()
collect items
echo "${#items[@]}"
echo "${items[0]} ${items[1]} ${items[2]}"
# Expected stdout:
# 3
# alpha beta gamma
4. Two namerefs in same function (harness pattern)
collect_from() {
local dir="$1"
local -n map_ref="$2"
local -n order_ref="$3"
map_ref["key-a"]="${dir}/file-a"
map_ref["key-b"]="${dir}/file-b"
order_ref+=("key-a")
order_ref+=("key-b")
}
declare -A my_map
my_order=()
collect_from "/src" my_map my_order
echo "${my_map[key-a]}"
echo "${my_map[key-b]}"
echo "${my_order[0]} ${my_order[1]}"
# Expected stdout:
# /src/file-a
# /src/file-b
# key-a key-b
5. Nameref with associative array length
count_entries() {
local -n ref="$1"
echo "${#ref[@]}"
}
declare -A data=([x]=1 [y]=2 [z]=3)
count_entries data
# Expected stdout: 3
6. Nameref overwrite existing key in associative array
update() {
local -n ref="$1"
ref["name"]="updated"
}
declare -A record=([name]=original [age]=30)
update record
echo "${record[name]}"
echo "${record[age]}"
# Expected stdout:
# updated
# 30
7. Nested function calls with nameref passthrough
inner() {
local -n ref="$1"
ref["from_inner"]="yes"
}
outer() {
local -n ref="$1"
ref["from_outer"]="yes"
inner "$1"
}
declare -A result
outer result
echo "${result[from_outer]}"
echo "${result[from_inner]}"
# Expected stdout:
# yes
# yes
8. local arr=(...) syntax (currently skipped)
caller() {
local items=(one two three)
show items
}
show() {
local -n ref="$1"
echo "${ref[1]}"
}
caller
# Expected stdout: two
This is currently blocked by a parser limitation (local arr=(...) syntax). See spec test nameref_local_dynamic_scope which is skipped for this reason.
9. Nameref to associative array — check key existence
has_key() {
local -n ref="$1"
local key="$2"
if [[ -v "ref[$key]" ]]; then
echo "found"
else
echo "missing"
fi
}
declare -A config=([debug]=true)
has_key config debug
has_key config verbose
# Expected stdout:
# found
# missing
10. Nameref loop — discover and collect (full harness pattern)
mkdir -p /plugins/tools
echo "tool-a" > /plugins/tools/grep
chmod +x /plugins/tools/grep
echo "tool-b" > /plugins/tools/sed
chmod +x /plugins/tools/sed
discover_tools() {
local dir="$1"
local -n tmap_ref="$2"
for f in "${dir}"/*; do
[[ -f "${f}" ]] || continue
local name
name="$(basename "${f}")"
tmap_ref["${name}"]="${f}"
done
}
declare -A tool_map
discover_tools "/plugins/tools" tool_map
for name in $(echo "${!tool_map[@]}" | tr ' ' '\n' | sort); do
echo "${name}=${tool_map[$name]}"
done
# Expected stdout:
# grep=/plugins/tools/grep
# sed=/plugins/tools/sed
Context
wedow/harness uses
local -nextensively to pass associative arrays and indexed arrays by reference into helper functions. The existing nameref spec tests (13 pass, 1 skip) cover basic patterns, but harness uses more complex patterns that need validation:${!ref[@]}ref["key"]="value"ref+=("value")local arr=(...)syntax (currently skipped in spec tests — parser limitation)The key harness function pattern:
Test cases
1. Nameref assign key to caller's associative array
2. Nameref iterate keys of associative array
3. Nameref append to caller's indexed array
4. Two namerefs in same function (harness pattern)
5. Nameref with associative array length
6. Nameref overwrite existing key in associative array
7. Nested function calls with nameref passthrough
8.
local arr=(...)syntax (currently skipped)This is currently blocked by a parser limitation (
local arr=(...)syntax). See spec testnameref_local_dynamic_scopewhich is skipped for this reason.9. Nameref to associative array — check key existence
10. Nameref loop — discover and collect (full harness pattern)