8 Commits
1.0.0 ... 2.0.2

Author SHA1 Message Date
Tyler Akins
4f615a0faf More fixes if variables are not set and strict mode is enabled 2017-11-13 10:43:32 -06:00
Tyler Akins
1e91e414cc Fix for when running in strict mode 2017-11-13 10:31:51 -06:00
Tyler Akins
ad98577c42 Changing how functions are called
Old way:

    functionName CONTENT argument1 argument2

New way:

    echo -n "$CONTENT" | functionName argument1 argument2

This follow the Unix style more closely.
2017-11-13 10:13:56 -06:00
Tyler Akins
e78b15d95b Updating test to enable the flag 2017-11-03 19:38:34 -05:00
Tyler Akins
f20e4ae83a Making a bit more safe and disabling an eval by default 2017-11-03 16:45:51 -05:00
Tyler Akins
a5ec7dd740 I think this finally implements arguments to functions
This closes #18.
2017-11-03 16:34:08 -05:00
Tyler Akins
ab5dfee519 Fixing install directions 2017-10-24 07:47:50 -05:00
Tyler Akins
81fd601ebd Shortening URL 2017-10-23 15:11:23 -05:00
9 changed files with 106 additions and 19 deletions

View File

@@ -41,7 +41,7 @@ There are a few ways you can install this tool. How you install it depends on h
You can install this file in `/usr/local/bin/` or `/usr/bin/` by simply downloading it, changing the permissions, then moving it to the right location. Double check that your system's PATH includes the destination folder, otherwise users may have a hard time starting the command. You can install this file in `/usr/local/bin/` or `/usr/bin/` by simply downloading it, changing the permissions, then moving it to the right location. Double check that your system's PATH includes the destination folder, otherwise users may have a hard time starting the command.
# Download # Download
curl -sSO https://raw.githubusercontent.com/tests-always-included/mo/master/mo curl -sS https://git.io/get-mo -o mo
# Make executable # Make executable
chmod +x mo chmod +x mo
@@ -58,7 +58,7 @@ You can install this file in `/usr/local/bin/` or `/usr/bin/` by simply download
This is very similar to installing it globally but it does not require root privileges. It is very important that your PATH includes the destination folder otherwise it won't work. Some local folders that are typically used are `~/bin/` and `~/.local/bin/`. This is very similar to installing it globally but it does not require root privileges. It is very important that your PATH includes the destination folder otherwise it won't work. Some local folders that are typically used are `~/bin/` and `~/.local/bin/`.
# Download # Download
curl -sSO https://raw.githubusercontent.com/tests-always-included/mo/master/mo curl -sS https://git.io/get-mo -o mo
# Make executable # Make executable
chmod +x mo chmod +x mo
@@ -78,7 +78,7 @@ This is very similar to installing it globally but it does not require root priv
Bash scripts can source `mo` to include the functionality in their own routines. This usage typically would have `mo` saved to a `lib/` folder in an application and your other scripts would use `. lib/mo` to bring it into your project. Bash scripts can source `mo` to include the functionality in their own routines. This usage typically would have `mo` saved to a `lib/` folder in an application and your other scripts would use `. lib/mo` to bring it into your project.
# Download # Download
curl -sSO https://raw.githubusercontent.com/tests-always-included/mo/master/mo curl -sS https://git.io/get-mo -o mo
# Move into your project folder # Move into your project folder
mv mo ~/projects/amazing-things/lib/ mv mo ~/projects/amazing-things/lib/
@@ -115,6 +115,8 @@ The result? You get a list of the five elements in the array. It is vital that
There are more scripts available in the [demos directory](demo/) that could help illustrate how you would use this program. There are more scripts available in the [demos directory](demo/) that could help illustrate how you would use this program.
There are additional features that the program supports. Try using `mo --help` to see what is available.
Concessions Concessions
----------- -----------

View File

@@ -3,6 +3,9 @@
cd "$(dirname "$0")" # Go to the script's directory cd "$(dirname "$0")" # Go to the script's directory
EVERY_REPO() { EVERY_REPO() {
# The block contents come in through standard input. Capture it here.
content=$(cat)
echo "# Starting EVERY_REPO" echo "# Starting EVERY_REPO"
# Get list of repos # Get list of repos
@@ -14,7 +17,7 @@ EVERY_REPO() {
# It rewrites {{__REPO__.name}} into {{resque.name}}, for instance. # It rewrites {{__REPO__.name}} into {{resque.name}}, for instance.
# You can prefix your environment variables and do other things as well. # You can prefix your environment variables and do other things as well.
echo -n "$1" | sed "s/__REPO__/${REPO}/" echo "$content" | sed "s/__REPO__/${REPO}/"
echo "## Looped one time for repo: $REPO" echo "## Looped one time for repo: $REPO"
done done

View File

@@ -2,13 +2,17 @@
cd "$(dirname "$0")"/.. cd "$(dirname "$0")"/..
date-string() { date; } date-string() {
wrapper() { echo -n "*** $1 ***"; } date
}
wrapper() {
echo -n "*** $(cat) ***"
}
export IP=127.0.0.1 export IP=127.0.0.1
export ALLOWED_HOSTS=( 192.168.0.1 192.168.0.2 192.168.0.3 ) export ALLOWED_HOSTS=( 192.168.0.1 192.168.0.2 192.168.0.3 )
. mo # Keep in mind this script is executing in the parent directory . ./mo # Keep in mind this script is executing in the parent directory
cat <<EOF | mo cat <<EOF | mo
# {{#wrapper}}OH SO IMPORTANT{{/wrapper}} # {{#wrapper}}OH SO IMPORTANT{{/wrapper}}
# This file automatically generated at {{date-string}} # This file automatically generated at {{date-string}}

74
mo
View File

@@ -29,6 +29,10 @@
# 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.
# --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.
# --fail-not-set - Fail upon expansion of an unset variable. Default behavior # --fail-not-set - Fail upon expansion of an unset variable. Default behavior
# is to silently ignore and expand into empty string. # is to silently ignore and expand into empty string.
# --false - Treat "false" as an empty value. You may set the # --false - Treat "false" as an empty value. You may set the
@@ -43,6 +47,12 @@
# #
# Mo uses the following environment variables: # 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_FAIL_ON_UNSET - When set to a non-empty value, expansion of an unset # MO_FAIL_ON_UNSET - When set to a non-empty value, expansion of an unset
# env variable will be aborted with an error. # env variable will be aborted with an error.
# MO_FALSE_IS_EMPTY - When set to a non-empty value, the string "false" # MO_FALSE_IS_EMPTY - When set to a non-empty value, the string "false"
@@ -74,6 +84,11 @@ mo() (
exit 0 exit 0
;; ;;
--allow-function-arguments)
# shellcheck disable=SC2030
MO_ALLOW_FUNCTION_ARGUMENTS=true
;;
--fail-not-set) --fail-not-set)
# shellcheck disable=SC2030 # shellcheck disable=SC2030
MO_FAIL_ON_UNSET=true MO_FAIL_ON_UNSET=true
@@ -115,6 +130,30 @@ mo() (
) )
# Internal: Call a function.
#
# $1 - Function to call
# $2 - Content to pass
# $3 - Additional arguments as a single string
#
# This can be dangerous, especially if you are using tags like
# {{someFunction ; rm -rf / }}
#
# Returns nothing.
moCallFunction() {
local moArgs
moArgs=()
# shellcheck disable=SC2031
if [[ -n "$MO_ALLOW_FUNCTION_ARGUMENTS" ]]; then
moArgs=$3
fi
echo -n "$2" | eval "$1" "$moArgs"
}
# Internal: Scan content until the right end tag is found. Creates an array # Internal: Scan content until the right end tag is found. Creates an array
# with the following members: # with the following members:
# #
@@ -567,7 +606,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 moNextIsBeginning moTag local moArgs moBlock moContent moCurrent moIsBeginning moNextIsBeginning moTag
moCurrent=$2 moCurrent=$2
moIsBeginning=$3 moIsBeginning=$3
@@ -585,6 +624,13 @@ moParse() {
# Sets context # Sets context
moStandaloneAllowed moContent "${moContent[@]}" "$moIsBeginning" moStandaloneAllowed moContent "${moContent[@]}" "$moIsBeginning"
moTrimWhitespace moTag "${moTag:1}" moTrimWhitespace moTag "${moTag:1}"
# Split arguments from the tag name. Arguments are passed to
# functions.
moArgs=$moTag
moTag=${moTag%% *}
moTag=${moTag%%$'\t'*}
moArgs=${moArgs:${#moTag}}
moFindEndTag moBlock "$moContent" "$moTag" moFindEndTag moBlock "$moContent" "$moTag"
moFullTagName moTag "$moCurrent" "$moTag" moFullTagName moTag "$moCurrent" "$moTag"
@@ -593,7 +639,7 @@ moParse() {
if moIsFunction "$moTag"; then if moIsFunction "$moTag"; then
#: 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=$(moCallFunction "$moTag" "${moBlock[0]}" "$moArgs")
moParse "$moContent" "$moCurrent" false moParse "$moContent" "$moCurrent" false
moContent="${moBlock[2]}" moContent="${moBlock[2]}"
elif moIsArray "$moTag"; then elif moIsArray "$moTag"; then
@@ -658,11 +704,16 @@ moParse() {
moContent="${moTag:1}"'}}'"$moContent" moContent="${moTag:1}"'}}'"$moContent"
moSplit moContent "$moContent" '}}}' moSplit moContent "$moContent" '}}}'
moTrimWhitespace moTag "${moContent[0]}" moTrimWhitespace moTag "${moContent[0]}"
moArgs=$moTag
moTag=${moTag%% *}
moTag=${moTag%%$'\t'*}
moArgs=${moArgs:${#moTag}}
moFullTagName moTag "$moCurrent" "$moTag" moFullTagName moTag "$moCurrent" "$moTag"
moContent=${moContent[1]} moContent=${moContent[1]}
# Now show the value # Now show the value
moShow "$moTag" "$moCurrent" # Quote moArgs here, do not quote it later.
moShow "$moTag" "$moCurrent" "$moArgs"
;; ;;
'&'*) '&'*)
@@ -676,8 +727,14 @@ moParse() {
*) *)
# Normal environment variable or function call # Normal environment variable or function call
moStandaloneDenied moContent "${moContent[@]}" moStandaloneDenied moContent "${moContent[@]}"
moArgs=$moTag
moTag=${moTag%% *}
moTag=${moTag%%$'\t'*}
moArgs=${moArgs:${#moTag}}
moFullTagName moTag "$moCurrent" "$moTag" moFullTagName moTag "$moCurrent" "$moTag"
moShow "$moTag" "$moCurrent"
# Quote moArgs here, do not quote it later.
moShow "$moTag" "$moCurrent" "$moArgs"
;; ;;
esac esac
@@ -763,6 +820,7 @@ moPartial() {
# #
# $1 - Name of environment variable or function # $1 - Name of environment variable or function
# $2 - Current context # $2 - Current context
# $3 - Arguments string if $1 is a function
# #
# Returns nothing. # Returns nothing.
moShow() { moShow() {
@@ -770,22 +828,22 @@ moShow() {
local moJoined moNameParts local moJoined moNameParts
if moIsFunction "$1"; then if moIsFunction "$1"; then
CONTENT=$($1 "") CONTENT=$(moCallFunction "$1" "" "$3")
moParse "$CONTENT" "$2" false moParse "$CONTENT" "$2" false
return 0 return 0
fi fi
moSplit moNameParts "$1" "." moSplit moNameParts "$1" "."
if [[ -z "${moNameParts[1]}" ]]; then if [[ -z "${moNameParts[1]-}" ]]; then
if moIsArray "$1"; then if moIsArray "$1"; then
eval moJoin moJoined "," "\${$1[@]}" eval moJoin moJoined "," "\${$1[@]}"
echo -n "$moJoined" echo -n "$moJoined"
else else
# shellcheck disable=SC2031 # shellcheck disable=SC2031
if [[ -z "$MO_FAIL_ON_UNSET" ]] || moTestVarSet "$1"; then if moTestVarSet "$1"; then
echo -n "${!1}" echo -n "${!1}"
else elif [[ -n "${MO_FAIL_ON_UNSET-}" ]]; then
echo "Env variable not set: $1" >&2 echo "Env variable not set: $1" >&2
exit 1 exit 1
fi fi

13
tests/function-args.env Normal file
View File

@@ -0,0 +1,13 @@
name=Willy
MO_ALLOW_FUNCTION_ARGUMENTS=true
pipeTo() {
cat | "$1"
}
testArgs() {
printf "%d" "$#"
# Display all arguments
printf " %q" ${@+"$@"}
}

View File

@@ -0,0 +1,4 @@
No args: 0 '' - done
One arg: 1 one - done
Getting name in a string: 1 The\ name\ is\ Willy - done
Reverse this: edcba

View File

@@ -0,0 +1,4 @@
No args: {{testArgs}} - done
One arg: {{testArgs one}} - done
Getting name in a string: {{testArgs "The name is $name"}} - done
Reverse this: {{#pipeTo rev}}abcde{{/pipeTo}}

View File

@@ -1,5 +1,5 @@
name=Willy name=Willy
wrapped() { wrapped() {
# The final newline is eaten by mo # This eats the newline in the content
echo "<b>$1</b>" echo "<b>$(cat)</b>"
} }

View File

@@ -1,2 +1 @@
<b> Willy is awesome. <b> Willy is awesome.</b>... this is the last line.
</b>... this is the last line.