Reformat comments into TomDoc format

This commit is contained in:
Tyler Akins 2015-10-02 09:46:57 -05:00
parent 3354bd7089
commit b5faf67737

416
mo
View File

@ -17,35 +17,64 @@
# https://github.com/tests-always-included/mo # https://github.com/tests-always-included/mo
# Scan content until the right end tag is found. Returns an array with the # Public: Template parser function. Writes templates to stdout.
# following members: #
# [0] = Content before end tag # $0 - Name of the mo file, used for getting the help message.
# [1] = End tag (complete tag) # $* - Filenames to parse. Can use -h or --help as the only option
# [2] = Content after end tag # in order to show a help message.
#
# Returns nothing.
mo() (
# This function executes in a subshell so IFS is reset
local MUSTACHE_CONTENT
IFS=$' \n\t'
if [[ $# -gt 0 ]]; then
case "$1" in
-h|--h|--he|--hel|--help)
moUsage "$0"
exit 0
;;
esac
fi
moGetContent MUSTACHE_CONTENT "$@"
moParse "$MUSTACHE_CONTENT" "" true
)
# Internal: Scan content until the right end tag is found. Creates an array
# with the following members:
#
# [0] = Content before end tag
# [1] = End tag (complete tag)
# [2] = Content after end tag
# #
# Everything using this function uses the "standalone tags" logic. # Everything using this function uses the "standalone tags" logic.
# #
# Parameters: # $1 - Name of variable for the array
# $1: Where to store the array # $2 - Content
# $2: Content # $3 - Name of end tag
# $3: Name of end tag # $4 - If -z, do standalone tag processing before finishing
# $4: If -z, do standalone tag processing before finishing #
# Returns nothing.
moFindEndTag() { moFindEndTag() {
local CONTENT SCANNED local CONTENT SCANNED
# Find open tags #: Find open tags
SCANNED="" SCANNED=""
moSplit CONTENT "$2" '{{' '}}' moSplit CONTENT "$2" '{{' '}}'
while [[ "${#CONTENT[@]}" -gt 1 ]]; do while [[ "${#CONTENT[@]}" -gt 1 ]]; do
moTrimWhitespace TAG "${CONTENT[1]}" moTrimWhitespace TAG "${CONTENT[1]}"
# Restore CONTENT[1] before we start using it #: Restore CONTENT[1] before we start using it
CONTENT[1]='{{'"${CONTENT[1]}"'}}' CONTENT[1]='{{'"${CONTENT[1]}"'}}'
case $TAG in case $TAG in
'#'* | '^'*) '#'* | '^'*)
# Start another block #: Start another block
SCANNED="${SCANNED}${CONTENT[0]}${CONTENT[1]}" SCANNED="${SCANNED}${CONTENT[0]}${CONTENT[1]}"
moTrimWhitespace TAG "${TAG:1}" moTrimWhitespace TAG "${TAG:1}"
moFindEndTag CONTENT "${CONTENT[2]}" "$TAG" "loop" moFindEndTag CONTENT "${CONTENT[2]}" "$TAG" "loop"
@ -54,15 +83,15 @@ moFindEndTag() {
;; ;;
'/'*) '/'*)
# End a block - could be ours #: End a block - could be ours
moTrimWhitespace TAG "${TAG:1}" moTrimWhitespace TAG "${TAG:1}"
SCANNED="$SCANNED${CONTENT[0]}" SCANNED="$SCANNED${CONTENT[0]}"
if [[ "$TAG" == "$3" ]]; then if [[ "$TAG" == "$3" ]]; then
# Found our end tag #: Found our end tag
if [[ -z "$4" ]] && moIsStandalone STANDALONE_BYTES "$SCANNED" "${CONTENT[2]}" true; then if [[ -z "$4" ]] && moIsStandalone STANDALONE_BYTES "$SCANNED" "${CONTENT[2]}" true; then
# This is also a standalone tag - clean up whitespace #: This is also a standalone tag - clean up whitespace
# and move those whitespace bytes to the "tag" element #: and move those whitespace bytes to the "tag" element
STANDALONE_BYTES=( $STANDALONE_BYTES ) STANDALONE_BYTES=( $STANDALONE_BYTES )
CONTENT[1]="${SCANNED:${STANDALONE_BYTES[0]}}${CONTENT[1]}${CONTENT[2]:0:${STANDALONE_BYTES[1]}}" CONTENT[1]="${SCANNED:${STANDALONE_BYTES[0]}}${CONTENT[1]}${CONTENT[2]:0:${STANDALONE_BYTES[1]}}"
SCANNED="${SCANNED:0:${STANDALONE_BYTES[0]}}" SCANNED="${SCANNED:0:${STANDALONE_BYTES[0]}}"
@ -78,7 +107,7 @@ moFindEndTag() {
;; ;;
*) *)
# Ignore all other tags #: Ignore all other tags
SCANNED="${SCANNED}${CONTENT[0]}${CONTENT[1]}" SCANNED="${SCANNED}${CONTENT[0]}${CONTENT[1]}"
CONTENT=${CONTENT[2]} CONTENT=${CONTENT[2]}
;; ;;
@ -87,18 +116,20 @@ moFindEndTag() {
moSplit CONTENT "$CONTENT" '{{' '}}' moSplit CONTENT "$CONTENT" '{{' '}}'
done done
# Did not find our closing tag #: Did not find our closing tag
SCANNED="$SCANNED${CONTENT[0]}" SCANNED="$SCANNED${CONTENT[0]}"
local "$1" && moIndirectArray "$1" "${SCANNED}" "" "" local "$1" && moIndirectArray "$1" "${SCANNED}" "" ""
} }
# Find the first index of a substring # Internal: Find the first index of a substring. If not found, sets the
# index to -1.
# #
# Parameters: # $1 - Destination variable for the index
# $1: Destination variable # $2 - Haystack
# $2: Haystack # $3 - Needle
# $3: Needle #
# Returns nothing.
moFindString() { moFindString() {
local POS STRING local POS STRING
@ -108,12 +139,13 @@ moFindString() {
} }
# Return a dotted name based on current context and target name # Internal: Generate a dotted name based on current context and target name.
# #
# Parameters: # $1 - Target variable to store results
# $1: Target variable to store results # $2 - Context name
# $2: Context name # $3 - Desired variable name
# $3: Desired variable name #
# Returns nothing.
moFullTagName() { moFullTagName() {
if [[ -z "$2" ]] || [[ "$2" == *.* ]]; then if [[ -z "$2" ]] || [[ "$2" == *.* ]]; then
local "$1" && moIndirect "$1" "$3" local "$1" && moIndirect "$1" "$3"
@ -123,12 +155,13 @@ moFullTagName() {
} }
# Return the content to parse. Can be a list of partials for files or # Internal: Fetches the content to parse into a variable. Can be a list of
# the content from stdin. # partials for files or the content from stdin.
# #
# Parameters: # $1 - Variable name to assign this content back as
# $1: Variable name to assign this content back as # $2-* - File names (optional)
# $2-*: File names (optional) #
# Returns nothing.
moGetContent() { moGetContent() {
local CONTENT FILENAME TARGET local CONTENT FILENAME TARGET
@ -138,7 +171,7 @@ moGetContent() {
CONTENT="" CONTENT=""
for FILENAME in "$@"; do for FILENAME in "$@"; do
# This is so relative paths work from inside template files #: This is so relative paths work from inside template files
CONTENT="$CONTENT"'{{>'"$FILENAME"'}}' CONTENT="$CONTENT"'{{>'"$FILENAME"'}}'
done done
else else
@ -149,19 +182,22 @@ moGetContent() {
} }
# Indent a string, placing the indent at the beginning of every # Internal: Indent a string, placing the indent at the beginning of every
# line that has any content. # line that has any content.
# #
# Parameters: # $1 - Name of destination variable to get an array of lines
# $1: Name of destination variable to get an array of lines # $2 - The indent string
# $2: The indent string # $3 - The string to reindent
# $3: The string to reindent #
# Returns nothing.
moIndentLines() { moIndentLines() {
local CONTENT FRAGMENT LEN POS_N POS_R RESULT TRIMMED local CONTENT FRAGMENT LEN POS_N POS_R RESULT TRIMMED
RESULT="" RESULT=""
LEN=$((${#3} - 1)) LEN=$((${#3} - 1))
CONTENT="${3:0:$LEN}" # Remove newline and dot from workaround - in moPartial
#: This removes newline and dot from the workaround in moPartial
CONTENT="${3:0:$LEN}"
if [ -z "$2" ]; then if [ -z "$2" ]; then
local "$1" && moIndirect "$1" "$CONTENT" local "$1" && moIndirect "$1" "$CONTENT"
@ -203,35 +239,61 @@ moIndentLines() {
} }
# Send a variable up to caller of a function # Internal: Send a variable up to the parent of the caller of this function.
# #
# Parameters: # $1 - Variable name
# $1: Variable name # $2 - Value
# $2: Value #
# Examples
#
# callFunc () {
# local "$1" && moIndirect "$1" "the value"
# }
# callFunc DEST
# echo "$DEST" # writes "the value"
#
# Returns nothing.
moIndirect() { moIndirect() {
unset -v "$1" unset -v "$1"
printf -v "$1" '%s' "$2" printf -v "$1" '%s' "$2"
} }
# Send an array up to caller of a function # Internal: Send an array as a variable up to caller of a function
# #
# Parameters: # $1 - Variable name
# $1: Variable name # $2-* - Array elements
# $2-*: Array elements #
# Examples
#
# callFunc () {
# local myArray=(one two three)
# local "$1" && moIndirectArray "$1" "${myArray[@]}"
# }
# callFunc DEST
# echo "${DEST[@]}" # writes "one two three"
#
# Returns nothing.
moIndirectArray() { moIndirectArray() {
unset -v "$1" unset -v "$1"
eval $1=\(\"\${@:2}\"\) eval $1=\(\"\${@:2}\"\)
} }
# Determine if a given environment variable exists and if it is an array. # Internal: Determine if a given environment variable exists and if it is
# an array.
# #
# Parameters: # $1 - Name of environment variable
# $1: Name of environment variable
# #
# Return code: # Examples
# 0 if the name is not empty, 1 otherwise #
# var=(abc)
# if moIsArray var; then
# echo "This is an array"
# echo "Make sure you don't accidentally use \$var"
# fi
#
# Returns 0 if the name is not empty, 1 otherwise.
moIsArray() { moIsArray() {
local MUSTACHE_TEST local MUSTACHE_TEST
@ -243,13 +305,20 @@ moIsArray() {
} }
# Return 0 if the passed name is a function. # Internal: Determine if the given name is a defined function.
# #
# Parameters: # $1 - Function name to check
# $1: Name to check if it's a function
# #
# Return code: # Examples
# 0 if the name is a function, 1 otherwise #
# moo () {
# echo "This is a function"
# }
# if moIsFunction moo; then
# echo "moo is a defined function"
# fi
#
# Returns 0 if the name is a function, 1 otherwise.
moIsFunction() { moIsFunction() {
local FUNCTIONS NAME local FUNCTIONS NAME
@ -266,23 +335,26 @@ moIsFunction() {
} }
# Determine if the tag is a standalone tag based on whitespace before and # Internal: Determine if the tag is a standalone tag based on whitespace
# after the tag. # before and after the tag.
# #
# Passes back a string containing two numbers in the format "BEFORE AFTER" # Passes back a string containing two numbers in the format "BEFORE AFTER"
# like "27 10". It indicates the number of bytes remaining in the "before" # like "27 10". It indicates the number of bytes remaining in the "before"
# string (27) and the number of bytes to trim in the "after" string (10). # string (27) and the number of bytes to trim in the "after" string (10).
# Useful for string manipulation: # Useful for string manipulation:
# #
# moIsStandalone RESULT "$before" "$after" false || return 0 # $1 - Variable to set for passing data back
# RESULT_ARRAY=( $RESULT ) # $2 - Content before the tag
# echo "${before:0:${RESULT_ARRAY[0]}}...${after:${RESULT_ARRAY[1]}}" # $3 - Content after the tag
# $4 - true/false: is this the beginning of the content?
# #
# Parameters: # Examples
# $1: Variable to pass data back #
# $2: Content before the tag # moIsStandalone RESULT "$before" "$after" false || return 0
# $3: Content after the tag # RESULT_ARRAY=( $RESULT )
# $4: true/false: is this the beginning of the content? # echo "${before:0:${RESULT_ARRAY[0]}}...${after:${RESULT_ARRAY[1]}}"
#
# Returns nothing.
moIsStandalone() { moIsStandalone() {
local AFTER_TRIMMED BEFORE_TRIMMED CHAR local AFTER_TRIMMED BEFORE_TRIMMED CHAR
@ -311,12 +383,13 @@ moIsStandalone() {
} }
# Join / implode an array # Internal: Join / implode an array
# #
# Parameters: # $1 - Variable name to receive the joined content
# $1: Variable name to receive the joined content # $2 - Joiner
# $2: Joiner # $3-$* - Elements to join
# $3-$*: Elements to join #
# Returns nothing.
moJoin() { moJoin() {
local JOINER PART RESULT TARGET local JOINER PART RESULT TARGET
@ -332,17 +405,19 @@ moJoin() {
local "$TARGET" && moIndirect "$TARGET" "$RESULT" local "$TARGET" && moIndirect "$TARGET" "$RESULT"
} }
# Read a file # Internal: Read a file into a variable.
# #
# Parameters: # $1 - Variable name to receive the file's content
# $1: Variable name to receive the file's content # $2 - Filename to load
# $2: Filename to load #
# Returns nothing.
moLoadFile() { moLoadFile() {
local CONTENT LEN local CONTENT LEN
# 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? # TODO: remove cat and replace with read loop?
CONTENT=$(cat $2; echo '.') CONTENT=$(cat $2; echo '.')
LEN=$((${#CONTENT} - 1)) LEN=$((${#CONTENT} - 1))
CONTENT=${CONTENT:0:$LEN} # Remove last dot CONTENT=${CONTENT:0:$LEN} # Remove last dot
@ -351,12 +426,14 @@ moLoadFile() {
} }
# Process a chunk of content some number of times. # Internal: Process a chunk of content some number of times. Writes output
# to stdout.
# #
# Parameters: # $1 - Content to parse repeatedly
# $1: Content to parse and reparse and reparse # $2 - Tag prefix (context name)
# $2: Tag prefix (context name) # $3-* - Names to insert into the parsed content
# $3-*: Names to insert into the parsed content #
# Returns nothing.
moLoop() { moLoop() {
local CONTENT CONTEXT CONTEXT_BASE IGNORE local CONTENT CONTEXT CONTEXT_BASE IGNORE
@ -372,12 +449,13 @@ moLoop() {
} }
# Parse a block of text # Internal: Parse a block of text, writing the result to stdout.
# #
# Parameters: # $1 - Block of text to change
# $1: Block of text to change # $2 - Current name (the variable NAME for what {{.}} means)
# $2: Current name (the variable NAME for what {{.}} means) # $3 - true when no content before this, false otherwise
# $3: true when no content before this, false otherwise #
# Returns nothing.
moParse() { moParse() {
# Keep naming variables MUSTACHE_* here to not overwrite needed variables # Keep naming variables MUSTACHE_* here to not overwrite needed variables
# used in the string replacements # used in the string replacements
@ -404,9 +482,8 @@ moParse() {
if moTest "$MUSTACHE_TAG"; then if moTest "$MUSTACHE_TAG"; then
# Show / loop / pass through function # Show / loop / pass through function
if moIsFunction "$MUSTACHE_TAG"; then if moIsFunction "$MUSTACHE_TAG"; then
# TODO: Consider piping the output to #: TODO: Consider piping the output to moGetContent
# moGetContent so the lambda does not #: so the lambda does not execute in a subshell?
# execute in a subshell?
MUSTACHE_CONTENT=$($MUSTACHE_TAG "${MUSTACHE_BLOCK[0]}") MUSTACHE_CONTENT=$($MUSTACHE_TAG "${MUSTACHE_BLOCK[0]}")
moParse "$MUSTACHE_CONTENT" "$MUSTACHE_CURRENT" false moParse "$MUSTACHE_CONTENT" "$MUSTACHE_CURRENT" false
MUSTACHE_CONTENT="${MUSTACHE_BLOCK[2]}" MUSTACHE_CONTENT="${MUSTACHE_BLOCK[2]}"
@ -501,19 +578,20 @@ moParse() {
} }
# Process a partial # Internal: Process a partial.
# #
# Indentation should be applied to the entire partial # Indentation should be applied to the entire partial
# #
# Prefix all variables # Prefix all variables.
# #
# Parameters: # $1 - Name of destination "content" variable.
# $1: Name of destination "content" variable. # $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 # $5 - true/false: is this the beginning of the content?
# $5: true/false: is this the beginning of the content? # $6 - Current context name
# $6: Current context name #
# Returns nothing.
moPartial() { moPartial() {
local MUSTACHE_CONTENT MUSTACHE_FILENAME MUSTACHE_INDENT MUSTACHE_LINE MUSTACHE_PARTIAL MUSTACHE_STANDALONE local MUSTACHE_CONTENT MUSTACHE_FILENAME MUSTACHE_INDENT MUSTACHE_LINE MUSTACHE_PARTIAL MUSTACHE_STANDALONE
@ -548,13 +626,15 @@ moPartial() {
} }
# Show an environment variable or the output of a function. # Internal: Show an environment variable or the output of a function to
# stdout.
# #
# Limit/prefix any variables used # Limit/prefix any variables used.
# #
# Parameters: # $1 - Name of environment variable or function
# $1: Name of environment variable or function # $2 - Current context
# $2: Current context #
# Returns nothing.
moShow() { moShow() {
local JOINED MUSTACHE_NAME_PARTS local JOINED MUSTACHE_NAME_PARTS
@ -580,13 +660,14 @@ moShow() {
} }
# Split a larger string into an array # Internal: Split a larger string into an array.
# #
# Parameters: # $1 - Destination variable
# $1: Destination variable # $2 - String to split
# $2: String to split # $3 - Starting delimiter
# $3: Starting delimiter # $4 - Ending delimiter (optional)
# $4: Ending delimiter (optional) #
# Returns nothing.
moSplit() { moSplit() {
local POS RESULT local POS RESULT
@ -613,16 +694,17 @@ moSplit() {
} }
# Handle the content for a standalone tag. This means removing whitespace # Internal: Handle the content for a standalone tag. This means removing
# (not newlines) before a tag and whitespace and a newline after a tag. # whitespace (not newlines) before a tag and whitespace and a newline after
# That is, assuming, that the line is otherwise empty. # a tag. That is, assuming, that the line is otherwise empty.
# #
# Parameters: # $1 - Name of destination "content" variable.
# $1: Name of destination "content" variable. # $2 - Content before the tag that was not yet written
# $2: Content before the tag that was not yet written # $3 - Tag content (not used)
# $3: Tag content (not used) # $4 - Content after the tag
# $4: Content after the tag # $5 - true/false: is this the beginning of the content?
# $5: true/false: is this the beginning of the content? #
# Returns nothing.
moStandaloneAllowed() { moStandaloneAllowed() {
local STANDALONE_BYTES local STANDALONE_BYTES
@ -637,32 +719,31 @@ moStandaloneAllowed() {
} }
# Handle the content for a tag that is never "standalone". No adjustments # Internal: Handle the content for a tag that is never "standalone". No
# are made for newlines and whitespace. # adjustments are made for newlines and whitespace.
# #
# Parameters: # $1 - Name of destination "content" variable.
# $1: Name of destination "content" variable. # $2 - Content before the tag that was not yet written
# $2: Content before the tag that was not yet written # $3 - Tag content (not used)
# $3: Tag content (not used) # $4 - Content after the tag
# $4: Content after the tag #
# Returns nothing.
moStandaloneDenied() { moStandaloneDenied() {
echo -n "$2" echo -n "$2"
local "$1" && moIndirect "$1" "$4" local "$1" && moIndirect "$1" "$4"
} }
# Returns 0 (success) if the named thing is a function or if it is a non-empty # Internal: Determines if the named thing is a function or if it is a
# environment variable. # non-empty environment variable.
# #
# Do not use unprefixed variables here if possible as this needs to check # Do not use variables without prefixes here if possible as this needs to
# if any name exists in the environment # check if any name exists in the environment
# #
# Parameters: # $1 - Name of environment variable or function
# $1: Name of environment variable or function # $2 - Current value (our context)
# $2: Current value (our context)
# #
# Return code: # Returns 0 if the name is not empty, 1 otherwise.
# 0 if the name is not empty, 1 otherwise
moTest() { moTest() {
# Test for functions # Test for functions
moIsFunction "$1" && return 0 moIsFunction "$1" && return 0
@ -679,14 +760,15 @@ moTest() {
} }
# Trim the leading whitespace only # Internal: Trim the leading whitespace only.
# #
# Parameters: # $1 - Name of destination variable
# $1: Name of destination variable # $2 - The string
# $2: The string # $3 - true/false - trim front?
# $3: true/false - trim front? # $4 - true/false - trim end?
# $4: true/false - trim end? # $5-* - Characters to trim
# $5-*: Characters to trim #
# Returns nothing.
moTrimChars() { moTrimChars() {
local BACK CURRENT FRONT LAST TARGET VAR local BACK CURRENT FRONT LAST TARGET VAR
@ -695,10 +777,7 @@ moTrimChars() {
FRONT=$3 FRONT=$3
BACK=$4 BACK=$4
LAST="" LAST=""
shift # Remove target shift 4 # Remove target, string, trim front flag, trim end flag
shift # Remove string
shift # Remove trim front flag
shift # Remove trim end flag
while [[ "$CURRENT" != "$LAST" ]]; do while [[ "$CURRENT" != "$LAST" ]]; do
LAST=$CURRENT LAST=$CURRENT
@ -713,11 +792,12 @@ moTrimChars() {
} }
# Trim leading and trailing whitespace from a string # Internal: Trim leading and trailing whitespace from a string.
# #
# Parameters: # $1 - Name of variable to store trimmed string
# $1: Name of variable to store trimmed string # $2 - The string
# $2: The string #
# Returns nothing.
moTrimWhitespace() { moTrimWhitespace() {
local RESULT local RESULT
@ -726,41 +806,21 @@ moTrimWhitespace() {
} }
# Displays the usage for mo. Pulls this from the file that contained # Internal: Displays the usage for mo. Pulls this from the file that
# the `mo` function. Likely will only work when # contained the `mo` function. Can only work when the right filename
# comes is the one argument, and that only happens when `mo` is called
# with `$0` set to this file.
# #
# $1 - Filename that has the help message # $1 - Filename that has the help message
# #
# Returns nothing. # Returns nothing.
moUsage() { moUsage() {
grep '^#/' < "$0" | cut -c 4- grep '^#/' < "$1" | cut -c 4-
} }
# Template parser # If sourced, load all functions.
# # If executed, perform the actions as expected.
# $* - Filenames to parse. Can use -h or --help as the only option
# in order to show a help message.
#
# Returns nothing.
mo() (
# Execute in a subshell so IFS is reset
IFS=$' \n\t'
if [[ $# -gt 0 ]]; then
case "$1" in
-h|--h|--he|--hel|--help)
moUsage "$0"
exit 0
;;
esac
fi
moGetContent MUSTACHE_CONTENT "$@"
moParse "$MUSTACHE_CONTENT" "" true
)
if [[ "$0" == "$BASH_SOURCE" ]] || ! [[ -n "$BASH_SOURCE" ]]; then if [[ "$0" == "$BASH_SOURCE" ]] || ! [[ -n "$BASH_SOURCE" ]]; then
mo "$@" mo "$@"
fi fi