mirror of
https://github.com/tests-always-included/mo.git
synced 2026-04-08 08:50:38 +02:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
929ffc5b88 | ||
|
|
5b8cf24068 | ||
|
|
fcedd32155 | ||
|
|
9f6d3bcdab | ||
|
|
eac2685632 | ||
|
|
505570a57b | ||
|
|
aabc62f1d6 | ||
|
|
e672bda163 |
@@ -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 -sS https://git.io/get-mo -o mo
|
curl -sSL 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 -sS https://git.io/get-mo -o mo
|
curl -sSL 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/
|
||||||
|
|||||||
29
demo/function-args
Executable file
29
demo/function-args
Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# This sources a simple script with the env. variables needed for the template.
|
||||||
|
|
||||||
|
cd "$(dirname "$0")" # Go to the script's directory
|
||||||
|
source ../mo
|
||||||
|
|
||||||
|
export NAME="Alex"
|
||||||
|
export ARRAY=( AAA BBB CCC )
|
||||||
|
|
||||||
|
# Include an external template
|
||||||
|
INCLUDE() {
|
||||||
|
cat "$MO_FUNCTION_ARGS"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Print section title
|
||||||
|
TITLE() {
|
||||||
|
echo "+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+"
|
||||||
|
echo "$MO_FUNCTION_ARGS"
|
||||||
|
echo "+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+"
|
||||||
|
}
|
||||||
|
|
||||||
|
cat <<EOF | mo -u
|
||||||
|
{{TITLE Part 1}}
|
||||||
|
{{INCLUDE function-args-part1}}
|
||||||
|
|
||||||
|
{{TITLE Part 2}}
|
||||||
|
{{INCLUDE function-args-part2}}
|
||||||
|
EOF
|
||||||
1
demo/function-args-part1
Normal file
1
demo/function-args-part1
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Hello, my name is {{NAME}}.
|
||||||
3
demo/function-args-part2
Normal file
3
demo/function-args-part2
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{{#ARRAY}}
|
||||||
|
* {{.}}
|
||||||
|
{{/ARRAY}}
|
||||||
39
demo/function-for-building-json
Executable file
39
demo/function-for-building-json
Executable file
@@ -0,0 +1,39 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
cd "$(dirname "$0")" # Go to the script's directory
|
||||||
|
|
||||||
|
# Detect if this is the first item and write a comma if it is.
|
||||||
|
# Normally, I would track this using a variable, like so:
|
||||||
|
#
|
||||||
|
# COMMA_IF_NOT_FIRST_FLAG=false
|
||||||
|
# COMMA_IF_NOT_FIRST() {
|
||||||
|
# $COMMA_IF_NOT_FIRST || echo ","
|
||||||
|
# COMMA_IF_NOT_FIRST_FLAG=true
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# Since this function executes in a subshell, that approach will not work.
|
||||||
|
# Instead, we peek inside mo and see what is being processed. If the variable
|
||||||
|
# name in moParse() changes, this will need to get updated as well. An
|
||||||
|
# alternate variable that is usable is context, but that is in moLoop() and is
|
||||||
|
# two levels levels deep instead of just one.
|
||||||
|
COMMA_IF_NOT_FIRST() {
|
||||||
|
[[ "${moCurrent#*.}" != "0" ]] && echo ","
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create an array that will be embedded into the JSON. If you are manipulating
|
||||||
|
# JSON, might I suggest you look at using jq? It's really good at processing
|
||||||
|
# JSON.
|
||||||
|
items=(
|
||||||
|
'{"position":"one","url":"1"}'
|
||||||
|
'{"position":"two","url":"2"}'
|
||||||
|
'{"position":"three","url":"3"}'
|
||||||
|
)
|
||||||
|
. ../mo
|
||||||
|
cat <<EOF | mo
|
||||||
|
{
|
||||||
|
{{#items}}
|
||||||
|
{{COMMA_IF_NOT_FIRST}}
|
||||||
|
{{.}}
|
||||||
|
{{/items}}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
48
demo/function-for-foreach
Executable file
48
demo/function-for-foreach
Executable file
@@ -0,0 +1,48 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Example for how #29 can get implemented.
|
||||||
|
|
||||||
|
cd "$(dirname "$0")" # Go to the script's directory
|
||||||
|
|
||||||
|
foreach() {
|
||||||
|
# Trying to use unique names
|
||||||
|
local foreachSourceName foreachIterator foreachEvalString foreachContent
|
||||||
|
|
||||||
|
foreachContent=$(cat)
|
||||||
|
|
||||||
|
if [[ "$2" != "as" && "$2" != "in" ]]; then
|
||||||
|
echo "Invalid foreach - bad format."
|
||||||
|
elif [[ "$(declare -p "$1")" != "declare -"[aA]* ]]; then
|
||||||
|
echo "$1 is not an array"
|
||||||
|
else
|
||||||
|
foreachSourceName="${1}[@]"
|
||||||
|
|
||||||
|
for foreachIterator in "${!foreachSourceName}"; do
|
||||||
|
foreachEvalString=$(declare -p "$foreachIterator")
|
||||||
|
foreachEvalString="declare -A $3=${foreachEvalString#*=}"
|
||||||
|
eval "$foreachEvalString"
|
||||||
|
echo "$foreachContent" | mo
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# The links are associative arrays
|
||||||
|
declare -A resque hub rip
|
||||||
|
resque=([name]=Resque [url]=http://example.com/resque)
|
||||||
|
hub=([name]=Hub [url]=http://example.com/hub)
|
||||||
|
rip=([name]=Rip [url]=http://example.com/rip)
|
||||||
|
|
||||||
|
# This is a list of the link arrays
|
||||||
|
links=(resque hub rip)
|
||||||
|
|
||||||
|
# Source mo in order to work with arrays
|
||||||
|
. ../mo
|
||||||
|
|
||||||
|
# Process the template
|
||||||
|
cat <<EOF | mo --allow-function-arguments
|
||||||
|
Here are your links:
|
||||||
|
{{#foreach links as link}}
|
||||||
|
* [{{link.name}}]({{link.url}})
|
||||||
|
{{/foreach}}
|
||||||
|
|
||||||
|
EOF
|
||||||
47
mo
47
mo
@@ -11,12 +11,18 @@
|
|||||||
#/
|
#/
|
||||||
#/ Simple usage:
|
#/ Simple usage:
|
||||||
#/
|
#/
|
||||||
#/ mo [--false] [--help] [--source=FILE] filenames...
|
#/ mo [OPTIONS] filenames...
|
||||||
#/
|
#/
|
||||||
#/ --fail-not-set - Fail upon expansion of an unset variable.
|
#/ Options:
|
||||||
#/ --false - Treat the string "false" as empty for conditionals.
|
#/
|
||||||
#/ --help - This message.
|
#/ -u, --fail-not-set
|
||||||
#/ --source=FILE - Load FILE into the environment before processing templates.
|
#/ - Fail upon expansion of an unset variable.
|
||||||
|
#/ -e, --false
|
||||||
|
#/ - Treat the string "false" as empty for conditionals.
|
||||||
|
#/ -h, --help
|
||||||
|
#/ - This message.
|
||||||
|
#/ -s=FILE, --source=FILE
|
||||||
|
#/ - Load FILE into the environment before processing templates.
|
||||||
#
|
#
|
||||||
# Mo is under a MIT style licence with an additional non-advertising clause.
|
# Mo is under a MIT style licence with an additional non-advertising clause.
|
||||||
# See LICENSE.md for the full text.
|
# See LICENSE.md for the full text.
|
||||||
@@ -32,14 +38,17 @@
|
|||||||
# --allow-function-arguments
|
# --allow-function-arguments
|
||||||
# - Permit functions in templates to be called with additional
|
# - Permit functions in templates to be called with additional
|
||||||
# arguments. This puts template data directly in to the path
|
# arguments. This puts template data directly in to the path
|
||||||
# of an eval statement. Use with caution.
|
# of an eval statement. Use with caution. Not listed in the
|
||||||
# --fail-not-set - Fail upon expansion of an unset variable. Default behavior
|
# help because it only makes sense when mo is sourced.
|
||||||
|
# -u, --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
|
# -e, --false - Treat "false" as an empty value. You may set the
|
||||||
# MO_FALSE_IS_EMPTY environment variable instead to a non-empty
|
# MO_FALSE_IS_EMPTY environment variable instead to a non-empty
|
||||||
# value to enable this behavior.
|
# value to enable this behavior.
|
||||||
# --help - Display a help message.
|
# -h, --help - Display a help message.
|
||||||
# --source=FILE - Source a file into the environment before processint
|
# -s=FILE, --source=FILE
|
||||||
|
# - Source a file into the environment before processint
|
||||||
# template files.
|
# template files.
|
||||||
# -- - Used to indicate the end of options. You may optionally
|
# -- - Used to indicate the end of options. You may optionally
|
||||||
# use this when filenames may start with two hyphens.
|
# use this when filenames may start with two hyphens.
|
||||||
@@ -53,6 +62,7 @@
|
|||||||
# options and arguments. This puts the content from the
|
# options and arguments. This puts the content from the
|
||||||
# template directly into an eval statement. Use with
|
# template directly into an eval statement. Use with
|
||||||
# extreme care.
|
# extreme care.
|
||||||
|
# MO_FUNCTION_ARGS - Arguments passed to the function
|
||||||
# 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"
|
||||||
@@ -89,18 +99,22 @@ mo() (
|
|||||||
MO_ALLOW_FUNCTION_ARGUMENTS=true
|
MO_ALLOW_FUNCTION_ARGUMENTS=true
|
||||||
;;
|
;;
|
||||||
|
|
||||||
--fail-not-set)
|
-u | --fail-not-set)
|
||||||
# shellcheck disable=SC2030
|
# shellcheck disable=SC2030
|
||||||
MO_FAIL_ON_UNSET=true
|
MO_FAIL_ON_UNSET=true
|
||||||
;;
|
;;
|
||||||
|
|
||||||
--false)
|
-e | --false)
|
||||||
# shellcheck disable=SC2030
|
# shellcheck disable=SC2030
|
||||||
MO_FALSE_IS_EMPTY=true
|
MO_FALSE_IS_EMPTY=true
|
||||||
;;
|
;;
|
||||||
|
|
||||||
--source=*)
|
-s=* | --source=*)
|
||||||
f2source="${arg#--source=}"
|
if [[ "$arg" == --source=* ]]; then
|
||||||
|
f2source="${arg#--source=}"
|
||||||
|
else
|
||||||
|
f2source="${arg#-s=}"
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ -f "$f2source" ]]; then
|
if [[ -f "$f2source" ]]; then
|
||||||
# shellcheck disable=SC1090
|
# shellcheck disable=SC1090
|
||||||
@@ -141,16 +155,17 @@ mo() (
|
|||||||
#
|
#
|
||||||
# Returns nothing.
|
# Returns nothing.
|
||||||
moCallFunction() {
|
moCallFunction() {
|
||||||
local moArgs
|
local moArgs moFunctionArgs
|
||||||
|
|
||||||
moArgs=()
|
moArgs=()
|
||||||
|
moTrimWhitespace moFunctionArgs "$3"
|
||||||
|
|
||||||
# shellcheck disable=SC2031
|
# shellcheck disable=SC2031
|
||||||
if [[ -n "${MO_ALLOW_FUNCTION_ARGUMENTS-}" ]]; then
|
if [[ -n "${MO_ALLOW_FUNCTION_ARGUMENTS-}" ]]; then
|
||||||
moArgs=$3
|
moArgs=$3
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -n "$2" | eval "$1" "$moArgs"
|
echo -n "$2" | MO_FUNCTION_ARGS="$moFunctionArgs" eval "$1" "$moArgs"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
3
tests/function-args-read.env
Normal file
3
tests/function-args-read.env
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
testArgs() {
|
||||||
|
echo "$MO_FUNCTION_ARGS"
|
||||||
|
}
|
||||||
4
tests/function-args-read.expected
Normal file
4
tests/function-args-read.expected
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
No args: [] - done
|
||||||
|
One arg: [one] - done
|
||||||
|
Multiple arguments: [aa bb cc 'x' " ! {[_.|] - done
|
||||||
|
Evil: [bla; cat /etc/issue] - done
|
||||||
4
tests/function-args-read.template
Normal file
4
tests/function-args-read.template
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
No args: [{{testArgs}}] - done
|
||||||
|
One arg: [{{testArgs one}}] - done
|
||||||
|
Multiple arguments: [{{testArgs aa bb cc 'x' " ! {[_.| }}] - done
|
||||||
|
Evil: [{{testArgs bla; cat /etc/issue}}] - done
|
||||||
Reference in New Issue
Block a user