5 Commits
3.0.1 ... 3.0.5

Author SHA1 Message Date
Tyler Akins
26ca5059d8 Fix slowness with larger templates
Closes #69 and #71
Released 3.0.5
2024-03-27 21:57:11 -05:00
Tyler Akins
6e57510ba9 Making it more clear that sourced files are shell
Addresses part of the concerns from #69
2023-11-16 16:04:52 -06:00
Tyler Akins
54b2184b70 Bumping version 2023-09-10 08:11:54 -05:00
Tyler Akins
84d17268c9 Work with symbolic links 2023-09-10 08:10:51 -05:00
Tyler Akins
68306c4c6d More Bash 4.x compatibility issues found and fixed 2023-05-12 08:17:57 -05:00
5 changed files with 60 additions and 30 deletions

View File

@@ -117,9 +117,11 @@ There are more scripts available in the [demos directory](demo/) that could help
There are additional features that the program supports. Try using `mo --help` to see what is available. There are additional features that the program supports. Try using `mo --help` to see what is available.
Please note that this command is written in Bash and pulls data from either the environment or (when using `--source`) from a text file that will be sourced and loaded into the environment, which means you will need to have Bash-style variables defined. Please see the examples in `demo/` for different ways you can use `mo`.
Enhancements Enhancements
----------- ------------
In addition to many of the features built-in to Mustache, `mo` includes a number of unique features that make it a bit more powerful. In addition to many of the features built-in to Mustache, `mo` includes a number of unique features that make it a bit more powerful.

61
mo
View File

@@ -38,7 +38,8 @@
#/ 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. The file must be a valid shell script
#/ and should only contain variable assignments.
#/ -o=DELIM, --open=DELIM #/ -o=DELIM, --open=DELIM
#/ Set the opening delimiter. Default is "{{". #/ Set the opening delimiter. Default is "{{".
#/ -c=DELIM, --close=DELIM #/ -c=DELIM, --close=DELIM
@@ -155,7 +156,7 @@ mo() (
moSource="${arg#-s=}" moSource="${arg#-s=}"
fi fi
if [[ -f "$moSource" ]]; then if [[ -e "$moSource" ]]; then
# shellcheck disable=SC1090 # shellcheck disable=SC1090
. "$moSource" . "$moSource"
else else
@@ -429,19 +430,29 @@ mo::indirectArray() {
# #
# Returns nothing. # Returns nothing.
mo::trimUnparsed() { mo::trimUnparsed() {
local moLast moR moN moT local moLastLen moR moN moT
moLast="" moLastLen=0
moR=$'\r' moR=$'\r'
moN=$'\n' moN=$'\n'
moT=$'\t' moT=$'\t'
while [[ "$MO_UNPARSED" != "$moLast" ]]; do while [[ "${#MO_UNPARSED}" != "$moLastLen" ]]; do
moLast=$MO_UNPARSED moLastLen=${#MO_UNPARSED}
MO_UNPARSED=${MO_UNPARSED# }
MO_UNPARSED=${MO_UNPARSED#"$moR"} # These conditions are necessary for a significant speed increase
MO_UNPARSED=${MO_UNPARSED#"$moN"} while [[ "${MO_UNPARSED:0:1}" == " " ]]; do
MO_UNPARSED=${MO_UNPARSED#"$moT"} MO_UNPARSED=${MO_UNPARSED# }
done
while [[ "${MO_UNPARSED:0:1}" == "$moR" ]]; do
MO_UNPARSED=${MO_UNPARSED#"$moR"}
done
while [[ "${MO_UNPARSED:0:1}" == "$moN" ]]; do
MO_UNPARSED=${MO_UNPARSED#"$moN"}
done
while [[ "${MO_UNPARSED:0:1}" == "$moT" ]]; do
MO_UNPARSED=${MO_UNPARSED#"$moT"}
done
done done
} }
@@ -1061,7 +1072,7 @@ mo::evaluate() {
;; ;;
*) *)
moStack=("${moStack[@]}" "$1" "$2") moStack=(${moStack[@]+"${moStack[@]}"} "$1" "$2")
;; ;;
esac esac
@@ -1077,7 +1088,7 @@ mo::evaluate() {
else else
#: Concatenate #: Concatenate
mo::debug "Concatenating ${#moStack[@]} stack items" mo::debug "Concatenating ${#moStack[@]} stack items"
mo::evaluateListOfSingles moResult "${moStack[@]}" mo::evaluateListOfSingles moResult ${moStack[@]+"${moStack[@]}"}
fi fi
local "$moTarget" && mo::indirect "$moTarget" "$moResult" local "$moTarget" && mo::indirect "$moTarget" "$moResult"
@@ -1310,10 +1321,12 @@ mo::evaluateFunction() {
if [[ -n "${MO_ALLOW_FUNCTION_ARGUMENTS-}" ]]; then if [[ -n "${MO_ALLOW_FUNCTION_ARGUMENTS-}" ]]; then
mo::debug "Function arguments are allowed" mo::debug "Function arguments are allowed"
for moTemp in "${moArgs[@]}"; do if [[ ${#moArgs[@]} -gt 0 ]]; then
mo::escape moTemp "$moTemp" for moTemp in "${moArgs[@]}"; do
moFunctionCall="$moFunctionCall $moTemp" mo::escape moTemp "$moTemp"
done moFunctionCall="$moFunctionCall $moTemp"
done
fi
fi fi
mo::debug "Calling function: $moFunctionCall" mo::debug "Calling function: $moFunctionCall"
@@ -1321,7 +1334,7 @@ mo::evaluateFunction() {
#: Call the function in a subshell for safety. Employ the trick to preserve #: Call the function in a subshell for safety. Employ the trick to preserve
#: whitespace at the end of the output. #: whitespace at the end of the output.
moContent=$( moContent=$(
export MO_FUNCTION_ARGS=("${moArgs[@]}") export MO_FUNCTION_ARGS=(${moArgs[@]+"${moArgs[@]}"})
echo -n "$moContent" | eval "$moFunctionCall ; moFunctionResult=\$? ; echo -n '.' ; exit \"\$moFunctionResult\"" echo -n "$moContent" | eval "$moFunctionCall ; moFunctionResult=\$? ; echo -n '.' ; exit \"\$moFunctionResult\""
) || { ) || {
moFunctionResult=$? moFunctionResult=$?
@@ -1767,7 +1780,7 @@ mo::tokenizeTagContents() {
"$moTerminator"*) "$moTerminator"*)
mo::debug "Found terminator" mo::debug "Found terminator"
local "$1" && mo::indirectArray "$1" "$moTokenCount" "${moResult[@]}" local "$1" && mo::indirectArray "$1" "$moTokenCount" ${moResult[@]+"${moResult[@]}"}
return return
;; ;;
@@ -1775,7 +1788,7 @@ mo::tokenizeTagContents() {
#: Do not tokenize the open paren - treat this as RPL #: Do not tokenize the open paren - treat this as RPL
MO_UNPARSED=${MO_UNPARSED:1} MO_UNPARSED=${MO_UNPARSED:1}
mo::tokenizeTagContents moTemp ')' mo::tokenizeTagContents moTemp ')'
moResult=("${moResult[@]}" "${moTemp[@]:1}" PAREN "${moTemp[0]}") moResult=(${moResult[@]+"${moResult[@]}"} "${moTemp[@]:1}" PAREN "${moTemp[0]}")
MO_UNPARSED=${MO_UNPARSED:1} MO_UNPARSED=${MO_UNPARSED:1}
;; ;;
@@ -1783,7 +1796,7 @@ mo::tokenizeTagContents() {
#: Do not tokenize the open brace - treat this as RPL #: Do not tokenize the open brace - treat this as RPL
MO_UNPARSED=${MO_UNPARSED:1} MO_UNPARSED=${MO_UNPARSED:1}
mo::tokenizeTagContents moTemp '}' mo::tokenizeTagContents moTemp '}'
moResult=("${moResult[@]}" "${moTemp[@]:1}" BRACE "${moTemp[0]}") moResult=(${moResult[@]+"${moResult[@]}"} "${moTemp[@]:1}" BRACE "${moTemp[0]}")
MO_UNPARSED=${MO_UNPARSED:1} MO_UNPARSED=${MO_UNPARSED:1}
;; ;;
@@ -1793,17 +1806,17 @@ mo::tokenizeTagContents() {
"'"*) "'"*)
mo::tokenizeTagContentsSingleQuote moTemp mo::tokenizeTagContentsSingleQuote moTemp
moResult=("${moResult[@]}" "${moTemp[@]}") moResult=(${moResult[@]+"${moResult[@]}"} "${moTemp[@]}")
;; ;;
'"'*) '"'*)
mo::tokenizeTagContentsDoubleQuote moTemp mo::tokenizeTagContentsDoubleQuote moTemp
moResult=("${moResult[@]}" "${moTemp[@]}") moResult=(${moResult[@]+"${moResult[@]}"} "${moTemp[@]}")
;; ;;
*) *)
mo::tokenizeTagContentsName moTemp mo::tokenizeTagContentsName moTemp
moResult=("${moResult[@]}" "${moTemp[@]}") moResult=(${moResult[@]+"${moResult[@]}"} "${moTemp[@]}")
;; ;;
esac esac
@@ -1947,7 +1960,7 @@ mo::tokenizeTagContentsSingleQuote() {
# Save the original command's path for usage later # Save the original command's path for usage later
MO_ORIGINAL_COMMAND="$(cd "${BASH_SOURCE[0]%/*}" || exit 1; pwd)/${BASH_SOURCE[0]##*/}" MO_ORIGINAL_COMMAND="$(cd "${BASH_SOURCE[0]%/*}" || exit 1; pwd)/${BASH_SOURCE[0]##*/}"
MO_VERSION="3.0.1" MO_VERSION="3.0.5"
# If sourced, load all functions. # If sourced, load all functions.
# If executed, perform the actions as expected. # If executed, perform the actions as expected.

View File

@@ -3,7 +3,8 @@ cd "${0%/*}" || exit 1
. ../run-tests . ../run-tests
declare -A repo declare -A repo
repo[resque]="Resque" # The order of the array elements can be shuffled depending on the version of
# Bash. Keeping this to a minimal set and alphabetized seems to help.
repo[hub]="Hub" repo[hub]="Hub"
repo[rip]="Rip" repo[rip]="Rip"
export repo export repo
@@ -18,7 +19,6 @@ expected() {
cat <<EOF cat <<EOF
<b>hub - Hub</b> <b>hub - Hub</b>
<b>rip - Rip</b> <b>rip - Rip</b>
<b>resque - Resque</b>
EOF EOF
} }

View File

@@ -6,7 +6,21 @@ testArgs() {
local args local args
# shellcheck disable=SC2031 # shellcheck disable=SC2031
args=$(declare -p MO_FUNCTION_ARGS) args=$(declare -p MO_FUNCTION_ARGS)
echo -n "${args#*=}"
# The output from declare -p could look like these
# declare -a MO_FUNCTION_ARGS=([0]="one")
# declare -ax MO_FUNCTION_ARGS='([0]="one")'
# Trim leading declare statement and variable name
args="${args#*=}"
# If there are any quotes, remove them. The function arguments will always
# be an array.
if [[ "${args:0:1}" == "'" ]]; then
args=${args#\'}
args=${args%\'}
fi
echo -n "$args"
} }
template() { template() {
cat <<EOF cat <<EOF

View File

@@ -43,7 +43,8 @@ Options:
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. The file must be a valid shell script
and should only contain variable assignments.
-o=DELIM, --open=DELIM -o=DELIM, --open=DELIM
Set the opening delimiter. Default is "{{". Set the opening delimiter. Default is "{{".
-c=DELIM, --close=DELIM -c=DELIM, --close=DELIM
@@ -93,7 +94,7 @@ This is open source! Please feel free to contribute.
https://github.com/tests-always-included/mo https://github.com/tests-always-included/mo
MO_VERSION=3.0.1 MO_VERSION=3.0.5
EOF EOF
} }