mirror of
https://github.com/tests-always-included/mo.git
synced 2024-12-18 16:27:52 +00:00
parent
e6787e71d5
commit
6376a9b817
28
API.md
28
API.md
@ -10,6 +10,7 @@ mo()
|
||||
Public: Template parser function. Writes templates to stdout.
|
||||
|
||||
* $0 - Name of the mo file, used for getting the help message.
|
||||
* --fail-not-set - Fail upon expansion of an unset variable. Default behavior is to silently ignore and expand into empty string.
|
||||
* --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.
|
||||
* --help - Display a help message.
|
||||
* --source=FILE - Source a file into the environment before processint template files.
|
||||
@ -18,6 +19,7 @@ Public: Template parser function. Writes templates to stdout.
|
||||
|
||||
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_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.
|
||||
|
||||
|
||||
MO_FAIL_ON_UNSET
|
||||
----------------
|
||||
|
||||
shellcheck disable=SC2030
|
||||
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
var=(abc)
|
||||
@ -178,6 +188,8 @@ Internal: Determine if the given name is a defined function.
|
||||
|
||||
* $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
|
||||
|
||||
moo () {
|
||||
@ -263,11 +275,13 @@ moPartial()
|
||||
|
||||
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.
|
||||
|
||||
* $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
|
||||
* $3 - Tag content
|
||||
* $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".
|
||||
|
||||
|
||||
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()
|
||||
-------------
|
||||
|
||||
|
45
mo
45
mo
@ -464,15 +464,20 @@ moIsStandalone() {
|
||||
char=$((${#beforeTrimmed} - 1))
|
||||
char=${beforeTrimmed:$char}
|
||||
|
||||
# If the content before didn't end in a newline
|
||||
if [[ "$char" != $'\n' ]] && [[ "$char" != $'\r' ]]; then
|
||||
# and there was content or this didn't start the file
|
||||
if [[ -n "$char" ]] || ! $4; then
|
||||
# then this is not a standalone tag.
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
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
|
||||
# then this is not a standalone tag.
|
||||
return 2
|
||||
fi
|
||||
|
||||
@ -518,7 +523,8 @@ moLoadFile() {
|
||||
|
||||
# The subshell removes any trailing newlines. We forcibly add
|
||||
# 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 '.')
|
||||
len=$((${#content} - 1))
|
||||
@ -561,7 +567,7 @@ moLoop() {
|
||||
moParse() {
|
||||
# Keep naming variables mo* here to not overwrite needed variables
|
||||
# used in the string replacements
|
||||
local moBlock moContent moCurrent moIsBeginning moTag
|
||||
local moBlock moContent moCurrent moIsBeginning moNextIsBeginning moTag
|
||||
|
||||
moCurrent=$2
|
||||
moIsBeginning=$3
|
||||
@ -571,6 +577,7 @@ moParse() {
|
||||
|
||||
while [[ "${#moContent[@]}" -gt 1 ]]; do
|
||||
moTrimWhitespace moTag "${moContent[1]}"
|
||||
moNextIsBeginning=false
|
||||
|
||||
case $moTag in
|
||||
'#'*)
|
||||
@ -584,7 +591,7 @@ moParse() {
|
||||
if moTest "$moTag"; then
|
||||
# Show / loop / pass through function
|
||||
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?
|
||||
moContent=$($moTag "${moBlock[0]}")
|
||||
moParse "$moContent" "$moCurrent" false
|
||||
@ -602,6 +609,8 @@ moParse() {
|
||||
'>'*)
|
||||
# Load partial - get name of file relative to cwd
|
||||
moPartial moContent "${moContent[@]}" "$moIsBeginning" "$moCurrent"
|
||||
moNextIsBeginning=${moContent[1]}
|
||||
moContent=${moContent[0]}
|
||||
;;
|
||||
|
||||
'/'*)
|
||||
@ -639,7 +648,7 @@ moParse() {
|
||||
'=')
|
||||
# Change delimiters
|
||||
# Any two non-whitespace sequences separated by whitespace.
|
||||
# TODO
|
||||
# This tag is ignored.
|
||||
moStandaloneAllowed moContent "${moContent[@]}" "$moIsBeginning"
|
||||
;;
|
||||
|
||||
@ -672,7 +681,7 @@ moParse() {
|
||||
;;
|
||||
esac
|
||||
|
||||
moIsBeginning=false
|
||||
moIsBeginning=$moNextIsBeginning
|
||||
moSplit moContent "$moContent" '{{' '}}'
|
||||
done
|
||||
|
||||
@ -682,11 +691,18 @@ moParse() {
|
||||
|
||||
# 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.
|
||||
#
|
||||
# $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
|
||||
# $3 - Tag content
|
||||
# $4 - Content after the tag
|
||||
@ -696,24 +712,27 @@ moParse() {
|
||||
# Returns nothing.
|
||||
moPartial() {
|
||||
# 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
|
||||
moStandalone=( $moStandalone )
|
||||
echo -n "${2:0:${moStandalone[0]}}"
|
||||
moIndent=${2:${moStandalone[0]}}
|
||||
moContent=${4:${moStandalone[1]}}
|
||||
moIsBeginning=true
|
||||
else
|
||||
moIndent=""
|
||||
echo -n "$2"
|
||||
moContent=$4
|
||||
moIsBeginning=$5
|
||||
fi
|
||||
|
||||
moTrimWhitespace moFilename "${3:1}"
|
||||
|
||||
# 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
|
||||
moUnindented="$(
|
||||
moLoadFile moPartial "${moFilename##*/}"
|
||||
@ -727,7 +746,13 @@ moPartial() {
|
||||
echo -n "$moPartial"
|
||||
) || 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