mirror of
https://github.com/tests-always-included/mo.git
synced 2024-12-18 16:27:52 +00:00
parent
e6787e71d5
commit
6376a9b817
40
API.md
40
API.md
@ -9,15 +9,17 @@ mo()
|
|||||||
|
|
||||||
Public: Template parser function. Writes templates to stdout.
|
Public: Template parser function. Writes templates to stdout.
|
||||||
|
|
||||||
* $0 - Name of the mo file, used for getting the help message.
|
* $0 - Name of the mo file, used for getting the help message.
|
||||||
* --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.
|
* --fail-not-set - Fail upon expansion of an unset variable. Default behavior is to silently ignore and expand into empty string.
|
||||||
* --help - Display a help message.
|
* --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.
|
||||||
* --source=FILE - Source a file into the environment before processint template files.
|
* --help - Display a help message.
|
||||||
* -- - Used to indicate the end of options. You may optionally use this when filenames may start with two hyphens.
|
* --source=FILE - Source a file into the environment before processint template files.
|
||||||
* $@ - Filenames to parse.
|
* -- - Used to indicate the end of options. You may optionally use this when filenames may start with two hyphens.
|
||||||
|
* $@ - Filenames to parse.
|
||||||
|
|
||||||
Mo uses the following environment variables:
|
Mo uses the following environment variables:
|
||||||
|
|
||||||
|
* 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_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_ORIGINAL_COMMAND - Used to find the `mo` program in order to generate a help message.
|
||||||
|
|
||||||
@ -30,6 +32,12 @@ files
|
|||||||
After we encounter two hyphens together, all the rest of the arguments are files.
|
After we encounter two hyphens together, all the rest of the arguments are files.
|
||||||
|
|
||||||
|
|
||||||
|
MO_FAIL_ON_UNSET
|
||||||
|
----------------
|
||||||
|
|
||||||
|
shellcheck disable=SC2030
|
||||||
|
|
||||||
|
|
||||||
MO_FALSE_IS_EMPTY
|
MO_FALSE_IS_EMPTY
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
@ -160,6 +168,8 @@ Internal: Determine if a given environment variable exists and if it is an array
|
|||||||
|
|
||||||
* $1 - Name of environment variable
|
* $1 - Name of environment variable
|
||||||
|
|
||||||
|
Be extremely careful. Even if strict mode is enabled, it is not honored in newer versions of Bash. Any errors that crop up here will not be caught automatically.
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
|
|
||||||
var=(abc)
|
var=(abc)
|
||||||
@ -178,6 +188,8 @@ Internal: Determine if the given name is a defined function.
|
|||||||
|
|
||||||
* $1 - Function name to check
|
* $1 - Function name to check
|
||||||
|
|
||||||
|
Be extremely careful. Even if strict mode is enabled, it is not honored in newer versions of Bash. Any errors that crop up here will not be caught automatically.
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
|
|
||||||
moo () {
|
moo () {
|
||||||
@ -263,11 +275,13 @@ moPartial()
|
|||||||
|
|
||||||
Internal: Process a partial.
|
Internal: Process a partial.
|
||||||
|
|
||||||
Indentation should be applied to the entire partial
|
Indentation should be applied to the entire partial.
|
||||||
|
|
||||||
|
This sends back the "is beginning" flag because the newline after a standalone partial is consumed. That newline is very important in the middle of content. We send back this flag to reset the processing loop's `moIsBeginning` variable, so the software thinks we are back at the beginning of a file and standalone processing continues to work.
|
||||||
|
|
||||||
Prefix all variables.
|
Prefix all variables.
|
||||||
|
|
||||||
* $1 - Name of destination "content" variable.
|
* $1 - Name of destination variable. Element [0] is the content, [1] is the true/false flag indicating if we are at the beginning of content.
|
||||||
* $2 - Content before the tag that was not yet written
|
* $2 - Content before the tag that was not yet written
|
||||||
* $3 - Tag content
|
* $3 - Tag content
|
||||||
* $4 - Content after the tag
|
* $4 - Content after the tag
|
||||||
@ -344,6 +358,16 @@ Do not use variables without prefixes here if possible as this needs to check if
|
|||||||
Returns 0 if the name is not empty, 1 otherwise. When MO_FALSE_IS_EMPTY is set, this returns 1 if the name is "false".
|
Returns 0 if the name is not empty, 1 otherwise. When MO_FALSE_IS_EMPTY is set, this returns 1 if the name is "false".
|
||||||
|
|
||||||
|
|
||||||
|
moTestVarSet()
|
||||||
|
--------------
|
||||||
|
|
||||||
|
Internal: Determine if a variable is assigned, even if it is assigned an empty value.
|
||||||
|
|
||||||
|
* $1 - Variable name to check.
|
||||||
|
|
||||||
|
Returns true (0) if the variable is set, 1 if the variable is unset.
|
||||||
|
|
||||||
|
|
||||||
moTrimChars()
|
moTrimChars()
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
45
mo
45
mo
@ -464,15 +464,20 @@ moIsStandalone() {
|
|||||||
char=$((${#beforeTrimmed} - 1))
|
char=$((${#beforeTrimmed} - 1))
|
||||||
char=${beforeTrimmed:$char}
|
char=${beforeTrimmed:$char}
|
||||||
|
|
||||||
|
# If the content before didn't end in a newline
|
||||||
if [[ "$char" != $'\n' ]] && [[ "$char" != $'\r' ]]; then
|
if [[ "$char" != $'\n' ]] && [[ "$char" != $'\r' ]]; then
|
||||||
|
# and there was content or this didn't start the file
|
||||||
if [[ -n "$char" ]] || ! $4; then
|
if [[ -n "$char" ]] || ! $4; then
|
||||||
|
# then this is not a standalone tag.
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
char=${afterTrimmed:0:1}
|
char=${afterTrimmed:0:1}
|
||||||
|
|
||||||
|
# If the content after doesn't start with a newline and it is something
|
||||||
if [[ "$char" != $'\n' ]] && [[ "$char" != $'\r' ]] && [[ -n "$char" ]]; then
|
if [[ "$char" != $'\n' ]] && [[ "$char" != $'\r' ]] && [[ -n "$char" ]]; then
|
||||||
|
# then this is not a standalone tag.
|
||||||
return 2
|
return 2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -518,7 +523,8 @@ moLoadFile() {
|
|||||||
|
|
||||||
# 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.
|
||||||
# TODO: remove cat and replace with read loop?
|
# As a future optimization, it would be worth considering removing
|
||||||
|
# cat and replacing this with a read loop.
|
||||||
|
|
||||||
content=$(cat -- "$2"; echo '.')
|
content=$(cat -- "$2"; echo '.')
|
||||||
len=$((${#content} - 1))
|
len=$((${#content} - 1))
|
||||||
@ -561,7 +567,7 @@ moLoop() {
|
|||||||
moParse() {
|
moParse() {
|
||||||
# Keep naming variables mo* here to not overwrite needed variables
|
# Keep naming variables mo* here to not overwrite needed variables
|
||||||
# used in the string replacements
|
# used in the string replacements
|
||||||
local moBlock moContent moCurrent moIsBeginning moTag
|
local moBlock moContent moCurrent moIsBeginning moNextIsBeginning moTag
|
||||||
|
|
||||||
moCurrent=$2
|
moCurrent=$2
|
||||||
moIsBeginning=$3
|
moIsBeginning=$3
|
||||||
@ -571,6 +577,7 @@ moParse() {
|
|||||||
|
|
||||||
while [[ "${#moContent[@]}" -gt 1 ]]; do
|
while [[ "${#moContent[@]}" -gt 1 ]]; do
|
||||||
moTrimWhitespace moTag "${moContent[1]}"
|
moTrimWhitespace moTag "${moContent[1]}"
|
||||||
|
moNextIsBeginning=false
|
||||||
|
|
||||||
case $moTag in
|
case $moTag in
|
||||||
'#'*)
|
'#'*)
|
||||||
@ -584,7 +591,7 @@ moParse() {
|
|||||||
if moTest "$moTag"; then
|
if moTest "$moTag"; then
|
||||||
# Show / loop / pass through function
|
# Show / loop / pass through function
|
||||||
if moIsFunction "$moTag"; then
|
if moIsFunction "$moTag"; then
|
||||||
#: TODO: Consider piping the output to moGetContent
|
#: Consider piping the output to moGetContent
|
||||||
#: so the lambda does not execute in a subshell?
|
#: so the lambda does not execute in a subshell?
|
||||||
moContent=$($moTag "${moBlock[0]}")
|
moContent=$($moTag "${moBlock[0]}")
|
||||||
moParse "$moContent" "$moCurrent" false
|
moParse "$moContent" "$moCurrent" false
|
||||||
@ -602,6 +609,8 @@ moParse() {
|
|||||||
'>'*)
|
'>'*)
|
||||||
# Load partial - get name of file relative to cwd
|
# Load partial - get name of file relative to cwd
|
||||||
moPartial moContent "${moContent[@]}" "$moIsBeginning" "$moCurrent"
|
moPartial moContent "${moContent[@]}" "$moIsBeginning" "$moCurrent"
|
||||||
|
moNextIsBeginning=${moContent[1]}
|
||||||
|
moContent=${moContent[0]}
|
||||||
;;
|
;;
|
||||||
|
|
||||||
'/'*)
|
'/'*)
|
||||||
@ -639,7 +648,7 @@ moParse() {
|
|||||||
'=')
|
'=')
|
||||||
# Change delimiters
|
# Change delimiters
|
||||||
# Any two non-whitespace sequences separated by whitespace.
|
# Any two non-whitespace sequences separated by whitespace.
|
||||||
# TODO
|
# This tag is ignored.
|
||||||
moStandaloneAllowed moContent "${moContent[@]}" "$moIsBeginning"
|
moStandaloneAllowed moContent "${moContent[@]}" "$moIsBeginning"
|
||||||
;;
|
;;
|
||||||
|
|
||||||
@ -672,7 +681,7 @@ moParse() {
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
moIsBeginning=false
|
moIsBeginning=$moNextIsBeginning
|
||||||
moSplit moContent "$moContent" '{{' '}}'
|
moSplit moContent "$moContent" '{{' '}}'
|
||||||
done
|
done
|
||||||
|
|
||||||
@ -682,11 +691,18 @@ moParse() {
|
|||||||
|
|
||||||
# Internal: Process a partial.
|
# Internal: Process a partial.
|
||||||
#
|
#
|
||||||
# Indentation should be applied to the entire partial
|
# Indentation should be applied to the entire partial.
|
||||||
|
#
|
||||||
|
# This sends back the "is beginning" flag because the newline after a
|
||||||
|
# standalone partial is consumed. That newline is very important in the middle
|
||||||
|
# of content. We send back this flag to reset the processing loop's
|
||||||
|
# `moIsBeginning` variable, so the software thinks we are back at the
|
||||||
|
# beginning of a file and standalone processing continues to work.
|
||||||
#
|
#
|
||||||
# Prefix all variables.
|
# Prefix all variables.
|
||||||
#
|
#
|
||||||
# $1 - Name of destination "content" variable.
|
# $1 - Name of destination variable. Element [0] is the content, [1] is the
|
||||||
|
# true/false flag indicating if we are at the beginning of content.
|
||||||
# $2 - Content before the tag that was not yet written
|
# $2 - Content before the tag that was not yet written
|
||||||
# $3 - Tag content
|
# $3 - Tag content
|
||||||
# $4 - Content after the tag
|
# $4 - Content after the tag
|
||||||
@ -696,24 +712,27 @@ moParse() {
|
|||||||
# Returns nothing.
|
# Returns nothing.
|
||||||
moPartial() {
|
moPartial() {
|
||||||
# Namespace variables here to prevent conflicts.
|
# Namespace variables here to prevent conflicts.
|
||||||
local moContent moFilename moIndent moPartial moStandalone moUnindented
|
local moContent moFilename moIndent moIsBeginning moPartial moStandalone moUnindented
|
||||||
|
|
||||||
if moIsStandalone moStandalone "$2" "$4" "$5"; then
|
if moIsStandalone moStandalone "$2" "$4" "$5"; then
|
||||||
moStandalone=( $moStandalone )
|
moStandalone=( $moStandalone )
|
||||||
echo -n "${2:0:${moStandalone[0]}}"
|
echo -n "${2:0:${moStandalone[0]}}"
|
||||||
moIndent=${2:${moStandalone[0]}}
|
moIndent=${2:${moStandalone[0]}}
|
||||||
moContent=${4:${moStandalone[1]}}
|
moContent=${4:${moStandalone[1]}}
|
||||||
|
moIsBeginning=true
|
||||||
else
|
else
|
||||||
moIndent=""
|
moIndent=""
|
||||||
echo -n "$2"
|
echo -n "$2"
|
||||||
moContent=$4
|
moContent=$4
|
||||||
|
moIsBeginning=$5
|
||||||
fi
|
fi
|
||||||
|
|
||||||
moTrimWhitespace moFilename "${3:1}"
|
moTrimWhitespace moFilename "${3:1}"
|
||||||
|
|
||||||
# Execute in subshell to preserve current cwd and environment
|
# Execute in subshell to preserve current cwd and environment
|
||||||
(
|
(
|
||||||
# TODO: Remove dirname and use a function instead
|
# It would be nice to remove `dirname` and use a function instead,
|
||||||
|
# but that's difficult when you're only given filenames.
|
||||||
cd "$(dirname -- "$moFilename")" || exit 1
|
cd "$(dirname -- "$moFilename")" || exit 1
|
||||||
moUnindented="$(
|
moUnindented="$(
|
||||||
moLoadFile moPartial "${moFilename##*/}"
|
moLoadFile moPartial "${moFilename##*/}"
|
||||||
@ -727,7 +746,13 @@ moPartial() {
|
|||||||
echo -n "$moPartial"
|
echo -n "$moPartial"
|
||||||
) || exit 1
|
) || exit 1
|
||||||
|
|
||||||
local "$1" && moIndirect "$1" "$moContent"
|
# If this is a standalone tag, the trailing newline after the tag is
|
||||||
|
# removed and the contents of the partial are added, which typically
|
||||||
|
# contain a newline. We need to send a signal back to the processing
|
||||||
|
# loop that the moIsBeginning flag needs to be turned on again.
|
||||||
|
#
|
||||||
|
# [0] is the content, [1] is that flag.
|
||||||
|
local "$1" && moIndirectArray "$1" "$moContent" "$moIsBeginning"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
0
tests/indented-partials.env
Normal file
0
tests/indented-partials.env
Normal file
19
tests/indented-partials.expected
Normal file
19
tests/indented-partials.expected
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
With spacing
|
||||||
|
first line
|
||||||
|
second line
|
||||||
|
|
||||||
|
first line
|
||||||
|
second line
|
||||||
|
|
||||||
|
Without spacing
|
||||||
|
first line
|
||||||
|
second line
|
||||||
|
first line
|
||||||
|
second line
|
||||||
|
|
||||||
|
With text
|
||||||
|
first line
|
||||||
|
second line
|
||||||
|
text
|
||||||
|
first line
|
||||||
|
second line
|
2
tests/indented-partials.partial
Normal file
2
tests/indented-partials.partial
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
first line
|
||||||
|
second line
|
13
tests/indented-partials.template
Normal file
13
tests/indented-partials.template
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
With spacing
|
||||||
|
{{> indented-partials.partial}}
|
||||||
|
|
||||||
|
{{> indented-partials.partial}}
|
||||||
|
|
||||||
|
Without spacing
|
||||||
|
{{> indented-partials.partial}}
|
||||||
|
{{> indented-partials.partial}}
|
||||||
|
|
||||||
|
With text
|
||||||
|
{{> indented-partials.partial}}
|
||||||
|
text
|
||||||
|
{{> indented-partials.partial}}
|
Loading…
Reference in New Issue
Block a user