Last active
December 23, 2015 11:49
-
-
Save AtnNn/6631167 to your computer and use it in GitHub Desktop.
Mostly posix shell scripting tricks: assoc list, logging, classes, methods, inheritance, ...
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
set -e | |
set -u | |
main () { | |
init | |
# ... | |
} | |
# contains <haystack> <needle> | |
# Test if the space-separated list haystack contains needle | |
contains () { | |
local d=" $1 " | |
[ "${d% $2 *}" != "$d" ] | |
} | |
# any "<list>" <command> | |
# Test if the command is true for any element of the space seperated list | |
any () { | |
local list=$1 | |
shift | |
for x in $list; do | |
if "$@" $x; then | |
return 0 | |
fi | |
done | |
return 1 | |
} | |
# lookup <dict> <key> [var] | |
# dict is an assoc-list composed of two seperators followed by a list of pairs | |
# eg: ':|foo:bar|test:123|baz:quux' or '= a=b c=d' | |
lookup () { | |
local _val=${1#*${1:1:1}$2${1:0:1}} | |
if [[ "$_val" = "$1" ]]; then | |
unset ${3:-$2} | |
return 1 | |
fi | |
eval "${3:-$2}=$(quote "${_val%%${1:1:1}*}")" | |
} | |
uc () { echo "$*" | tr '[:lower:]' '[:upper:]' ; } | |
lc () { echo "$*" | tr '[:upper:]' '[:lower:]' ; } | |
subst () { echo "${1%%$2*}$3${1#*$2}" ; } | |
# Make the path absolute and prettier (with no /..) | |
niceabspath () { | |
if [[ -d "$1" ]]; then | |
(cd "$1" && pwd) && return | |
fi | |
local dir=$(dirname "$1") | |
if [[ -d "$dir" ]] && dir=$(cd "$dir" && pwd); then | |
echo "$dir/$(basename "$1")" | sed 's|^//|/|' | |
return | |
fi | |
if [[ "${1:0:1}" = / ]]; then | |
echo "$1" | |
else | |
echo "$(pwd)/$1" | |
fi | |
} | |
init () { | |
debug=false | |
log_file= | |
this= | |
stack= | |
} | |
log () { | |
echo "$*" >&3 | |
test -n "$log_file" && echo "$*" >> "$log_file" | |
} | |
virtual () { | |
method "$@" || { | |
error "the $1 method is missing in $this" | |
} | |
} | |
can () { $2 can "$1" ; } | |
cannot () { not $2 can "$1" ; } | |
not () { ! "$@" ; } | |
each () { | |
$class each "$1" | |
local list="$1" | |
shift | |
method "" "$@" || { | |
echo "$list" | |
return | |
} | |
{ | |
for object in $list; do | |
$object "$@" | |
done | |
return | |
} | |
} | |
method () { | |
local name="$1" | |
case "${2:-}" in | |
list_methods) echo "$name" ;; | |
$name) push_stack "$name"; return 1 ;; | |
*) return ;; | |
esac | |
} | |
push_stack () { | |
stack="$stack $1" | |
stack_trace=$stack | |
} | |
nomethod () { | |
error "No such method ${1:-''} for $this" | |
} | |
error () { | |
last_error="$*" | |
last_error_stack=$stack | |
return 1 | |
} | |
class='eval local this; local stack="$stack"; debug_args="$*"; _class' | |
_class () { | |
$debug && echo "TRACE: $1 $debug_args" | |
if [ "${this##inherit *}" = "" ] && [ -n "$this" ]; then | |
set -- $this | |
this=$2 | |
else | |
this=$* | |
push_stack "| $this" | |
fi | |
} | |
inherit () { | |
this="inherit $this" | |
"$@" | |
} | |
either () { | |
local list="$1" | |
shift | |
method "" "$@" || { | |
echo "$list" | |
return | |
} | |
{ | |
for object in $list; do | |
$object "$@" && return || true | |
done | |
return 1 | |
} | |
} | |
tmpfile () { | |
local _file=`mktemp` | |
cat >"$_file" | |
at_exit rm "$_file" | |
eval "$1=$(printf %q "$_file")" | |
} | |
at_exit () { | |
local cmd= | |
for x in "$@"; do | |
cmd="$cmd $(printf %q "$x")" | |
done | |
AT_EXIT_ALL=${AT_EXIT_ALL:-}' | |
'"$cmd" | |
trap exit_handler EXIT | |
} | |
exit_handler () { | |
eval "$AT_EXIT_ALL" | |
} | |
main "$@" 3>&1 || { | |
log "ERROR: ${last_error:-unknown error}" | |
log "ERROR: in ${last_error_stack:-}" | |
log "Aborting" | |
exit 1 | |
} 3>&1 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment