mirror of
https://github.com/tests-always-included/mo.git
synced 2024-12-18 16:27:52 +00:00
Pass shellcheck, more specs are handled, preserve function whitespace
This closes #49.
This commit is contained in:
parent
e0e9189355
commit
7604ce3054
223
mo
223
mo
@ -15,26 +15,59 @@
|
|||||||
#/
|
#/
|
||||||
#/ Options:
|
#/ Options:
|
||||||
#/
|
#/
|
||||||
|
#/ --allow-function-arguments
|
||||||
|
#/ Permit functions to be called with additional arguments. Otherwise,
|
||||||
|
#/ the only way to get access to the arguments is to use the
|
||||||
|
#/ MO_FUNCTION_ARGS environment variable.
|
||||||
|
#/ -d, --debug
|
||||||
|
#/ Enable debug logging to stderr.
|
||||||
#/ -u, --fail-not-set
|
#/ -u, --fail-not-set
|
||||||
#/ Fail upon expansion of an unset variable.
|
#/ Fail upon expansion of an unset variable. Will silently ignore by
|
||||||
|
#/ default. Alternately, set MO_FAIL_ON_UNSET to a non-empty value.
|
||||||
#/ -x, --fail-on-function
|
#/ -x, --fail-on-function
|
||||||
#/ Fail when a function returns a non-zero status code.
|
#/ Fail when a function returns a non-zero status code instead of
|
||||||
|
#/ silently ignoring it. Alternately, set MO_FAIL_ON_FUNCTION to a
|
||||||
|
#/ non-empty value.
|
||||||
|
#/ -f, --fail-on-file
|
||||||
|
#/ Fail when a file (from command-line or partial) does not exist.
|
||||||
|
#/ Alternately, set MO_FAIL_ON_FILE to a non-empty value.
|
||||||
#/ -e, --false
|
#/ -e, --false
|
||||||
#/ Treat the string "false" as empty for conditionals.
|
#/ Treat the string "false" as empty for conditionals. Alternately,
|
||||||
|
#/ set MO_FALSE_IS_EMPTY to a non-empty value.
|
||||||
#/ -h, --help
|
#/ -h, --help
|
||||||
#/ This message.
|
#/ This message.
|
||||||
#/ -s=FILE, --source=FILE
|
#/ -s=FILE, --source=FILE
|
||||||
#/ Load FILE into the environment before processing templates.
|
#/ Load FILE into the environment before processing templates.
|
||||||
#/ Can be used multiple times.
|
#/ Can be used multiple times.
|
||||||
#/ -d, --debug
|
#/ -- Indicate the end of options. All arguments after this will be
|
||||||
#/ Enable debug logging to stderr.
|
#/ treated as filenames only. Use when filenames may start with
|
||||||
#
|
#/ hyphens.
|
||||||
# Mo is under a MIT style licence with an additional non-advertising clause.
|
#/
|
||||||
# See LICENSE.md for the full text.
|
#/ Mo uses the following environment variables:
|
||||||
#
|
#/
|
||||||
# This is open source! Please feel free to contribute.
|
#/ MO_ALLOW_FUNCTION_ARGUMENTS - When set to a non-empty value, this allows
|
||||||
#
|
#/ functions referenced in templates to receive additional options and
|
||||||
# https://github.com/tests-always-included/mo
|
#/ arguments.
|
||||||
|
#/ MO_DEBUG - When set to a non-empty value, additional debug information is
|
||||||
|
#/ written to stderr.
|
||||||
|
#/ MO_FUNCTION_ARGS - Arguments passed to the function.
|
||||||
|
#/ MO_FAIL_ON_FILE - If a filename from the command-line is missing or a
|
||||||
|
#/ partial does not exist, abort with an error.
|
||||||
|
#/ MO_FAIL_ON_FUNCTION - If a function returns a non-zero status code, abort
|
||||||
|
#/ with an error.
|
||||||
|
#/ MO_FAIL_ON_UNSET - When set to a non-empty value, expansion of an unset env
|
||||||
|
#/ variable will be aborted with an error.
|
||||||
|
#/ MO_FALSE_IS_EMPTY - When set to a non-empty value, the string "false" will
|
||||||
|
#/ be treated as an empty value for the purposes of conditionals.
|
||||||
|
#/ MO_ORIGINAL_COMMAND - Used to find the `mo` program in order to generate a
|
||||||
|
#/ help message.
|
||||||
|
#/
|
||||||
|
#/ Mo is under a MIT style licence with an additional non-advertising clause.
|
||||||
|
#/ See LICENSE.md for the full text.
|
||||||
|
#/
|
||||||
|
#/ This is open source! Please feel free to contribute.
|
||||||
|
#/
|
||||||
|
#/ https://github.com/tests-always-included/mo
|
||||||
|
|
||||||
|
|
||||||
# Public: Template parser function. Writes templates to stdout.
|
# Public: Template parser function. Writes templates to stdout.
|
||||||
@ -42,63 +75,7 @@
|
|||||||
# $0 - Name of the mo file, used for getting the help message.
|
# $0 - Name of the mo file, used for getting the help message.
|
||||||
# $@ - Filenames to parse.
|
# $@ - Filenames to parse.
|
||||||
#
|
#
|
||||||
# Options:
|
# See the comment above for details.
|
||||||
#
|
|
||||||
# --allow-function-arguments
|
|
||||||
#
|
|
||||||
# Permit functions in templates to be called with additional arguments. This
|
|
||||||
# puts template data directly in to the path of an eval statement. Use with
|
|
||||||
# caution. Not listed in the help because it only makes sense when mo is
|
|
||||||
# sourced.
|
|
||||||
#
|
|
||||||
# -u, --fail-not-set
|
|
||||||
#
|
|
||||||
# Fail upon expansion of an unset variable. Default behavior is to silently
|
|
||||||
# ignore and expand into empty string.
|
|
||||||
#
|
|
||||||
# -x, --fail-on-function
|
|
||||||
#
|
|
||||||
# Fail when a function used by a template returns an error status code.
|
|
||||||
# Alternately, ou may set the MO_FAIL_ON_FUNCTION environment variable to a
|
|
||||||
# non-empty value to enable this behavior.
|
|
||||||
#
|
|
||||||
# -e, --false
|
|
||||||
#
|
|
||||||
# Treat "false" as an empty value. You may set the MO_FALSE_IS_EMPTY
|
|
||||||
# environment variable instead to a non-empty value to enable this behavior.
|
|
||||||
#
|
|
||||||
# -h, --help
|
|
||||||
#
|
|
||||||
# Display a help message.
|
|
||||||
#
|
|
||||||
# -s=FILE, --source=FILE
|
|
||||||
#
|
|
||||||
# Source a file into the environment before processing template files.
|
|
||||||
# This can be used multiple times.
|
|
||||||
#
|
|
||||||
# --
|
|
||||||
#
|
|
||||||
# Used to indicate the end of options. You may optionally use this when
|
|
||||||
# filenames may start with two hyphens.
|
|
||||||
#
|
|
||||||
# Mo uses the following environment variables:
|
|
||||||
#
|
|
||||||
# MO_ALLOW_FUNCTION_ARGUMENTS - When set to a non-empty value, this allows
|
|
||||||
# functions referenced in templates to receive additional
|
|
||||||
# options and arguments. This puts the content from the
|
|
||||||
# template directly into an eval statement. Use with extreme
|
|
||||||
# care.
|
|
||||||
# MO_DEBUG - When set to a non-empty value, additional debug information is
|
|
||||||
# written to stderr.
|
|
||||||
# MO_FUNCTION_ARGS - Arguments passed to the function.
|
|
||||||
# MO_FAIL_ON_FUNCTION - If a function returns a non-zero status code, abort
|
|
||||||
# with an error.
|
|
||||||
# MO_FAIL_ON_UNSET - When set to a non-empty value, expansion of an unset env
|
|
||||||
# variable will be aborted with an error.
|
|
||||||
# MO_FALSE_IS_EMPTY - When set to a non-empty value, the string "false" will be
|
|
||||||
# treated as an empty value for the purposes of conditionals.
|
|
||||||
# MO_ORIGINAL_COMMAND - Used to find the `mo` program in order to generate a
|
|
||||||
# help message.
|
|
||||||
#
|
#
|
||||||
# Returns nothing.
|
# Returns nothing.
|
||||||
mo() (
|
mo() (
|
||||||
@ -140,6 +117,11 @@ mo() (
|
|||||||
MO_FAIL_ON_FUNCTION=true
|
MO_FAIL_ON_FUNCTION=true
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
-p | --fail-on-file)
|
||||||
|
# shellcheck disable=SC2030
|
||||||
|
MO_FAIL_ON_FILE=true
|
||||||
|
;;
|
||||||
|
|
||||||
-e | --false)
|
-e | --false)
|
||||||
# shellcheck disable=SC2030
|
# shellcheck disable=SC2030
|
||||||
MO_FALSE_IS_EMPTY=true
|
MO_FALSE_IS_EMPTY=true
|
||||||
@ -162,6 +144,7 @@ mo() (
|
|||||||
;;
|
;;
|
||||||
|
|
||||||
-d | --debug)
|
-d | --debug)
|
||||||
|
# shellcheck disable=SC2030
|
||||||
MO_DEBUG=true
|
MO_DEBUG=true
|
||||||
;;
|
;;
|
||||||
|
|
||||||
@ -170,6 +153,10 @@ mo() (
|
|||||||
moDoubleHyphens=true
|
moDoubleHyphens=true
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
-*)
|
||||||
|
mo::error "Unknown option: $arg (See --help for options)"
|
||||||
|
;;
|
||||||
|
|
||||||
*)
|
*)
|
||||||
#: Every arg that is not a flag or a option should be a file
|
#: Every arg that is not a flag or a option should be a file
|
||||||
moFiles=(${moFiles[@]+"${moFiles[@]}"} "$arg")
|
moFiles=(${moFiles[@]+"${moFiles[@]}"} "$arg")
|
||||||
@ -192,6 +179,7 @@ mo() (
|
|||||||
#
|
#
|
||||||
# Returns nothing.
|
# Returns nothing.
|
||||||
mo::debug() {
|
mo::debug() {
|
||||||
|
# shellcheck disable=SC2031
|
||||||
if [[ -n "${MO_DEBUG:-}" ]]; then
|
if [[ -n "${MO_DEBUG:-}" ]]; then
|
||||||
echo "DEBUG: $1" >&2
|
echo "DEBUG: $1" >&2
|
||||||
fi
|
fi
|
||||||
@ -205,7 +193,7 @@ mo::debug() {
|
|||||||
# Returns nothing. Exits the program.
|
# Returns nothing. Exits the program.
|
||||||
mo::error() {
|
mo::error() {
|
||||||
echo "ERROR: $1" >&2
|
echo "ERROR: $1" >&2
|
||||||
exit ${2:-1}
|
exit "${2:-1}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -264,17 +252,26 @@ mo::content() {
|
|||||||
#
|
#
|
||||||
# Returns nothing.
|
# Returns nothing.
|
||||||
mo::contentFile() {
|
mo::contentFile() {
|
||||||
local moContent moLen
|
local moContent moFile
|
||||||
|
|
||||||
# The subshell removes any trailing newlines. We forcibly add
|
# The subshell removes any trailing newlines. We forcibly add
|
||||||
# a dot to the content to preserve all newlines.
|
# a dot to the content to preserve all newlines.
|
||||||
# As a future optimization, it would be worth considering removing
|
# As a future optimization, it would be worth considering removing
|
||||||
# cat and replacing this with a read loop.
|
# cat and replacing this with a read loop.
|
||||||
|
|
||||||
mo::debug "Loading content: ${2:-/dev/stdin}"
|
moFile=${2:-/dev/stdin}
|
||||||
moContent=$(cat -- "${2:-/dev/stdin}" && echo '.') || return 1
|
|
||||||
moLen=$((${#moContent} - 1))
|
# shellcheck disable=SC2031
|
||||||
moContent=${moContent:0:$moLen} # Remove last dot
|
if [[ -e "$moFile" ]]; then
|
||||||
|
mo::debug "Loading content: $moFile"
|
||||||
|
moContent=$(cat -- "$moFile" && echo '.') || return 1
|
||||||
|
moContent=${moContent%.} # Remove last dot
|
||||||
|
elif [[ -n "${MO_FAIL_ON_FILE-}" ]]; then
|
||||||
|
mo::error "No such file: $moFile"
|
||||||
|
else
|
||||||
|
mo::debug "File does not exist: $moFile"
|
||||||
|
moContent=""
|
||||||
|
fi
|
||||||
|
|
||||||
local "$1" && mo::indirect "$1" "$moContent"
|
local "$1" && mo::indirect "$1" "$moContent"
|
||||||
}
|
}
|
||||||
@ -384,9 +381,9 @@ mo::trim() {
|
|||||||
while [[ "$moContent" != "$moLast" ]]; do
|
while [[ "$moContent" != "$moLast" ]]; do
|
||||||
moLast=$moContent
|
moLast=$moContent
|
||||||
moContent=${moContent# }
|
moContent=${moContent# }
|
||||||
moContent=${moContent#$moR}
|
moContent=${moContent#"$moR"}
|
||||||
moContent=${moContent#$moN}
|
moContent=${moContent#"$moN"}
|
||||||
moContent=${moContent#$moT}
|
moContent=${moContent#"$moT"}
|
||||||
done
|
done
|
||||||
|
|
||||||
local "$1" && mo::indirect "$1" "$moContent"
|
local "$1" && mo::indirect "$1" "$moContent"
|
||||||
@ -406,9 +403,9 @@ mo::chomp() {
|
|||||||
moN=$'\n'
|
moN=$'\n'
|
||||||
moT=$'\t'
|
moT=$'\t'
|
||||||
moTemp=${2%% *}
|
moTemp=${2%% *}
|
||||||
moTemp=${moTemp%%$moR*}
|
moTemp=${moTemp%%"$moR"*}
|
||||||
moTemp=${moTemp%%$moN*}
|
moTemp=${moTemp%%"$moN"*}
|
||||||
moTemp=${moTemp%%$moT*}
|
moTemp=${moTemp%%"$moT"*}
|
||||||
|
|
||||||
local "$1" && mo::indirect "$1" "$moTemp"
|
local "$1" && mo::indirect "$1" "$moTemp"
|
||||||
}
|
}
|
||||||
@ -440,7 +437,7 @@ mo::chomp() {
|
|||||||
#
|
#
|
||||||
# Returns nothing.
|
# Returns nothing.
|
||||||
mo::parse() {
|
mo::parse() {
|
||||||
local moContent moCurrent moOpenDelimiter moCloseDelimieter moResult moSplit moParseChunk moFastMode moStandaloneContent moRemainder
|
local moContent moCurrent moOpenDelimiter moCloseDelimiter moResult moSplit moParseChunk moFastMode moStandaloneContent moRemainder
|
||||||
moContent=$2
|
moContent=$2
|
||||||
moCurrent=$3
|
moCurrent=$3
|
||||||
moCurrentBlock=$4
|
moCurrentBlock=$4
|
||||||
@ -777,15 +774,15 @@ mo::parsePartial() {
|
|||||||
moCloseDelimiter=$5
|
moCloseDelimiter=$5
|
||||||
moFastMode=$6
|
moFastMode=$6
|
||||||
moStandaloneContent=$7
|
moStandaloneContent=$7
|
||||||
mo::chomp moFilename "${moContent%%$moCloseDelimiter*}"
|
mo::chomp moFilename "${moContent%%"$moCloseDelimiter"*}"
|
||||||
moContent="${moContent#*$moCloseDelimiter}"
|
moContent="${moContent#*"$moCloseDelimiter"}"
|
||||||
moIndentation=""
|
moIndentation=""
|
||||||
|
|
||||||
if mo::standaloneCheck "$moStandaloneContent" "$moContent"; then
|
if mo::standaloneCheck "$moStandaloneContent" "$moContent"; then
|
||||||
moN=$'\n'
|
moN=$'\n'
|
||||||
moR=$'\r'
|
moR=$'\r'
|
||||||
moIndentation="$moN${moPrevious//$moR/$moN}"
|
moIndentation="$moN${moPrevious//"$moR"/"$moN"}"
|
||||||
moIndentation=${moIndentation##*$moN}
|
moIndentation=${moIndentation##*"$moN"}
|
||||||
mo::debug "Adding indentation to partial: '$moIndentation'"
|
mo::debug "Adding indentation to partial: '$moIndentation'"
|
||||||
mo::standaloneProcessBefore moPrevious "$moPrevious"
|
mo::standaloneProcessBefore moPrevious "$moPrevious"
|
||||||
mo::standaloneProcessAfter moContent "$moContent"
|
mo::standaloneProcessAfter moContent "$moContent"
|
||||||
@ -796,7 +793,6 @@ mo::parsePartial() {
|
|||||||
|
|
||||||
if [[ -n "$moFastMode" ]]; then
|
if [[ -n "$moFastMode" ]]; then
|
||||||
moResult=""
|
moResult=""
|
||||||
moLen=0
|
|
||||||
else
|
else
|
||||||
mo::debug "Parsing partial: $moFilename"
|
mo::debug "Parsing partial: $moFilename"
|
||||||
|
|
||||||
@ -901,7 +897,7 @@ mo::parseComment() {
|
|||||||
moContent=$3
|
moContent=$3
|
||||||
moCloseDelimiter=$4
|
moCloseDelimiter=$4
|
||||||
moStandaloneContent=$5
|
moStandaloneContent=$5
|
||||||
moContent=${moContent#*$moCloseDelimiter}
|
moContent=${moContent#*"$moCloseDelimiter"}
|
||||||
mo::debug "Parsing comment"
|
mo::debug "Parsing comment"
|
||||||
|
|
||||||
if mo::standaloneCheck "$moStandaloneContent" "$moContent"; then
|
if mo::standaloneCheck "$moStandaloneContent" "$moContent"; then
|
||||||
@ -942,8 +938,8 @@ mo::parseDelimiter() {
|
|||||||
mo::chomp moOpen "$moContent"
|
mo::chomp moOpen "$moContent"
|
||||||
moContent=${moContent:${#moOpen}}
|
moContent=${moContent:${#moOpen}}
|
||||||
mo::trim moContent "$moContent"
|
mo::trim moContent "$moContent"
|
||||||
moClose="${moContent%%=$moCloseDelimiter*}"
|
moClose="${moContent%%="$moCloseDelimiter"*}"
|
||||||
moContent=${moContent#*=$moCloseDelimiter}
|
moContent=${moContent#*="$moCloseDelimiter"}
|
||||||
mo::debug "Parsing delimiters: $moOpen $moClose"
|
mo::debug "Parsing delimiters: $moOpen $moClose"
|
||||||
|
|
||||||
if mo::standaloneCheck "$moStandaloneContent" "$moContent"; then
|
if mo::standaloneCheck "$moStandaloneContent" "$moContent"; then
|
||||||
@ -983,7 +979,7 @@ mo::parseValue() {
|
|||||||
moOpenDelimiter=$5
|
moOpenDelimiter=$5
|
||||||
moCloseDelimiter=$6
|
moCloseDelimiter=$6
|
||||||
moFastMode=$7
|
moFastMode=$7
|
||||||
mo::trim moContent "${moContentOriginal#$moOpenDelimiter}"
|
mo::trim moContent "${moContentOriginal#"$moOpenDelimiter"}"
|
||||||
|
|
||||||
mo::parseValueInner moArgs "$moContent" "$moCurrent" "$moCloseDelimiter"
|
mo::parseValueInner moArgs "$moContent" "$moCurrent" "$moCloseDelimiter"
|
||||||
moContent=${moArgs[0]}
|
moContent=${moArgs[0]}
|
||||||
@ -1252,7 +1248,7 @@ mo::getArgumentDefault() {
|
|||||||
local moTemp moContent
|
local moTemp moContent
|
||||||
|
|
||||||
moTemp=$2
|
moTemp=$2
|
||||||
mo::chomp moTemp "${moTemp%%$3*}"
|
mo::chomp moTemp "${moTemp%%"$3"*}"
|
||||||
moTemp=${moTemp%%)*}
|
moTemp=${moTemp%%)*}
|
||||||
moTemp=${moTemp%%\}*}
|
moTemp=${moTemp%%\}*}
|
||||||
moContent=${2:${#moTemp}}
|
moContent=${2:${#moTemp}}
|
||||||
@ -1384,6 +1380,7 @@ mo::isTruthy() {
|
|||||||
|
|
||||||
moTruthy=true
|
moTruthy=true
|
||||||
|
|
||||||
|
# shellcheck disable=SC2031
|
||||||
if [[ -z "${1-}" ]]; then
|
if [[ -z "${1-}" ]]; then
|
||||||
moTruthy=false
|
moTruthy=false
|
||||||
elif [[ -n "${MO_FALSE_IS_EMPTY-}" ]] && [[ "${1-}" == "false" ]]; then
|
elif [[ -n "${MO_FALSE_IS_EMPTY-}" ]] && [[ "${1-}" == "false" ]]; then
|
||||||
@ -1533,7 +1530,7 @@ mo::evaluateKey() {
|
|||||||
#
|
#
|
||||||
# Returns nothing.
|
# Returns nothing.
|
||||||
mo::evaluateVariable() {
|
mo::evaluateVariable() {
|
||||||
local moResult moCurrent moArg moNameParts moJoined moKey moValue
|
local moResult moCurrent moArg moNameParts
|
||||||
|
|
||||||
moArg=$2
|
moArg=$2
|
||||||
moCurrent=$3
|
moCurrent=$3
|
||||||
@ -1543,7 +1540,7 @@ mo::evaluateVariable() {
|
|||||||
|
|
||||||
if [[ -z "${moNameParts[1]}" ]]; then
|
if [[ -z "${moNameParts[1]}" ]]; then
|
||||||
if mo::isArray "$moArg"; then
|
if mo::isArray "$moArg"; then
|
||||||
eval mo::join moResult "," "\${$moArg[@]}"
|
eval mo::join moResult "," "\${${moArg}[@]}"
|
||||||
else
|
else
|
||||||
# shellcheck disable=SC2031
|
# shellcheck disable=SC2031
|
||||||
if mo::isVarSet "$moArg"; then
|
if mo::isVarSet "$moArg"; then
|
||||||
@ -1560,7 +1557,7 @@ mo::evaluateVariable() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local $1 && mo::indirect "$1" "$moResult"
|
local "$1" && mo::indirect "$1" "$moResult"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1648,7 +1645,7 @@ moJoin() {
|
|||||||
#
|
#
|
||||||
# Returns nothing.
|
# Returns nothing.
|
||||||
mo::evaluateFunction() {
|
mo::evaluateFunction() {
|
||||||
local moArgs moContent moFunctionArgs moFunctionResult moTarget moFunction moTemp moFunctionCall
|
local moArgs moContent moFunctionResult moTarget moFunction moTemp moFunctionCall
|
||||||
|
|
||||||
moTarget=$1
|
moTarget=$1
|
||||||
moContent=$2
|
moContent=$2
|
||||||
@ -1675,16 +1672,18 @@ mo::evaluateFunction() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
mo::debug "Calling function: $moFunctionCall"
|
mo::debug "Calling function: $moFunctionCall"
|
||||||
moContent=$(export MO_FUNCTION_ARGS=("${moArgs[@]}"); echo -n "$moContent" | eval "$moFunctionCall") || {
|
|
||||||
|
# Call the function in a subshell for safety. Employ the trick to preserve
|
||||||
|
# whitespace at the end of the output.
|
||||||
|
moContent=$(export MO_FUNCTION_ARGS=("${moArgs[@]}"); echo -n "$moContent" | eval "$moFunctionCall ; moFunctionResult=\$? ; echo -n '.' ; exit \"\$moFunctionResult\"") || {
|
||||||
moFunctionResult=$?
|
moFunctionResult=$?
|
||||||
# shellcheck disable=SC2031
|
# shellcheck disable=SC2031
|
||||||
if [[ -n "${MO_FAIL_ON_FUNCTION-}" && "$moFunctionResult" != 0 ]]; then
|
if [[ -n "${MO_FAIL_ON_FUNCTION-}" && "$moFunctionResult" != 0 ]]; then
|
||||||
mo::error "Function '$moFunction' with args (${moArgs[@]+"${moArgs[@]}"}) failed with status code $moFunctionResult" "$moFunctionResult"
|
mo::error "Function failed with status code $moFunctionResult: $moFunctionCall" "$moFunctionResult"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# shellcheck disable=SC2031
|
local "$moTarget" && mo::indirect "$moTarget" "${moContent%.}"
|
||||||
local "$moTarget" && mo::indirect "$moTarget" "$moContent"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1704,7 +1703,7 @@ mo::standaloneCheck() {
|
|||||||
moT=$'\t'
|
moT=$'\t'
|
||||||
|
|
||||||
# Check the content before
|
# Check the content before
|
||||||
moContent=${1//$moR/$moN}
|
moContent=${1//"$moR"/"$moN"}
|
||||||
|
|
||||||
if [[ "$moContent" != *"$moN"* ]]; then
|
if [[ "$moContent" != *"$moN"* ]]; then
|
||||||
mo::debug "Not a standalone tag - no newline before"
|
mo::debug "Not a standalone tag - no newline before"
|
||||||
@ -1712,8 +1711,8 @@ mo::standaloneCheck() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
moContent=${moContent##*$moN}
|
moContent=${moContent##*"$moN"}
|
||||||
moContent=${moContent//$moT/}
|
moContent=${moContent//"$moT"/}
|
||||||
moContent=${moContent// /}
|
moContent=${moContent// /}
|
||||||
|
|
||||||
if [[ -n "$moContent" ]]; then
|
if [[ -n "$moContent" ]]; then
|
||||||
@ -1723,9 +1722,9 @@ mo::standaloneCheck() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Check the content after
|
# Check the content after
|
||||||
moContent=${2//$moR/$moN}
|
moContent=${2//"$moR"/"$moN"}
|
||||||
moContent=${moContent%%$moN*}
|
moContent=${moContent%%"$moN"*}
|
||||||
moContent=${moContent//$moT/}
|
moContent=${moContent//"$moT"/}
|
||||||
moContent=${moContent// /}
|
moContent=${moContent// /}
|
||||||
|
|
||||||
if [[ -n "$moContent" ]]; then
|
if [[ -n "$moContent" ]]; then
|
||||||
@ -1756,7 +1755,7 @@ mo::standaloneProcessBefore() {
|
|||||||
while [[ "$moLast" != "$moContent" ]]; do
|
while [[ "$moLast" != "$moContent" ]]; do
|
||||||
moLast=$moContent
|
moLast=$moContent
|
||||||
moContent=${moContent% }
|
moContent=${moContent% }
|
||||||
moContent=${moContent%$moT}
|
moContent=${moContent%"$moT"}
|
||||||
done
|
done
|
||||||
|
|
||||||
local "$1" && mo::indirect "$1" "$moContent"
|
local "$1" && mo::indirect "$1" "$moContent"
|
||||||
@ -1783,11 +1782,11 @@ mo::standaloneProcessAfter() {
|
|||||||
while [[ "$moLast" != "$moContent" ]]; do
|
while [[ "$moLast" != "$moContent" ]]; do
|
||||||
moLast=$moContent
|
moLast=$moContent
|
||||||
moContent=${moContent# }
|
moContent=${moContent# }
|
||||||
moContent=${moContent#$moT}
|
moContent=${moContent#"$moT"}
|
||||||
done
|
done
|
||||||
|
|
||||||
moContent=${moContent#$moR}
|
moContent=${moContent#"$moR"}
|
||||||
moContent=${moContent#$moN}
|
moContent=${moContent#"$moN"}
|
||||||
|
|
||||||
local "$1" && mo::indirect "$1" "$moContent"
|
local "$1" && mo::indirect "$1" "$moContent"
|
||||||
}
|
}
|
||||||
@ -1816,8 +1815,8 @@ mo::indentLines() {
|
|||||||
mo::debug "Applying indentation: '${moIndentation}'"
|
mo::debug "Applying indentation: '${moIndentation}'"
|
||||||
|
|
||||||
while [[ -n "$moContent" ]]; do
|
while [[ -n "$moContent" ]]; do
|
||||||
moChunk=${moContent%%$moN*}
|
moChunk=${moContent%%"$moN"*}
|
||||||
moChunk=${moChunk%%$moR*}
|
moChunk=${moChunk%%"$moR"*}
|
||||||
moContent=${moContent:${#moChunk}}
|
moContent=${moContent:${#moChunk}}
|
||||||
|
|
||||||
if [[ -n "$moChunk" ]]; then
|
if [[ -n "$moChunk" ]]; then
|
||||||
|
25
run-spec.js
25
run-spec.js
@ -11,6 +11,12 @@ const fsPromises = require("fs").promises;
|
|||||||
//
|
//
|
||||||
// To override any test property, just define that property.
|
// To override any test property, just define that property.
|
||||||
const testOverrides = {
|
const testOverrides = {
|
||||||
|
"Comments -> Variable Name Collision": {
|
||||||
|
// Can't use variables with exclamation points easily
|
||||||
|
data: {
|
||||||
|
comment: 4
|
||||||
|
}
|
||||||
|
},
|
||||||
"Interpolation -> HTML Escaping": {
|
"Interpolation -> HTML Escaping": {
|
||||||
skip: "HTML escaping is not supported"
|
skip: "HTML escaping is not supported"
|
||||||
},
|
},
|
||||||
@ -20,6 +26,9 @@ const testOverrides = {
|
|||||||
"Lambdas -> Escaping": {
|
"Lambdas -> Escaping": {
|
||||||
skip: "HTML escaping is not supported"
|
skip: "HTML escaping is not supported"
|
||||||
},
|
},
|
||||||
|
"Partials -> Recursion": {
|
||||||
|
skip: "Complex objects are not supported and context is reset to the global level, so the recursion will loop forever"
|
||||||
|
},
|
||||||
"Sections -> Deeply Nested Contexts": {
|
"Sections -> Deeply Nested Contexts": {
|
||||||
skip: "Nested objects are not supported"
|
skip: "Nested objects are not supported"
|
||||||
},
|
},
|
||||||
@ -268,6 +277,7 @@ function applyTestOverrides(test) {
|
|||||||
test[key] = value;
|
test[key] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test.overridesApplied = true;
|
||||||
test.valuesBeforeOverride = originals;
|
test.valuesBeforeOverride = originals;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,6 +320,7 @@ function processSpecFile(filename) {
|
|||||||
testSet.pass = 0;
|
testSet.pass = 0;
|
||||||
testSet.fail = 0;
|
testSet.fail = 0;
|
||||||
testSet.skip = 0;
|
testSet.skip = 0;
|
||||||
|
testSet.passOverride = 0;
|
||||||
|
|
||||||
for (const test of testSet.tests) {
|
for (const test of testSet.tests) {
|
||||||
if (test.isFailure) {
|
if (test.isFailure) {
|
||||||
@ -318,10 +329,14 @@ function processSpecFile(filename) {
|
|||||||
testSet.skip += 1;
|
testSet.skip += 1;
|
||||||
} else {
|
} else {
|
||||||
testSet.pass += 1;
|
testSet.pass += 1;
|
||||||
|
|
||||||
|
if (test.overridesApplied) {
|
||||||
|
testSet.passOverride += 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(
|
console.log(
|
||||||
`### ${testSet.name} Results = ${testSet.pass} passed, ${testSet.fail} failed, ${testSet.skip} skipped`
|
`### ${testSet.name} Results = ${testSet.pass} passed (with ${testSet.passOverride} overridden), ${testSet.fail} failed, ${testSet.skip} skipped`
|
||||||
);
|
);
|
||||||
|
|
||||||
return testSet;
|
return testSet;
|
||||||
@ -344,16 +359,18 @@ processArraySequentially(process.argv.slice(2), processSpecFile).then(
|
|||||||
let pass = 0,
|
let pass = 0,
|
||||||
fail = 0,
|
fail = 0,
|
||||||
skip = 0,
|
skip = 0,
|
||||||
total = 0;
|
total = 0,
|
||||||
|
passOverride = 0;
|
||||||
|
|
||||||
for (const testSet of result) {
|
for (const testSet of result) {
|
||||||
pass += testSet.pass;
|
pass += testSet.pass;
|
||||||
fail += testSet.fail;
|
fail += testSet.fail;
|
||||||
skip += testSet.skip;
|
skip += testSet.skip;
|
||||||
total += testSet.tests.length;
|
total += testSet.tests.length;
|
||||||
|
passOverride += testSet.passOverride;
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
`* ${testSet.name}: ${testSet.tests.length} total, ${testSet.pass} pass, ${testSet.fail} fail, ${testSet.skip} skip`
|
`* ${testSet.name}: ${testSet.tests.length} total, ${testSet.pass} pass (with ${passOverride} overridden), ${testSet.fail} fail, ${testSet.skip} skip`
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const test of testSet.tests) {
|
for (const test of testSet.tests) {
|
||||||
@ -365,7 +382,7 @@ processArraySequentially(process.argv.slice(2), processSpecFile).then(
|
|||||||
|
|
||||||
console.log("");
|
console.log("");
|
||||||
console.log(
|
console.log(
|
||||||
`Final result: ${total} total, ${pass} pass, ${fail} fail, ${skip} skip`
|
`Final result: ${total} total, ${pass} pass (with ${passOverride} overridden), ${fail} fail, ${skip} skip`
|
||||||
);
|
);
|
||||||
|
|
||||||
if (fail) {
|
if (fail) {
|
||||||
|
@ -52,6 +52,8 @@ runTest() (
|
|||||||
|
|
||||||
if [[ -n "${MO_DEBUG_TEST-}" ]]; then
|
if [[ -n "${MO_DEBUG_TEST-}" ]]; then
|
||||||
declare -p testExpected
|
declare -p testExpected
|
||||||
|
# Align the two declare outputs
|
||||||
|
echo -n " "
|
||||||
declare -p testActual
|
declare -p testActual
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
thing="Works"
|
export thing="Works"
|
||||||
template="{{&thing}}"
|
export template="{{&thing}}"
|
||||||
expected="Works"
|
export expected="Works"
|
||||||
|
|
||||||
runTest
|
runTest
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
repo=( "resque" "hub" "rip" )
|
export repo=( "resque" "hub" "rip" )
|
||||||
template() {
|
template() {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
{{#repo}}
|
{{#repo}}
|
||||||
|
@ -6,6 +6,7 @@ declare -A repo
|
|||||||
repo[resque]="Resque"
|
repo[resque]="Resque"
|
||||||
repo[hub]="Hub"
|
repo[hub]="Hub"
|
||||||
repo[rip]="Rip"
|
repo[rip]="Rip"
|
||||||
|
export repo
|
||||||
template() {
|
template() {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
{{#repo}}
|
{{#repo}}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
template="Wor{{!comment}}ks"
|
export template="Wor{{!comment}}ks"
|
||||||
expected="Works"
|
export expected="Works"
|
||||||
|
|
||||||
runTest
|
runTest
|
||||||
|
@ -10,10 +10,6 @@ run through multiple
|
|||||||
lines}}.</h1>
|
lines}}.</h1>
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
expected() {
|
export expected=$'<h1>Today.</h1>\n'
|
||||||
cat <<EOF
|
|
||||||
<h1>Today.</h1>
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
runTest
|
runTest
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
template="Wor{{! comment }}ks"
|
export template="Wor{{! comment }}ks"
|
||||||
expected="Works"
|
export expected="Works"
|
||||||
|
|
||||||
runTest
|
runTest
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
thing="Wor"
|
export thing="Wor"
|
||||||
thing2="ks"
|
export thing2="ks"
|
||||||
template="{{thing thing2}}"
|
export template="{{thing thing2}}"
|
||||||
expected="Works"
|
export expected="Works"
|
||||||
|
|
||||||
runTest
|
runTest
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
thing="Works"
|
export thing="Works"
|
||||||
template="{{=| |=}}|thing|"
|
export template="{{=| |=}}|thing|"
|
||||||
expected="Works"
|
export expected="Works"
|
||||||
|
|
||||||
runTest
|
runTest
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
arguments=(-- --help)
|
export arguments=(--fail-on-file -- --help)
|
||||||
returnCode=1
|
export returnCode=1
|
||||||
template=""
|
export template=""
|
||||||
expected="cat: --help: No such file or directory"$'\n'
|
export expected=$'ERROR: No such file: --help\n'
|
||||||
|
|
||||||
runTest
|
runTest
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
template='{{"Works"}}'
|
export template='{{"Works"}}'
|
||||||
expected="Works"
|
export expected="Works"
|
||||||
|
|
||||||
runTest
|
runTest
|
||||||
|
@ -3,10 +3,10 @@ cd "${0%/*}" || exit 1
|
|||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
unset __NO_SUCH_VAR
|
unset __NO_SUCH_VAR
|
||||||
POPULATED="words"
|
export POPULATED="words"
|
||||||
EMPTY=""
|
export EMPTY=""
|
||||||
arguments=(--fail-not-set)
|
export arguments=(--fail-not-set)
|
||||||
returnCode=1
|
export returnCode=1
|
||||||
|
|
||||||
template() {
|
template() {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
@ -15,10 +15,6 @@ Empty: {{EMPTY}};
|
|||||||
Unset: {{__NO_SUCH_VAR}};
|
Unset: {{__NO_SUCH_VAR}};
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
expected() {
|
export expected=$'ERROR: Environment variable not set: __NO_SUCH_VAR\n'
|
||||||
cat <<EOF
|
|
||||||
ERROR: Environment variable not set: __NO_SUCH_VAR
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
runTest
|
runTest
|
||||||
|
@ -5,14 +5,9 @@ cd "${0%/*}" || exit 1
|
|||||||
failFunction() {
|
failFunction() {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
arguments=(--fail-on-function)
|
export arguments=(--fail-on-function)
|
||||||
returnCode=1
|
export returnCode=1
|
||||||
|
export template="Fail on function? {{failFunction}}"
|
||||||
template="Fail on function? {{failFunction}}"
|
export expected=$'ERROR: Function failed with status code 1: "failFunction"\n'
|
||||||
expected() {
|
|
||||||
cat <<EOF
|
|
||||||
ERROR: Function 'failFunction' with args () failed with status code 1
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
runTest
|
runTest
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
USER=j.doe
|
export USER=j.doe
|
||||||
ADMIN=false
|
export ADMIN=false
|
||||||
arguments=(--false)
|
export arguments=(--false)
|
||||||
template() {
|
template() {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
The user {{USER}} exists.
|
The user {{USER}} exists.
|
||||||
@ -13,10 +13,6 @@ WRONG - should not be an admin.
|
|||||||
{{/ADMIN}}
|
{{/ADMIN}}
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
expected() {
|
export expected=$'The user j.doe exists.\n'
|
||||||
cat <<EOF
|
|
||||||
The user j.doe exists.
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
runTest
|
runTest
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
USER=j.doe
|
export USER=j.doe
|
||||||
ADMIN=false
|
export ADMIN=false
|
||||||
MO_FALSE_IS_EMPTY=yeppers
|
MO_FALSE_IS_EMPTY=yeppers
|
||||||
template() {
|
template() {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
@ -13,10 +13,6 @@ WRONG - should not be an admin.
|
|||||||
{{/ADMIN}}
|
{{/ADMIN}}
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
expected() {
|
export expected=$'The user j.doe exists.\n'
|
||||||
cat <<EOF
|
|
||||||
The user j.doe exists.
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
runTest
|
runTest
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
person=""
|
export person=""
|
||||||
template() {
|
template() {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
Shown.
|
Shown.
|
||||||
@ -11,10 +11,6 @@ Shown.
|
|||||||
{{/person}}
|
{{/person}}
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
expected() {
|
export expected=$'Shown.\n'
|
||||||
cat <<EOF
|
|
||||||
Shown.
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
runTest
|
runTest
|
||||||
|
@ -2,9 +2,10 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
name=Willy
|
export name=Willy
|
||||||
wrapped() {
|
wrapped() {
|
||||||
# This eats the newline in the content
|
# Wrapping 'cat' in a subshell eats the trailing whitespace
|
||||||
|
# The echo adds a newline, which is preserved.
|
||||||
echo "<b>$(cat)</b>"
|
echo "<b>$(cat)</b>"
|
||||||
}
|
}
|
||||||
template() {
|
template() {
|
||||||
@ -15,10 +16,6 @@ template() {
|
|||||||
... this is the last line.
|
... this is the last line.
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
expected() {
|
export expected=$'<b> Willy is awesome.</b>\n... this is the last line.\n'
|
||||||
cat <<EOF
|
|
||||||
<b> Willy is awesome.</b>... this is the last line.
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
runTest
|
runTest
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
name=Willy
|
export name=Willy
|
||||||
MO_ALLOW_FUNCTION_ARGUMENTS=true
|
MO_ALLOW_FUNCTION_ARGUMENTS=true
|
||||||
|
|
||||||
pipeTo() {
|
pipeTo() {
|
||||||
|
@ -3,8 +3,10 @@ cd "${0%/*}" || exit 1
|
|||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
testArgs() {
|
testArgs() {
|
||||||
local args=$(declare -p MO_FUNCTION_ARGS)
|
local args
|
||||||
echo "${args#*=}"
|
# shellcheck disable=SC2031
|
||||||
|
args=$(declare -p MO_FUNCTION_ARGS)
|
||||||
|
echo -n "${args#*=}"
|
||||||
}
|
}
|
||||||
template() {
|
template() {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
STR=abc
|
export STR=abc
|
||||||
DATA=(111 222)
|
export DATA=(111 222)
|
||||||
template() {
|
template() {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
Issue #7
|
Issue #7
|
||||||
|
55
tests/help
55
tests/help
@ -2,10 +2,9 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
template=""
|
export arguments=(--help)
|
||||||
arguments=(--help)
|
|
||||||
expected() {
|
expected() {
|
||||||
cat <<EOF
|
cat <<'EOF'
|
||||||
Mo is a mustache template rendering software written in bash. It inserts
|
Mo is a mustache template rendering software written in bash. It inserts
|
||||||
environment variables into templates.
|
environment variables into templates.
|
||||||
|
|
||||||
@ -21,19 +20,59 @@ Simple usage:
|
|||||||
|
|
||||||
Options:
|
Options:
|
||||||
|
|
||||||
|
--allow-function-arguments
|
||||||
|
Permit functions to be called with additional arguments. Otherwise,
|
||||||
|
the only way to get access to the arguments is to use the
|
||||||
|
MO_FUNCTION_ARGS environment variable.
|
||||||
|
-d, --debug
|
||||||
|
Enable debug logging to stderr.
|
||||||
-u, --fail-not-set
|
-u, --fail-not-set
|
||||||
Fail upon expansion of an unset variable.
|
Fail upon expansion of an unset variable. Will silently ignore by
|
||||||
|
default. Alternately, set MO_FAIL_ON_UNSET to a non-empty value.
|
||||||
-x, --fail-on-function
|
-x, --fail-on-function
|
||||||
Fail when a function returns a non-zero status code.
|
Fail when a function returns a non-zero status code instead of
|
||||||
|
silently ignoring it. Alternately, set MO_FAIL_ON_FUNCTION to a
|
||||||
|
non-empty value.
|
||||||
|
-f, --fail-on-file
|
||||||
|
Fail when a file (from command-line or partial) does not exist.
|
||||||
|
Alternately, set MO_FAIL_ON_FILE to a non-empty value.
|
||||||
-e, --false
|
-e, --false
|
||||||
Treat the string "false" as empty for conditionals.
|
Treat the string "false" as empty for conditionals. Alternately,
|
||||||
|
set MO_FALSE_IS_EMPTY to a non-empty value.
|
||||||
-h, --help
|
-h, --help
|
||||||
This message.
|
This message.
|
||||||
-s=FILE, --source=FILE
|
-s=FILE, --source=FILE
|
||||||
Load FILE into the environment before processing templates.
|
Load FILE into the environment before processing templates.
|
||||||
Can be used multiple times.
|
Can be used multiple times.
|
||||||
-d, --debug
|
-- Indicate the end of options. All arguments after this will be
|
||||||
Enable debug logging to stderr.
|
treated as filenames only. Use when filenames may start with
|
||||||
|
hyphens.
|
||||||
|
|
||||||
|
Mo uses the following environment variables:
|
||||||
|
|
||||||
|
MO_ALLOW_FUNCTION_ARGUMENTS - When set to a non-empty value, this allows
|
||||||
|
functions referenced in templates to receive additional options and
|
||||||
|
arguments.
|
||||||
|
MO_DEBUG - When set to a non-empty value, additional debug information is
|
||||||
|
written to stderr.
|
||||||
|
MO_FUNCTION_ARGS - Arguments passed to the function.
|
||||||
|
MO_FAIL_ON_FILE - If a filename from the command-line is missing or a
|
||||||
|
partial does not exist, abort with an error.
|
||||||
|
MO_FAIL_ON_FUNCTION - If a function returns a non-zero status code, abort
|
||||||
|
with an error.
|
||||||
|
MO_FAIL_ON_UNSET - When set to a non-empty value, expansion of an unset env
|
||||||
|
variable will be aborted with an error.
|
||||||
|
MO_FALSE_IS_EMPTY - When set to a non-empty value, the string "false" will
|
||||||
|
be treated as an empty value for the purposes of conditionals.
|
||||||
|
MO_ORIGINAL_COMMAND - Used to find the `mo` program in order to generate a
|
||||||
|
help message.
|
||||||
|
|
||||||
|
Mo is under a MIT style licence with an additional non-advertising clause.
|
||||||
|
See LICENSE.md for the full text.
|
||||||
|
|
||||||
|
This is open source! Please feel free to contribute.
|
||||||
|
|
||||||
|
https://github.com/tests-always-included/mo
|
||||||
|
|
||||||
MO_VERSION=3.0.0
|
MO_VERSION=3.0.0
|
||||||
EOF
|
EOF
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
thisIsTrue=true
|
export thisIsTrue=true
|
||||||
template() {
|
template() {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
With spacing
|
With spacing
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
boolean=true
|
export boolean=true
|
||||||
template=$' | {{#boolean}} {{! Important Whitespace }}\n {{/boolean}} | \n'
|
export template=$' | {{#boolean}} {{! Important Whitespace }}\n {{/boolean}} | \n'
|
||||||
expected=$' | \n | \n'
|
export expected=$' | \n | \n'
|
||||||
|
|
||||||
runTest
|
runTest
|
||||||
|
@ -2,14 +2,10 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
person=""
|
export person=""
|
||||||
template=""
|
export template=""
|
||||||
returnCode=1
|
export returnCode=1
|
||||||
arguments=(--something)
|
export arguments=(--something)
|
||||||
expected() {
|
export expected=$'ERROR: Unknown option: --something (See --help for options)\n'
|
||||||
cat <<EOF
|
|
||||||
cat: --something: No such file or directory
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
runTest
|
runTest
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
repo=()
|
export repo=()
|
||||||
template() {
|
template() {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
{{#repo}}
|
{{#repo}}
|
||||||
@ -13,10 +13,6 @@ template() {
|
|||||||
{{/repo}}
|
{{/repo}}
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
expected() {
|
export expected=$' No repos :(\n'
|
||||||
cat <<EOF
|
|
||||||
No repos :(
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
runTest
|
runTest
|
||||||
|
@ -2,13 +2,15 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
a=foo
|
export a=foo
|
||||||
b=wrong
|
export b=wrong
|
||||||
declare -A sec
|
declare -A sec
|
||||||
sec=([b]="bar")
|
sec=([b]="bar")
|
||||||
|
export sec
|
||||||
declare -A c
|
declare -A c
|
||||||
c=([d]="baz")
|
c=([d]="baz")
|
||||||
template="{{#sec}}{{a}} {{b}} {{c.d}}{{/sec}}"
|
export c
|
||||||
expected="foo bar baz"
|
export template="{{#sec}}{{a}} {{b}} {{c.d}}{{/sec}}"
|
||||||
|
export expected="foo bar baz"
|
||||||
|
|
||||||
runTest
|
runTest
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
name="Chris"
|
export name="Chris"
|
||||||
company="<b>GitHub</b>"
|
export company="<b>GitHub</b>"
|
||||||
template() {
|
template() {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
* .{{name}}.
|
* .{{name}}.
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
multilineData=$'line 1\nline 2'
|
export multilineData=$'line 1\nline 2'
|
||||||
template() {
|
template() {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
Partial:
|
Partial:
|
||||||
@ -26,7 +26,10 @@ Indented:
|
|||||||
line 1
|
line 1
|
||||||
line 2
|
line 2
|
||||||
EOF
|
EOF
|
||||||
# This one looks odd, but if you check the spec spec/specs/partials.yaml, name "Standalone Indentation" (mirrors "standalone-indentation" in tests/), then the spec clearly shows that the indentation is applied before rendering.
|
# This one looks odd, but if you check the spec spec/specs/partials.yaml,
|
||||||
|
# name "Standalone Indentation" (mirrors "standalone-indentation" in
|
||||||
|
# tests/), then the spec clearly shows that the indentation is applied
|
||||||
|
# before rendering.
|
||||||
}
|
}
|
||||||
|
|
||||||
runTest
|
runTest
|
||||||
|
12
tests/mush
12
tests/mush
@ -2,12 +2,12 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
USER=jwerle
|
export USER=jwerle
|
||||||
GENDER=male
|
export GENDER=male
|
||||||
THING=apple
|
export THING=apple
|
||||||
COLOR=red
|
export COLOR=red
|
||||||
PERSON=tobi
|
export PERSON=tobi
|
||||||
ADJECTIVE=cool
|
export ADJECTIVE=cool
|
||||||
template() {
|
template() {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
{{! this is a comment }}
|
{{! this is a comment }}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
template="Works"
|
export template="Works"
|
||||||
expected="Works"
|
export expected="Works"
|
||||||
|
|
||||||
runTest
|
runTest
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
names=( "Tyler" )
|
export names=( "Tyler" )
|
||||||
template() {
|
template() {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
<h2>Names</h2>
|
<h2>Names</h2>
|
||||||
|
9
tests/partial-bad-file
Executable file
9
tests/partial-bad-file
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
cd "${0%/*}" || exit 1
|
||||||
|
. ../run-tests
|
||||||
|
|
||||||
|
# This file intentionally does not exist
|
||||||
|
export template="{{>fixtures/partial-bad-file.partial}}"
|
||||||
|
export expected=""
|
||||||
|
|
||||||
|
runTest
|
@ -2,8 +2,9 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
returnCode=1
|
export returnCode=1
|
||||||
person=""
|
export arguments=(--fail-on-file)
|
||||||
|
export person=""
|
||||||
template() {
|
template() {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
Won't be there: {{> fixtures/partial-missing.partial}}
|
Won't be there: {{> fixtures/partial-missing.partial}}
|
||||||
@ -11,7 +12,7 @@ EOF
|
|||||||
}
|
}
|
||||||
expected() {
|
expected() {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
cat: partial-missing.partial: No such file or directory
|
ERROR: No such file: partial-missing.partial
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
template="{{'Works'}}"
|
export template="{{'Works'}}"
|
||||||
expected="Works"
|
export expected="Works"
|
||||||
|
|
||||||
runTest
|
runTest
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
thing="Works"
|
export thing="Works"
|
||||||
template="{{thing}}"
|
export template="{{thing}}"
|
||||||
expected="Works"
|
export expected="Works"
|
||||||
|
|
||||||
runTest
|
runTest
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
arguments=(--source=fixtures/source.vars)
|
export arguments=(--source=fixtures/source.vars)
|
||||||
template() {
|
template() {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
{{VAR}}
|
{{VAR}}
|
||||||
|
@ -2,13 +2,9 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
arguments=(--source=invalid)
|
export arguments=(--source=invalid)
|
||||||
returnCode=1
|
export returnCode=1
|
||||||
template="Do not display this"
|
export template="Do not display this"
|
||||||
expected() {
|
export expected=$'No such file: invalid\n'
|
||||||
cat <<EOF
|
|
||||||
No such file: invalid
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
|
|
||||||
runTest
|
runTest
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
arguments=(--source=fixtures/source-multiple-1.vars --source=fixtures/source-multiple-2.vars)
|
export arguments=(--source=fixtures/source-multiple-1.vars --source=fixtures/source-multiple-2.vars)
|
||||||
template() {
|
template() {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
A: {{A}}
|
A: {{A}}
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
arguments=(--source=)
|
export arguments=(--source=)
|
||||||
returnCode=1
|
export returnCode=1
|
||||||
template="Do not display this"
|
export template="Do not display this"
|
||||||
expected=$'No such file: \n'
|
export expected=$'No such file: \n'
|
||||||
|
|
||||||
runTest
|
runTest
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
content=$'<\n->'
|
export content=$'<\n->'
|
||||||
template() {
|
template() {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
\
|
\
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
thing="Works"
|
export thing="Works"
|
||||||
template="{{{thing}}}"
|
export template="{{{thing}}}"
|
||||||
expected="Works"
|
export expected="Works"
|
||||||
|
|
||||||
runTest
|
runTest
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
NAME="Chris"
|
export NAME="Chris"
|
||||||
VALUE=10000
|
export VALUE=10000
|
||||||
TAXED_VALUE=6000
|
export TAXED_VALUE=6000
|
||||||
IN_CA=true
|
export IN_CA=true
|
||||||
template() {
|
template() {
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
Hello {{NAME}}
|
Hello {{NAME}}
|
||||||
|
@ -3,8 +3,8 @@ cd "${0%/*}" || exit 1
|
|||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
declare -A a
|
declare -A a
|
||||||
a=()
|
export a=()
|
||||||
template="o{{#a.b}}WRONG{{/a.b}}k"
|
export template="o{{#a.b}}WRONG{{/a.b}}k"
|
||||||
expected="ok"
|
export expected="ok"
|
||||||
|
|
||||||
runTest
|
runTest
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
cd "${0%/*}" || exit 1
|
cd "${0%/*}" || exit 1
|
||||||
. ../run-tests
|
. ../run-tests
|
||||||
|
|
||||||
foo=bar
|
export foo=bar
|
||||||
template="{{#foo}}{{.}} is {{foo}}{{/foo}}"
|
export template="{{#foo}}{{.}} is {{foo}}{{/foo}}"
|
||||||
expected="bar is bar"
|
export expected="bar is bar"
|
||||||
|
|
||||||
runTest
|
runTest
|
||||||
|
Loading…
Reference in New Issue
Block a user