Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion lib/bash/str/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ str_join joined "|" parts
- Trim helpers remove Bash character-class whitespace from the requested side.
- String transformation helpers mutate the named variable in place and do not
print transformed values for command substitution.
- Predicate helpers return shell status and do not print output.
- Predicate helpers require exactly two arguments, return shell status, and do
not print output.
- `str_split` preserves empty fields between repeated delimiters.
- `str_join` preserves empty array elements, including trailing empty elements.
- Named string, result, and array arguments must be valid Bash variable names.
Expand Down
28 changes: 17 additions & 11 deletions lib/bash/str/lib_str.sh
Original file line number Diff line number Diff line change
Expand Up @@ -56,39 +56,45 @@ str_trim() {

str_contains() {
local value="${1-}" needle="${2-}"

assert_arg_count "$#" 2
[[ "$value" == *"$needle"* ]]
}

str_starts_with() {
local value="${1-}" prefix="${2-}"

assert_arg_count "$#" 2
[[ "$value" == "$prefix"* ]]
}

str_ends_with() {
local value="${1-}" suffix="${2-}"

assert_arg_count "$#" 2
[[ "$value" == *"$suffix" ]]
}

str_split() {
local result_name="${1-}" value="${2-}" separator="${3-}"
local __str_split_result_name="${1-}" __str_split_value="${2-}" __str_split_separator="${3-}"

assert_arg_count "$#" 3
assert_variable_name "$result_name"
assert_variable_name "$__str_split_result_name"

local -a fields=()
local remainder="$value"
local -a __str_split_fields=()
local __str_split_remainder="$__str_split_value"

if [[ -z "$separator" ]]; then
fields=("$value")
if [[ -z "$__str_split_separator" ]]; then
__str_split_fields=("$__str_split_value")
else
while [[ "$remainder" == *"$separator"* ]]; do
fields+=("${remainder%%"$separator"*}")
remainder="${remainder#*"$separator"}"
while [[ "$__str_split_remainder" == *"$__str_split_separator"* ]]; do
__str_split_fields+=("${__str_split_remainder%%"$__str_split_separator"*}")
__str_split_remainder="${__str_split_remainder#*"$__str_split_separator"}"
done
fields+=("$remainder")
__str_split_fields+=("$__str_split_remainder")
fi

eval "$result_name=(\"\${fields[@]}\")"
eval "$__str_split_result_name=(\"\${__str_split_fields[@]}\")"
}

str_join() {
Expand Down
34 changes: 34 additions & 0 deletions lib/bash/str/tests/lib_str.bats
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,29 @@ EOF
fi
}

@test "string predicate helpers reject incorrect argument counts" {
local script="$TEST_TMPDIR/string-predicate-arity.sh"

create_script "$script" <<EOF
#!/usr/bin/env bash
source "$BASE_BASH_DIR/std/lib_std.sh"
source "$BASE_BASH_DIR/str/lib_str.sh"
"\$@"
EOF

bats_run bash "$script" str_contains "needle-only"
[ "$status" -eq 1 ]
[[ "$output" == *"Argument count mismatch: expected 2 but got 1 arguments"* ]]

bats_run bash "$script" str_starts_with "value" "prefix" "extra"
[ "$status" -eq 1 ]
[[ "$output" == *"Argument count mismatch: expected 2 but got 3 arguments"* ]]

bats_run bash "$script" str_ends_with
[ "$status" -eq 1 ]
[[ "$output" == *"Argument count mismatch: expected 2 but got 0 arguments"* ]]
}

@test "str_split stores delimited fields in a named array" {
local -a parts=()

Expand All @@ -114,6 +137,17 @@ EOF
[ "${parts[3]}" = "gamma" ]
}

@test "str_split can store results in an array named fields" {
local -a fields=()

str_split fields "alpha:beta:gamma" ":"

[ "${#fields[@]}" -eq 3 ]
[ "${fields[0]}" = "alpha" ]
[ "${fields[1]}" = "beta" ]
[ "${fields[2]}" = "gamma" ]
}

@test "str_split rejects invalid result variable names" {
local script="$TEST_TMPDIR/str-split-invalid.sh"

Expand Down
Loading