Skip to main content

The module::function pattern

bash::framehead uses a strict module::function naming convention for all 785 functions. This pattern provides namespace isolation, predictable discovery, and self-documenting code.

Why double colons?

The :: delimiter is valid in Bash function names and serves as a clear visual separator:
string::upper "hello"        # Immediately clear: string module, upper function
math::factorial 5            # Math module, factorial function  
fs::path::basename "/foo"    # Filesystem module, path subgroup, basename function
Unlike many languages, Bash doesn’t have true namespaces. The :: convention is purely visual but highly effective for organizing 785 functions.

Convention structure

All function names follow this hierarchy:
module::function
module::subgroup::function
module::function::variant
module::subgroup::function::variant

Examples from the source

Simple module::function:
src/string.sh:11-13
string::length() {
  echo "${#1}"
}
Module with subgroup:
fs::path::basename()    # Filesystem → path operations → basename
fs::path::dirname()     # Filesystem → path operations → dirname
fs::path::extension()   # Filesystem → path operations → extension
Function variants:
src/string.sh:93-100
# Modern Bash 4+ version
string::upper() {
  echo "${1^^}"
}

# Bash 3 compatible version
string::upper::legacy() {
  echo "$1" | tr '[:lower:]' '[:upper:]'
}

Subgroup organization

Complex modules use subgroups to organize related functions:

Filesystem paths

fs::path::basename      # Extract filename from path
fs::path::dirname       # Extract directory from path
fs::path::extension     # Get file extension
fs::path::stem          # Get filename without extension
fs::path::join          # Join path components
fs::path::absolute      # Convert to absolute path
fs::path::relative      # Get relative path between two paths

Filesystem permissions

fs::permissions                # Get numeric permissions (e.g., 755)
fs::permissions::symbolic      # Get symbolic permissions (e.g., rwxr-xr-x)

Array sorting

array::sort                    # Sort alphabetically ascending
array::sort::reverse           # Sort alphabetically descending
array::sort::numeric           # Sort numerically ascending  
array::sort::numeric_reverse   # Sort numerically descending

Color depth levels

colour::fg::red                # 4-bit ANSI foreground red
colour::bg::blue               # 4-bit ANSI background blue
colour::fg::256                # 8-bit foreground color by index
colour::bg::rgb                # 24-bit background color by RGB
Subgroups are discoverable via shell completion. Type fs::path:: and press Tab to see all path-related functions.

Variant conventions

Variants handle alternative implementations or optional dependencies:

Legacy compatibility

Bash 3 compatible versions for older systems:
src/string.sh:93-100
string::upper()           # Bash 4+ using ${var^^}
string::upper::legacy()   # Bash 3+ using tr command

string::lower()           # Bash 4+ using ${var,,}
string::lower::legacy()   # Bash 3+ using tr command

Pure vs. tool-dependent

string::base64_encode()         # Requires base64 command
string::base64_encode::pure()   # Pure Bash implementation (slower)

string::base64_decode()         # Requires base64 command  
string::base64_decode::pure()   # Pure Bash implementation (slower)

Output format variants

fs::size()              # Bytes as integer
fs::size::human()       # Human-readable (e.g., "2.3M")

fs::modified()          # Unix timestamp
fs::modified::human()   # Human-readable date string

Discovery and completion

The naming convention enables powerful shell completion:
# List all string functions
declare -F | grep '^string::'

# List all path functions
declare -F | grep '^fs::path::'

# Count functions per module
declare -F | awk -F'::' '{print $1}' | sort | uniq -c
Example output:
main.sh:113-118
=== Function count by module ===
    115 string
     79 fs
     74 timedate
     74 terminal
     65 colour
    ...
    785 total functions loaded

Naming consistency

All functions follow consistent verb patterns:

Boolean predicates

Functions that return exit codes use is_, has_, or question form:
runtime::is_terminal()        # Exit 0 if true, 1 if false
runtime::is_interactive()
runtime::has_command bc
math::has_bc
array::is_empty
string::is_integer
string::is_empty
fs::is_file
fs::is_dir
fs::is_symlink
Usage:
if runtime::is_terminal; then
    echo "Running in a terminal"
fi

if ! string::is_empty "$var"; then
    process::value "$var"
fi

Action verbs

Functions that perform operations use clear verbs:
string::upper              # Convert → upper
string::trim               # Remove whitespace → trim
array::reverse             # Reverse order → reverse  
array::sort                # Sort elements → sort
fs::read                   # Read file → read
fs::write                  # Write file → write
hash::verify               # Verify hash → verify
process::kill              # Kill process → kill

Getters

Functions that retrieve information use descriptive nouns:
string::length             # Get length
array::first               # Get first element
array::last                # Get last element  
fs::size                   # Get file size
fs::owner                  # Get file owner
runtime::os                # Get operating system
runtime::arch              # Get architecture

Testing conventions

The test suite in main.sh follows the same patterns:
main.sh:241-252
_test "string::upper"              "HELLO"          "$(string::upper hello)"
_test "string::lower"              "hello"          "$(string::lower HELLO)"
_test "string::length"             "5"              "$(string::length hello)"
_test "string::contains (true)"    "0"              "$( string::contains hello ell; echo $? )"
_test "string::contains (false)"   "1"              "$( string::contains hello xyz; echo $? )"
_test "string::reverse"            "olleh"          "$(string::reverse hello)"
_test "string::trim"               "hello"          "$(string::trim "  hello  ")"
_test "string::repeat"             "aaa"            "$(string::repeat a 3)"
_test "string::is_integer (true)"  "0"              "$( string::is_integer 42; echo $? )"
_test "string::is_integer (false)" "1"              "$( string::is_integer abc; echo $? )"
Test names mirror function names with result indicators in parentheses.

Documentation alignment

Function documentation follows the same hierarchy:
# String length
# Usage: string::length str
string::length() {
  echo "${#1}"
}

# Check if string contains substring  
# Usage: string::contains haystack needle
string::contains() {
  [[ "$1" == *"$2"* ]]
}
The wiki generator parses these comments to create structured API documentation automatically.

Reserved patterns

Certain patterns are reserved for framework internals:

Double underscores

Private helper functions use __ prefix:
_test()               # Test suite helper
_check_stderr()       # Internal test utility  
_mark_tested()        # Test tracking helper
User scripts should never define functions starting with _ to avoid conflicts with internal helpers.

Module names

The following module names are reserved and define the public API:
  • string
  • array
  • math
  • fs
  • runtime
  • hash
  • random
  • process
  • net
  • git
  • timedate
  • terminal
  • colour
  • hardware
  • device
  • pm

Adding custom functions

When extending the framework, follow the established patterns:
# Good: Clear module, subgroup, and function
mymodule::api::fetch() {
    curl -s "$1"
}

mymodule::api::post() {
    curl -s -X POST "$1" -d "$2"
}

# Bad: No module prefix (pollutes global namespace)
fetch_api() {
    curl -s "$1"
}

# Bad: Inconsistent delimiter
mymodule_api_fetch() {
    curl -s "$1"  
}
See the development guide for detailed instructions on adding custom modules.

Function signature patterns

Consistent parameter ordering improves usability:

Target-first pattern

Operations take the target/subject as the first parameter:
string::upper "hello"                    # Subject: string
string::contains "haystack" "needle"     # Subject: haystack
array::contains element "${array[@]}"    # Subject: array elements
fs::read "/path/to/file"                 # Subject: file
hash::md5 "content"                      # Subject: content

Options-last pattern

Optional parameters come last with sensible defaults:
math::bc "22/7" 2                        # precision (default: 10)
string::truncate "hello" 4               # length (ellipsis added)
string::pad_left "hi" 5                  # width (default char: space)
array::chunk "${items[@]}" 3             # chunk size

Discovering functions

Use shell introspection to explore the API:
# All functions
declare -F

# Functions from one module
declare -F | grep '^declare -f string::'

# Functions in a subgroup  
declare -F | grep '^declare -f fs::path::'

# Count by module
declare -F | awk '{print $3}' | awk -F'::' '{print $1}' | sort | uniq -c

Next steps

Architecture

Understand the framework structure

Module system

Explore the 16 available modules

Compilation

Learn how to build custom distributions

API Reference

Browse all 785 functions

Build docs developers (and LLMs) love