Merge branch 'helper_greater_than' into dust_helpers

This commit is contained in:
Tom Alexander 2020-05-16 18:23:00 -04:00
commit 7cde89c601
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
20 changed files with 938 additions and 127 deletions

View File

@ -38,7 +38,7 @@ while read -r test_group; do
else else
echo "$test_group_name::$test_case_name FAILED" echo "$test_group_name::$test_case_name FAILED"
if [ $show_diff -eq 1 ]; then if [ $show_diff -eq 1 ]; then
diff --label "dustjs-linked" --label "duster" <(xargs -a <(find "$test_group" -maxdepth 1 -mindepth 1 -type f -name 'main.dust'; find "$test_group" -maxdepth 1 -mindepth 1 -type f -name '*.dust' ! -name 'main.dust' | sort) node "$DIR/dustjs_shim.js" < "$test_case" 2>/dev/null ) <(xargs -a <(find "$test_group" -maxdepth 1 -mindepth 1 -type f -name 'main.dust'; find "$test_group" -maxdepth 1 -mindepth 1 -type f -name '*.dust' ! -name 'main.dust' | sort) "$DIR/../target/debug/duster-cli" < "$test_case" 2>/dev/null ) diff --label "dustjs-linkedin" --label "duster" <(xargs -a <(find "$test_group" -maxdepth 1 -mindepth 1 -type f -name 'main.dust'; find "$test_group" -maxdepth 1 -mindepth 1 -type f -name '*.dust' ! -name 'main.dust' | sort) node "$DIR/dustjs_shim.js" < "$test_case" 2>/dev/null ) <(xargs -a <(find "$test_group" -maxdepth 1 -mindepth 1 -type f -name 'main.dust'; find "$test_group" -maxdepth 1 -mindepth 1 -type f -name '*.dust' ! -name 'main.dust' | sort) "$DIR/../target/debug/duster-cli" < "$test_case" 2>/dev/null )
fi fi
exit 1 exit 1
fi fi
@ -48,7 +48,12 @@ while read -r test_group; do
fi fi
set -e set -e
done <<<"$(find "$test_group" -maxdepth 1 -mindepth 1 -type f -name '*.json' | sort)" done <<<"$(find "$test_group" -maxdepth 1 -mindepth 1 -type f -name '*.json' | sort)"
done <<<"$(find "$DIR/test_cases" -maxdepth 1 -mindepth 1 -type d | sort)" done <<<"$(find "$DIR/test_cases" -maxdepth 1 -mindepth 1 -type d ! -name '_*' | sort)"
ignored_count=$(find "$DIR/test_cases" -maxdepth 1 -mindepth 1 -type d -name '_*' | wc -l)
echo ""
echo "$ignored_count ignored tests"
if [ $failed_count -ne 0 ]; then if [ $failed_count -ne 0 ]; then
echo "$failed_count failed tests" echo "$failed_count failed tests"

View File

@ -0,0 +1,72 @@
{
"str": "master",
"int": 7,
"alpha": 21,
"beta": "21",
"null": null,
"true_value": true,
"false_value": false,
"array_lower": [
3,
5,
7
],
"array_lower_with_array": [
3,
5,
[
7
]
],
"copy_array_lower": [
3,
5,
7
],
"array_higher": [
8,
9
],
"array_higher_longer": [
8,
9,
1
],
"some_obj": {
"name": "cat"
},
"copy_some_obj": {
"name": "cat"
},
"other_obj": {
"name": "dog"
},
"array_of_some_obj": [
{
"name": "cat"
},
{
"name": "cat"
}
],
"copy_array_of_some_obj": [
{
"name": "cat"
},
{
"name": "cat"
}
],
"array_of_other_obj": [
{
"name": "dog"
},
{
"name": "dog"
}
],
"array_of_strings": [
"cat",
"dog"
]
}

View File

@ -0,0 +1,41 @@
Testing helpers:{~n}
str is {str}{~n}
int is {int}{~n}
alpha is {alpha}{~n}
beta is {beta}{~n}
{@gte key=str value="master"}str is greater than or equal to "master"{:else}str is less than "master"{/gte}{~n}
{@gte key=str value="7"}str is greater than or equal to "7"{:else}str is less than "7"{/gte}{~n}
{@gte key=int value="7"}int is greater than or equal to "7"{:else}int is less than "7"{/gte}{~n}
{@gte key=int value=7}int is greater than or equal to 7{:else}int is less than 7{/gte}{~n}
{@gte key=int value=6}int is greater than or equal to 6{:else}int is less than 6{/gte}{~n}
{@gte key=alpha value=beta}alpha is greater than or equal to beta{:else}alpha is less than beta{/gte}{~n}
{@gte value=beta}missing key is true{:else}missing key is false{/gte}{~n}
{@gte value=gamma}missing key and non-existent value is true{:else}missing key and non-existent value is false{/gte}{~n}
{@gte key=alpha}missing value is true{:else}missing value is false{/gte}{~n}
{@gte key=gamma}missing value and non-existent key is true{:else}missing value and non-existent key is false{/gte}{~n}
{@gte key="master" value="master"}"master" is greater than or equal to "master"{:else}"master" is less than "master"{/gte}{~n}
{@gte key=null}null is greater than or equal to a missing value{:else}null is less than a missing value{/gte}{~n}
{@gte key=null value=gamma}null is greater than or equal to a non-existent value{:else}null is less than a non-existent value{/gte}{~n}
{@gte}no parameters is true{:else}no parameters is false{/gte}{~n}
{@gte key="a" value="]"}"a" is greater than or equal to "]"{:else}"a" is less than "]"{/gte}{~n}
{@gte key="a" value="A"}"a" is greater than or equal to "A"{:else}"a" is less than "A"{/gte}{~n}
{@gte key="a" value="}"}"a" is greater than or equal to "}"{:else}"a" is less than "}"{/gte}{~n}
{!
Commented out because unicode breaks nom
{@gte key="☃" value="☄"}"☃" is greater than or equal to "☄"{:else}"☃" is less than "☄"{/gte}{~n}
!}
{@gte key=true_value value=false_value}true is greater than or equal to false{:else}true is less than false{/gte}{~n}
{@gte key=array_lower value=array_higher}[3,5,7] is greater than or equal to [8,9]{:else}[3,5,7] is less than [8,9]{/gte}{~n}
{@gte key=array_higher value=array_lower}[8,9] is greater than or equal to [3,5,7]{:else}[8,9] is less than [3,5,7]{/gte}{~n}
{! non-scalar and copied value tests !}
{@gte key=array_lower value=array_lower}array_lower is greater than or equal to array_lower{:else}array_lower is less than array_lower{/gte}{~n}
{@gte key=array_lower value=copy_array_lower}array_lower is greater than or equal to copy_array_lower{:else}array_lower is less than copy_array_lower{/gte}{~n}
{@gte key=some_obj value=some_obj}some_obj is greater than or equal to some_obj{:else}some_obj is less than some_obj{/gte}{~n}
{@gte key=some_obj value=copy_some_obj}some_obj is greater than or equal to copy_some_obj{:else}some_obj is less than copy_some_obj{/gte}{~n}
{@gte key=some_obj value=other_obj}some_obj is greater than or equal to other_obj{:else}some_obj is less than other_obj{/gte}{~n}
{@gte key=array_of_some_obj value=array_of_some_obj}array_of_some_obj is greater than or equal to array_of_some_obj{:else}array_of_some_obj is less than array_of_some_obj{/gte}{~n}
{@gte key=array_of_some_obj value=copy_array_of_some_obj}array_of_some_obj is greater than or equal to copy_array_of_some_obj{:else}array_of_some_obj is less than copy_array_of_some_obj{/gte}{~n}
{@gte key=array_of_some_obj value=array_of_other_obj}array_of_some_obj is greater than or equal to array_of_other_obj{:else}array_of_some_obj is less than array_of_other_obj{/gte}{~n}
{@gte key=array_higher value=array_higher_longer}array_higher is greater than or equal to array_higher_longer{:else}array_higher is less than array_higher_longer{/gte}{~n}
{@gte key=array_lower value=array_lower_with_array}array_lower is greater than or equal to array_lower_with_array{:else}array_lower is less than array_lower_with_array{/gte}{~n}
{@gte key=array_lower_with_array value=array_lower}array_lower_with_array is greater than or equal to array_lower{:else}array_lower_with_array is less than array_lower{/gte}{~n}

View File

@ -0,0 +1,72 @@
{
"str": "master",
"int": 7,
"alpha": 21,
"beta": "21",
"null": null,
"true_value": true,
"false_value": false,
"array_lower": [
3,
5,
7
],
"array_lower_with_array": [
3,
5,
[
7
]
],
"copy_array_lower": [
3,
5,
7
],
"array_higher": [
8,
9
],
"array_higher_longer": [
8,
9,
1
],
"some_obj": {
"name": "cat"
},
"copy_some_obj": {
"name": "cat"
},
"other_obj": {
"name": "dog"
},
"array_of_some_obj": [
{
"name": "cat"
},
{
"name": "cat"
}
],
"copy_array_of_some_obj": [
{
"name": "cat"
},
{
"name": "cat"
}
],
"array_of_other_obj": [
{
"name": "dog"
},
{
"name": "dog"
}
],
"array_of_strings": [
"cat",
"dog"
]
}

View File

@ -0,0 +1,41 @@
Testing helpers:{~n}
str is {str}{~n}
int is {int}{~n}
alpha is {alpha}{~n}
beta is {beta}{~n}
{@lt key=str value="master"}str is less than "master"{:else}str is greater than or equal to "master"{/lt}{~n}
{@lt key=str value="7"}str is less than "7"{:else}str is greater than or equal to "7"{/lt}{~n}
{@lt key=int value="7"}int is less than "7"{:else}int is greater than or equal to "7"{/lt}{~n}
{@lt key=int value=7}int is less than 7{:else}int is greater than or equal to 7{/lt}{~n}
{@lt key=int value=6}int is less than 6{:else}int is greater than or equal to 6{/lt}{~n}
{@lt key=alpha value=beta}alpha is less than beta{:else}alpha is greater than or equal to beta{/lt}{~n}
{@lt value=beta}missing key is true{:else}missing key is false{/lt}{~n}
{@lt value=gamma}missing key and non-existent value is true{:else}missing key and non-existent value is false{/lt}{~n}
{@lt key=alpha}missing value is true{:else}missing value is false{/lt}{~n}
{@lt key=gamma}missing value and non-existent key is true{:else}missing value and non-existent key is false{/lt}{~n}
{@lt key="master" value="master"}"master" is less than "master"{:else}"master" is greater than or equal to "master"{/lt}{~n}
{@lt key=null}null is less than a missing value{:else}null is greater than or equal to a missing value{/lt}{~n}
{@lt key=null value=gamma}null is less than a non-existent value{:else}null is greater than or equal to a non-existent value{/lt}{~n}
{@lt}no parameters is true{:else}no parameters is false{/lt}{~n}
{@lt key="a" value="]"}"a" is less than "]"{:else}"a" is greater than or equal to "]"{/lt}{~n}
{@lt key="a" value="A"}"a" is less than "A"{:else}"a" is greater than or equal to "A"{/lt}{~n}
{@lt key="a" value="}"}"a" is less than "}"{:else}"a" is greater than or equal to "}"{/lt}{~n}
{!
Commented out because unicode breaks nom
{@lt key="☃" value="☄"}"☃" is less than "☄"{:else}"☃" is greater than or equal to "☄"{/lt}{~n}
!}
{@lt key=true_value value=false_value}true is less than false{:else}true is greater than or equal to false{/lt}{~n}
{@lt key=array_lower value=array_higher}[3,5,7] is less than [8,9]{:else}[3,5,7] is greater than or equal to [8,9]{/lt}{~n}
{@lt key=array_higher value=array_lower}[8,9] is less than [3,5,7]{:else}[8,9] is greater than or equal to [3,5,7]{/lt}{~n}
{! non-scalar and copied value tests !}
{@lt key=array_lower value=array_lower}array_lower is less than array_lower{:else}array_lower is greater than or equal to array_lower{/lt}{~n}
{@lt key=array_lower value=copy_array_lower}array_lower is less than copy_array_lower{:else}array_lower is greater than or equal to copy_array_lower{/lt}{~n}
{@lt key=some_obj value=some_obj}some_obj is less than some_obj{:else}some_obj is greater than or equal to some_obj{/lt}{~n}
{@lt key=some_obj value=copy_some_obj}some_obj is less than copy_some_obj{:else}some_obj is greater than or equal to copy_some_obj{/lt}{~n}
{@lt key=some_obj value=other_obj}some_obj is less than other_obj{:else}some_obj is greater than or equal to other_obj{/lt}{~n}
{@lt key=array_of_some_obj value=array_of_some_obj}array_of_some_obj is less than array_of_some_obj{:else}array_of_some_obj is greater than or equal to array_of_some_obj{/lt}{~n}
{@lt key=array_of_some_obj value=copy_array_of_some_obj}array_of_some_obj is less than copy_array_of_some_obj{:else}array_of_some_obj is greater than or equal to copy_array_of_some_obj{/lt}{~n}
{@lt key=array_of_some_obj value=array_of_other_obj}array_of_some_obj is less than array_of_other_obj{:else}array_of_some_obj is greater than or equal to array_of_other_obj{/lt}{~n}
{@lt key=array_higher value=array_higher_longer}array_higher is less than array_higher_longer{:else}array_higher is greater than or equal to array_higher_longer{/lt}{~n}
{@lt key=array_lower value=array_lower_with_array}array_lower is less than array_lower_with_array{:else}array_lower is greater than or equal to array_lower_with_array{/lt}{~n}
{@lt key=array_lower_with_array value=array_lower}array_lower_with_array is less than array_lower{:else}array_lower_with_array is greater than or equal to array_lower{/lt}{~n}

View File

@ -0,0 +1,72 @@
{
"str": "master",
"int": 7,
"alpha": 21,
"beta": "21",
"null": null,
"true_value": true,
"false_value": false,
"array_lower": [
3,
5,
7
],
"array_lower_with_array": [
3,
5,
[
7
]
],
"copy_array_lower": [
3,
5,
7
],
"array_higher": [
8,
9
],
"array_higher_longer": [
8,
9,
1
],
"some_obj": {
"name": "cat"
},
"copy_some_obj": {
"name": "cat"
},
"other_obj": {
"name": "dog"
},
"array_of_some_obj": [
{
"name": "cat"
},
{
"name": "cat"
}
],
"copy_array_of_some_obj": [
{
"name": "cat"
},
{
"name": "cat"
}
],
"array_of_other_obj": [
{
"name": "dog"
},
{
"name": "dog"
}
],
"array_of_strings": [
"cat",
"dog"
]
}

View File

@ -0,0 +1,41 @@
Testing helpers:{~n}
str is {str}{~n}
int is {int}{~n}
alpha is {alpha}{~n}
beta is {beta}{~n}
{@lte key=str value="master"}str is less than or equal to "master"{:else}str is greater than "master"{/lte}{~n}
{@lte key=str value="7"}str is less than or equal to "7"{:else}str is greater than "7"{/lte}{~n}
{@lte key=int value="7"}int is less than or equal to "7"{:else}int is greater than "7"{/lte}{~n}
{@lte key=int value=7}int is less than or equal to 7{:else}int is greater than 7{/lte}{~n}
{@lte key=int value=6}int is less than or equal to 6{:else}int is greater than 6{/lte}{~n}
{@lte key=alpha value=beta}alpha is less than or equal to beta{:else}alpha is greater than beta{/lte}{~n}
{@lte value=beta}missing key is true{:else}missing key is false{/lte}{~n}
{@lte value=gamma}missing key and non-existent value is true{:else}missing key and non-existent value is false{/lte}{~n}
{@lte key=alpha}missing value is true{:else}missing value is false{/lte}{~n}
{@lte key=gamma}missing value and non-existent key is true{:else}missing value and non-existent key is false{/lte}{~n}
{@lte key="master" value="master"}"master" is less than or equal to "master"{:else}"master" is greater than "master"{/lte}{~n}
{@lte key=null}null is less than or equal to a missing value{:else}null is greater than a missing value{/lte}{~n}
{@lte key=null value=gamma}null is less than or equal to a non-existent value{:else}null is greater than a non-existent value{/lte}{~n}
{@lte}no parameters is true{:else}no parameters is false{/lte}{~n}
{@lte key="a" value="]"}"a" is less than or equal to "]"{:else}"a" is greater than "]"{/lte}{~n}
{@lte key="a" value="A"}"a" is less than or equal to "A"{:else}"a" is greater than "A"{/lte}{~n}
{@lte key="a" value="}"}"a" is less than or equal to "}"{:else}"a" is greater than "}"{/lte}{~n}
{!
Commented out because unicode breaks nom
{@lte key="☃" value="☄"}"☃" is less than or equal to "☄"{:else}"☃" is greater than "☄"{/lte}{~n}
!}
{@lte key=true_value value=false_value}true is less than or equal to false{:else}true is greater than false{/lte}{~n}
{@lte key=array_lower value=array_higher}[3,5,7] is less than or equal to [8,9]{:else}[3,5,7] is greater than [8,9]{/lte}{~n}
{@lte key=array_higher value=array_lower}[8,9] is less than or equal to [3,5,7]{:else}[8,9] is greater than [3,5,7]{/lte}{~n}
{! non-scalar and copied value tests !}
{@lte key=array_lower value=array_lower}array_lower is less than or equal to array_lower{:else}array_lower is greater than array_lower{/lte}{~n}
{@lte key=array_lower value=copy_array_lower}array_lower is less than or equal to copy_array_lower{:else}array_lower is greater than copy_array_lower{/lte}{~n}
{@lte key=some_obj value=some_obj}some_obj is less than or equal to some_obj{:else}some_obj is greater than some_obj{/lte}{~n}
{@lte key=some_obj value=copy_some_obj}some_obj is less than or equal to copy_some_obj{:else}some_obj is greater than copy_some_obj{/lte}{~n}
{@lte key=some_obj value=other_obj}some_obj is less than or equal to other_obj{:else}some_obj is greater than other_obj{/lte}{~n}
{@lte key=array_of_some_obj value=array_of_some_obj}array_of_some_obj is less than or equal to array_of_some_obj{:else}array_of_some_obj is greater than array_of_some_obj{/lte}{~n}
{@lte key=array_of_some_obj value=copy_array_of_some_obj}array_of_some_obj is less than or equal to copy_array_of_some_obj{:else}array_of_some_obj is greater than copy_array_of_some_obj{/lte}{~n}
{@lte key=array_of_some_obj value=array_of_other_obj}array_of_some_obj is less than or equal to array_of_other_obj{:else}array_of_some_obj is greater than array_of_other_obj{/lte}{~n}
{@lte key=array_higher value=array_higher_longer}array_higher is less than or equal to array_higher_longer{:else}array_higher is greater than array_higher_longer{/lte}{~n}
{@lte key=array_lower value=array_lower_with_array}array_lower is less than or equal to array_lower_with_array{:else}array_lower is greater than array_lower_with_array{/lte}{~n}
{@lte key=array_lower_with_array value=array_lower}array_lower_with_array is less than or equal to array_lower{:else}array_lower_with_array is greater than array_lower{/lte}{~n}

View File

@ -8,3 +8,8 @@ Can't Walk Theory
Assuming a missing value = cantwalk and a non-existent key = cantwalk then their equality makes sense. Assuming a missing value = cantwalk and a non-existent key = cantwalk then their equality makes sense.
The null tests have proven that absent parameters and missing values do not equal null and therefore it is not just making all falsey values equal. The null tests have proven that absent parameters and missing values do not equal null and therefore it is not just making all falsey values equal.
Non-Scalar Values
-----------------
For non-scalar values, it seems that dust does mark two values as true if they have the same path, but otherwise they are not equal.

View File

@ -3,5 +3,58 @@
"int": 7, "int": 7,
"alpha": 21, "alpha": 21,
"beta": "21", "beta": "21",
"null": null "null": null,
"true_value": true,
"false_value": false,
"array_lower": [
3,
5,
7
],
"copy_array_lower": [
3,
5,
7
],
"array_higher": [
8,
9
],
"some_obj": {
"name": "cat"
},
"copy_some_obj": {
"name": "cat"
},
"other_obj": {
"name": "dog"
},
"array_of_some_obj": [
{
"name": "cat"
},
{
"name": "cat"
}
],
"copy_array_of_some_obj": [
{
"name": "cat"
},
{
"name": "cat"
}
],
"array_of_other_obj": [
{
"name": "dog"
},
{
"name": "dog"
}
],
"array_of_strings": [
"cat",
"dog"
]
} }

View File

@ -15,4 +15,14 @@ beta is {beta}{~n}
{@eq key="master" value="master"}"master" is equal to "master"{:else}"master" does not equal "master"{/eq}{~n} {@eq key="master" value="master"}"master" is equal to "master"{:else}"master" does not equal "master"{/eq}{~n}
{@eq key=null}null equals a missing value{:else}null does not equal a missing value{/eq}{~n} {@eq key=null}null equals a missing value{:else}null does not equal a missing value{/eq}{~n}
{@eq key=null value=gamma}null equals a non-existent value{:else}null does not equal a non-existent value{/eq}{~n} {@eq key=null value=gamma}null equals a non-existent value{:else}null does not equal a non-existent value{/eq}{~n}
{@eq}no parameters is true{:else}no parameters if false{/eq}{~n} {@eq}no parameters is true{:else}no parameters is false{/eq}{~n}
{@eq key=array_lower value=array_higher}[3,5,7] is equal to [8,9]{:else}[3,5,7] does not equal [8,9]{/eq}{~n}
{! non-scalar and copied value tests !}
{@eq key=array_lower value=array_lower}array_lower is equal to array_lower{:else}array_lower does not equal array_lower{/eq}{~n}
{@eq key=array_lower value=copy_array_lower}array_lower is equal to copy_array_lower{:else}array_lower does not equal copy_array_lower{/eq}{~n}
{@eq key=some_obj value=some_obj}some_obj is equal to some_obj{:else}some_obj does not equal some_obj{/eq}{~n}
{@eq key=some_obj value=copy_some_obj}some_obj is equal to copy_some_obj{:else}some_obj does not equal copy_some_obj{/eq}{~n}
{@eq key=some_obj value=other_obj}some_obj is equal to other_obj{:else}some_obj does not equal other_obj{/eq}{~n}
{@eq key=array_of_some_obj value=array_of_some_obj}array_of_some_obj is equal to array_of_some_obj{:else}array_of_some_obj does not equal array_of_some_obj{/eq}{~n}
{@eq key=array_of_some_obj value=copy_array_of_some_obj}array_of_some_obj is equal to copy_array_of_some_obj{:else}array_of_some_obj does not equal copy_array_of_some_obj{/eq}{~n}
{@eq key=array_of_some_obj value=array_of_other_obj}array_of_some_obj is equal to array_of_other_obj{:else}array_of_some_obj does not equal array_of_other_obj{/eq}{~n}

View File

@ -0,0 +1,37 @@
Based on my tests, it appears dust is sorting based on ascii-table values. This also appears to extend to unicode codepoints based on a symbols test.
Greater than follows the same pattern for not rendering when key is omitted or null.
Longer arrays are greater than shorter arrays if all preceding values match.
Theory for comparing arrays: Compare the values, if theres any mismatched types then take the same action you would for non-matching scalar types.
greater than
------------
All comparisons between non-matching types (for example, int vs string) appear to render the else block.
Comparisons between non-scalar types (like arrays) appears to render the else block
greater than or equals to
-------------------------
All comparisons between non-matching types (for example, int vs string) appear to render the main block.
Comparisons between non-scalar types (like arrays) appears to render the main block
less than
---------
All comparisons between non-matching types (for example, int vs string) appear to render the else block.
Comparisons between non-scalar types (like arrays) appears to render the else block
less than or equal to
---------------------
All comparisons between non-matching types (for example, int vs string) appear to render the main block.
Comparisons between non-scalar types (like arrays) appears to render the main block

View File

@ -0,0 +1,72 @@
{
"str": "master",
"int": 7,
"alpha": 21,
"beta": "21",
"null": null,
"true_value": true,
"false_value": false,
"array_lower": [
3,
5,
7
],
"array_lower_with_array": [
3,
5,
[
7
]
],
"copy_array_lower": [
3,
5,
7
],
"array_higher": [
8,
9
],
"array_higher_longer": [
8,
9,
1
],
"some_obj": {
"name": "cat"
},
"copy_some_obj": {
"name": "cat"
},
"other_obj": {
"name": "dog"
},
"array_of_some_obj": [
{
"name": "cat"
},
{
"name": "cat"
}
],
"copy_array_of_some_obj": [
{
"name": "cat"
},
{
"name": "cat"
}
],
"array_of_other_obj": [
{
"name": "dog"
},
{
"name": "dog"
}
],
"array_of_strings": [
"cat",
"dog"
]
}

View File

@ -0,0 +1,42 @@
Testing helpers:{~n}
str is {str}{~n}
int is {int}{~n}
alpha is {alpha}{~n}
beta is {beta}{~n}
{@gt key=str value="master"}str is greater than "master"{:else}str is less than or equal to "master"{/gt}{~n}
{@gt key=str value="7"}str is greater than "7"{:else}str is less than or equal to "7"{/gt}{~n}
{@gt key=int value="7"}int is greater than "7"{:else}int is less than or equal to "7"{/gt}{~n}
{@gt key=int value=7}int is greater than 7{:else}int is less than or equal to 7{/gt}{~n}
{@gt key=int value=6}int is greater than 6{:else}int is less than or equal to 6{/gt}{~n}
{@gt key=alpha value=beta}alpha is greater than beta{:else}alpha is less than or equal to beta{/gt}{~n}
{@gt value=beta}missing key is true{:else}missing key is false{/gt}{~n}
{@gt value=gamma}missing key and non-existent value is true{:else}missing key and non-existent value is false{/gt}{~n}
{@gt key=alpha}missing value is true{:else}missing value is false{/gt}{~n}
{@gt key=gamma}missing value and non-existent key is true{:else}missing value and non-existent key is false{/gt}{~n}
{@gt key="master" value="master"}"master" is greater than "master"{:else}"master" is less than or equal to "master"{/gt}{~n}
{@gt key=null}null is greater than a missing value{:else}null is less than or equal to a missing value{/gt}{~n}
{@gt key=null value=gamma}null is greater than a non-existent value{:else}null is less than or equal to a non-existent value{/gt}{~n}
{@gt}no parameters is true{:else}no parameters is false{/gt}{~n}
{@gt key="a" value="]"}"a" is greater than "]"{:else}"a" is less than or equal to "]"{/gt}{~n}
{@gt key="a" value="A"}"a" is greater than "A"{:else}"a" is less than or equal to "A"{/gt}{~n}
{@gt key="a" value="}"}"a" is greater than "}"{:else}"a" is less than or equal to "}"{/gt}{~n}
{!
Commented out because unicode breaks nom
{@gt key="☃" value="☄"}"☃" is greater than "☄"{:else}"☃" is less than or equal to "☄"{/gt}{~n}
!}
{@gt key=true_value value=false_value}true is greater than false{:else}true is less than or equal to false{/gt}{~n}
{@gt key=array_lower value=array_higher}[3,5,7] is greater than [8,9]{:else}[3,5,7] is less than or equal to [8,9]{/gt}{~n}
{@gt key=array_higher value=array_lower}[8,9] is greater than [3,5,7]{:else}[8,9] is less than or equal to [3,5,7]{/gt}{~n}
{! non-scalar and copied value tests !}
{@gt key=array_lower value=array_lower}array_lower is greater than array_lower{:else}array_lower is less than or equal to array_lower{/gt}{~n}
{@gt key=array_lower value=copy_array_lower}array_lower is greater than copy_array_lower{:else}array_lower is less than or equal to copy_array_lower{/gt}{~n}
{@gt key=some_obj value=some_obj}some_obj is greater than some_obj{:else}some_obj is less than or equal to some_obj{/gt}{~n}
{@gt key=some_obj value=copy_some_obj}some_obj is greater than copy_some_obj{:else}some_obj is less than or equal to copy_some_obj{/gt}{~n}
{@gt key=some_obj value=other_obj}some_obj is greater than other_obj{:else}some_obj is less than or equal to other_obj{/gt}{~n}
{@gt key=array_of_some_obj value=array_of_some_obj}array_of_some_obj is greater than array_of_some_obj{:else}array_of_some_obj is less than or equal to array_of_some_obj{/gt}{~n}
{@gt key=array_of_some_obj value=copy_array_of_some_obj}array_of_some_obj is greater than copy_array_of_some_obj{:else}array_of_some_obj is less than or equal to copy_array_of_some_obj{/gt}{~n}
{@gt key=array_of_some_obj value=array_of_other_obj}array_of_some_obj is greater than array_of_other_obj{:else}array_of_some_obj is less than or equal to array_of_other_obj{/gt}{~n}
{@gt key=array_higher value=array_higher_longer}array_higher is greater than array_higher_longer{:else}array_higher is less than or equal to array_higher_longer{/gt}{~n}
{@gt key=array_lower value=array_lower_with_array}array_lower is greater than array_lower_with_array{:else}array_lower is less than or equal to array_lower_with_array{/gt}{~n}
{@gt key=array_lower_with_array value=array_lower}array_lower_with_array is greater than array_lower{:else}array_lower_with_array is less than or equal to array_lower{/gt}{~n}

View File

@ -1,10 +0,0 @@
Without a key parameter, neither the main block nor the else block is rendered.
Literal values work in both keys and values.
Can't Walk Theory
-----------------
Assuming a missing value = cantwalk and a non-existent key = cantwalk then their equality makes sense.
The null tests have proven that absent parameters and missing values do not equal null and therefore it is not just making all falsey values equal.

View File

@ -3,5 +3,58 @@
"int": 7, "int": 7,
"alpha": 21, "alpha": 21,
"beta": "21", "beta": "21",
"null": null "null": null,
"true_value": true,
"false_value": false,
"array_lower": [
3,
5,
7
],
"copy_array_lower": [
3,
5,
7
],
"array_higher": [
8,
9
],
"some_obj": {
"name": "cat"
},
"copy_some_obj": {
"name": "cat"
},
"other_obj": {
"name": "dog"
},
"array_of_some_obj": [
{
"name": "cat"
},
{
"name": "cat"
}
],
"copy_array_of_some_obj": [
{
"name": "cat"
},
{
"name": "cat"
}
],
"array_of_other_obj": [
{
"name": "dog"
},
{
"name": "dog"
}
],
"array_of_strings": [
"cat",
"dog"
]
} }

View File

@ -15,4 +15,14 @@ beta is {beta}{~n}
{@ne key="master" value="master"}"master" does not equal "master"{:else}"master" is equal to "master"{/ne}{~n} {@ne key="master" value="master"}"master" does not equal "master"{:else}"master" is equal to "master"{/ne}{~n}
{@ne key=null}null does not equal a missing value{:else}null equals a missing value{/ne}{~n} {@ne key=null}null does not equal a missing value{:else}null equals a missing value{/ne}{~n}
{@ne key=null value=gamma}null does not equal non-existent value{:else}null equals a non-existent value{/ne}{~n} {@ne key=null value=gamma}null does not equal non-existent value{:else}null equals a non-existent value{/ne}{~n}
{@ne}no parameters is true{:else}no parameters if false{/ne}{~n} {@ne}no parameters is true{:else}no parameters is false{/ne}{~n}
{@ne key=array_lower value=array_higher}[3,5,7] does not equal [8,9]{:else}[3,5,7] is equal to [8,9]{/ne}{~n}
{! non-scalar and copied value tests !}
{@ne key=array_lower value=array_lower}array_lower does not equal array_lower{:else}array_lower is equals to array_lower{/ne}{~n}
{@ne key=array_lower value=copy_array_lower}array_lower does not equal copy_array_lower{:else}array_lower is equals to copy_array_lower{/ne}{~n}
{@ne key=some_obj value=some_obj}some_obj does not equal some_obj{:else}some_obj is equals to some_obj{/ne}{~n}
{@ne key=some_obj value=copy_some_obj}some_obj does not equal copy_some_obj{:else}some_obj is equals to copy_some_obj{/ne}{~n}
{@ne key=some_obj value=other_obj}some_obj does not equal other_obj{:else}some_obj is equals to other_obj{/ne}{~n}
{@ne key=array_of_some_obj value=array_of_some_obj}array_of_some_obj does not equal array_of_some_obj{:else}array_of_some_obj is equals to array_of_some_obj{/ne}{~n}
{@ne key=array_of_some_obj value=copy_array_of_some_obj}array_of_some_obj does not equal copy_array_of_some_obj{:else}array_of_some_obj is equals to copy_array_of_some_obj{/ne}{~n}
{@ne key=array_of_some_obj value=array_of_other_obj}array_of_some_obj does not equal array_of_other_obj{:else}array_of_some_obj is equals to array_of_other_obj{/ne}{~n}

View File

@ -11,6 +11,7 @@ use renderer::RenderError;
use renderer::Renderable; use renderer::Renderable;
use renderer::WalkError; use renderer::WalkError;
use renderer::Walkable; use renderer::Walkable;
use std::cmp::Ordering;
use std::env; use std::env;
use std::fs; use std::fs;
use std::io::{self, Read}; use std::io::{self, Read};
@ -144,7 +145,15 @@ impl CompareContextElement for serde_json::Value {
// Handle other serde_json::Value // Handle other serde_json::Value
match other.to_any().downcast_ref::<Self>() { match other.to_any().downcast_ref::<Self>() {
None => (), None => (),
Some(other_json_value) => return self == other_json_value, Some(other_json_value) => match (self, other_json_value) {
// Non-scalar values not caught in the renderer by the
// identical-path shortcut are always not equal.
(serde_json::Value::Array(_), _)
| (_, serde_json::Value::Array(_))
| (serde_json::Value::Object(_), _)
| (_, serde_json::Value::Object(_)) => return false,
_ => return self == other_json_value,
},
} }
// Handle string literals // Handle string literals
match other.to_any().downcast_ref::<String>() { match other.to_any().downcast_ref::<String>() {
@ -158,4 +167,92 @@ impl CompareContextElement for serde_json::Value {
} }
false false
} }
fn partial_compare(&self, other: &dyn ContextElement) -> Option<Ordering> {
// Handle other serde_json::Value
match other.to_any().downcast_ref::<Self>() {
None => (),
Some(other_json_value) => {
return match (self, other_json_value) {
(
serde_json::Value::Bool(self_boolean),
serde_json::Value::Bool(other_boolean),
) => self_boolean.partial_cmp(other_boolean),
(
serde_json::Value::Number(self_number),
serde_json::Value::Number(other_number),
) => match (
self_number.as_f64(),
other_number.as_f64(),
self_number.as_u64(),
other_number.as_u64(),
self_number.as_i64(),
other_number.as_i64(),
) {
(_, _, _, _, Some(self_int), Some(other_int)) => {
self_int.partial_cmp(&other_int)
}
(_, _, Some(self_uint), Some(other_uint), _, _) => {
self_uint.partial_cmp(&other_uint)
}
(_, _, Some(_self_uint), _, _, Some(_other_int)) => {
// If the previous matches did not catch
// it, then other must be negative and
// self must be larger than can be
// represented with an i64, therefore self
// is greater than other.
Some(Ordering::Greater)
}
(_, _, _, Some(_other_uint), Some(_self_int), _) => {
// If the previous matches did not catch
// it, then self must be negative and
// other must be larger than can be
// represented with an i64, therefore
// other is greater than self.
Some(Ordering::Less)
}
(Some(self_float), Some(other_float), _, _, _, _) => {
self_float.partial_cmp(&other_float)
}
_ => panic!("This should be impossible since u64 and i64 can both be converted to floats"),
},
(
serde_json::Value::String(self_string),
serde_json::Value::String(other_string),
) => self_string.partial_cmp(other_string),
(serde_json::Value::Array(self_array), serde_json::Value::Array(other_array)) => convert_vec_to_context_element(self_array).partial_cmp(&convert_vec_to_context_element(other_array)),
_ => None,
};
}
}
// Handle string literals
match other.to_any().downcast_ref::<String>() {
None => (),
Some(other_string) => {
return self
.as_str()
.map_or(None, |s| s.partial_cmp(other_string.as_str()))
}
}
// Handle numeric literals
match other.to_any().downcast_ref::<u64>() {
None => (),
Some(other_num) => return self.as_u64().map_or(None, |n| n.partial_cmp(other_num)),
}
None
}
}
/// Create a new vec by of references to the serde_json::Values as
/// ContextElement trait objects so we can use its implementation of
/// PartialOrd.
///
/// You cannot implement a trait you do not define for a type you do
/// not define, so I cannot implement PartialOrd for
/// serde_json::value. Instead, I just re-use the PartialOrd
/// implementation for ContextElement which unfortunately has extra
/// overhead of downcasting. This would be a good spot for
/// optimization.
fn convert_vec_to_context_element(array: &Vec<serde_json::Value>) -> Vec<&dyn ContextElement> {
array.iter().map(|v| v as _).collect()
} }

View File

@ -2,7 +2,7 @@ use crate::parser::Filter;
use crate::renderer::errors::RenderError; use crate::renderer::errors::RenderError;
use crate::renderer::errors::WalkError; use crate::renderer::errors::WalkError;
use std::any::Any; use std::any::Any;
use std::fmt::Debug; use std::{cmp::Ordering, fmt::Debug};
pub trait ContextElement: pub trait ContextElement:
Debug + Walkable + Renderable + Loopable + CloneIntoBoxedContextElement + CompareContextElement Debug + Walkable + Renderable + Loopable + CloneIntoBoxedContextElement + CompareContextElement
@ -36,6 +36,8 @@ pub trait CastToAny {
pub trait CompareContextElement: CastToAny { pub trait CompareContextElement: CastToAny {
fn equals(&self, other: &dyn ContextElement) -> bool; fn equals(&self, other: &dyn ContextElement) -> bool;
fn partial_compare(&self, other: &dyn ContextElement) -> Option<Ordering>;
} }
pub trait CloneIntoBoxedContextElement { pub trait CloneIntoBoxedContextElement {
@ -59,3 +61,9 @@ impl<'a, 'b> PartialEq<&'b dyn ContextElement> for &'a dyn ContextElement {
self.equals(*other) self.equals(*other)
} }
} }
impl<'a, 'b> PartialOrd<&'b dyn ContextElement> for &'a dyn ContextElement {
fn partial_cmp(&self, other: &&'b dyn ContextElement) -> Option<Ordering> {
self.partial_compare(*other)
}
}

View File

@ -8,7 +8,7 @@ use crate::renderer::RenderError;
use crate::renderer::Renderable; use crate::renderer::Renderable;
use crate::renderer::WalkError; use crate::renderer::WalkError;
use crate::renderer::Walkable; use crate::renderer::Walkable;
use std::collections::HashMap; use std::{cmp::Ordering, collections::HashMap};
/// Copy the data from an RValue to an Owned struct /// Copy the data from an RValue to an Owned struct
/// ///
@ -122,6 +122,11 @@ impl CompareContextElement for ParametersContext {
// TODO: Does this ever happen? perhaps I should have a panic here. // TODO: Does this ever happen? perhaps I should have a panic here.
false false
} }
fn partial_compare(&self, other: &dyn ContextElement) -> Option<Ordering> {
// TODO: Does this ever happen? perhaps I should have a panic here.
None
}
} }
impl ContextElement for String {} impl ContextElement for String {}
@ -158,6 +163,23 @@ impl CompareContextElement for String {
Some(other_string) => self == other_string, Some(other_string) => self == other_string,
} }
} }
fn partial_compare(&self, other: &dyn ContextElement) -> Option<Ordering> {
// If its a string then compare them directly, otherwise defer
// to the other type's implementation of CompareContextElement
// since the end user could add any type.
match other.to_any().downcast_ref::<Self>() {
None => match other.partial_compare(self) {
None => None,
Some(ord) => match ord {
Ordering::Equal => Some(Ordering::Equal),
Ordering::Greater => Some(Ordering::Less),
Ordering::Less => Some(Ordering::Greater),
},
},
Some(other_string) => self.partial_cmp(other_string),
}
}
} }
impl ContextElement for u64 {} impl ContextElement for u64 {}
@ -190,4 +212,21 @@ impl CompareContextElement for u64 {
Some(other_num) => self == other_num, Some(other_num) => self == other_num,
} }
} }
fn partial_compare(&self, other: &dyn ContextElement) -> Option<Ordering> {
// If its a u64 then compare them directly, otherwise defer
// to the other type's implementation of CompareContextElement
// since the end user could add any type.
match other.to_any().downcast_ref::<Self>() {
None => match other.partial_compare(self) {
None => None,
Some(ord) => match ord {
Ordering::Equal => Some(Ordering::Equal),
Ordering::Greater => Some(Ordering::Less),
Ordering::Less => Some(Ordering::Greater),
},
},
Some(other_num) => self.partial_cmp(other_num),
}
}
} }

View File

@ -77,6 +77,18 @@ impl<'a> DustRenderer<'a> {
self.render_body(&main_template.contents, breadcrumbs, &new_blocks) self.render_body(&main_template.contents, breadcrumbs, &new_blocks)
} }
fn render_maybe_body(
&'a self,
body: &'a Option<Body>,
breadcrumbs: &Vec<&'a dyn ContextElement>,
blocks: &'a InlinePartialTreeElement<'a>,
) -> Result<String, RenderError> {
match body {
None => Ok("".to_owned()),
Some(body) => Ok(self.render_body(body, breadcrumbs, blocks)?),
}
}
fn render_body( fn render_body(
&'a self, &'a self,
body: &'a Body, body: &'a Body,
@ -130,16 +142,13 @@ impl<'a> DustRenderer<'a> {
} }
DustTag::DTSection(container) => { DustTag::DTSection(container) => {
let val = walk_path(breadcrumbs, &container.path.keys); let val = walk_path(breadcrumbs, &container.path.keys);
let loop_elements: Vec<&dyn ContextElement> = self.get_loop_elements(val); let loop_elements: Vec<&dyn ContextElement> = Self::get_loop_elements(val);
if loop_elements.is_empty() { if loop_elements.is_empty() {
// Oddly enough if the value is falsey (like // Oddly enough if the value is falsey (like
// an empty array or null), Dust uses the // an empty array or null), Dust uses the
// original context before walking the path as // original context before walking the path as
// the context for rendering the else block // the context for rendering the else block
return match &container.else_contents { return self.render_maybe_body(&container.else_contents, breadcrumbs, blocks);
Some(body) => self.render_body(&body, breadcrumbs, blocks),
None => Ok("".to_owned()),
};
} else { } else {
match &container.contents { match &container.contents {
None => return Ok("".to_owned()), None => return Ok("".to_owned()),
@ -160,34 +169,22 @@ impl<'a> DustRenderer<'a> {
} }
DustTag::DTExists(container) => { DustTag::DTExists(container) => {
let val = walk_path(breadcrumbs, &container.path.keys); let val = walk_path(breadcrumbs, &container.path.keys);
let loop_elements: Vec<&dyn ContextElement> = self.get_loop_elements(val); let loop_elements: Vec<&dyn ContextElement> = Self::get_loop_elements(val);
if loop_elements.is_empty() { return if loop_elements.is_empty() {
return match &container.else_contents { self.render_maybe_body(&container.else_contents, breadcrumbs, blocks)
Some(body) => self.render_body(&body, breadcrumbs, blocks),
None => Ok("".to_owned()),
};
} else { } else {
return match &container.contents { self.render_maybe_body(&container.contents, breadcrumbs, blocks)
None => Ok("".to_owned()),
Some(body) => self.render_body(&body, breadcrumbs, blocks),
}; };
} }
}
DustTag::DTNotExists(container) => { DustTag::DTNotExists(container) => {
let val = walk_path(breadcrumbs, &container.path.keys); let val = walk_path(breadcrumbs, &container.path.keys);
let loop_elements: Vec<&dyn ContextElement> = self.get_loop_elements(val); let loop_elements: Vec<&dyn ContextElement> = Self::get_loop_elements(val);
if !loop_elements.is_empty() { return if !loop_elements.is_empty() {
return match &container.else_contents { self.render_maybe_body(&container.else_contents, breadcrumbs, blocks)
Some(body) => self.render_body(&body, breadcrumbs, blocks),
None => Ok("".to_owned()),
};
} else { } else {
return match &container.contents { self.render_maybe_body(&container.contents, breadcrumbs, blocks)
None => Ok("".to_owned()),
Some(body) => self.render_body(&body, breadcrumbs, blocks),
}; };
} }
}
DustTag::DTPartial(partial) => { DustTag::DTPartial(partial) => {
if partial.params.is_empty() { if partial.params.is_empty() {
let rendered_content = let rendered_content =
@ -202,107 +199,127 @@ impl<'a> DustRenderer<'a> {
return Ok(rendered_content); return Ok(rendered_content);
} }
} }
DustTag::DTInlinePartial(named_block) => { DustTag::DTInlinePartial(_named_block) => {
// Inline partials are blank during rendering (they get injected into blocks) // Inline partials are blank during rendering (they get injected into blocks)
return Ok("".to_owned()); return Ok("".to_owned());
} }
DustTag::DTBlock(named_block) => { DustTag::DTBlock(named_block) => {
match blocks.get_block(named_block.name) { return match blocks.get_block(named_block.name) {
None => match &named_block.contents { None => self.render_maybe_body(&named_block.contents, breadcrumbs, blocks),
None => return Ok("".to_owned()), Some(interior) => self.render_maybe_body(interior, breadcrumbs, blocks),
Some(body) => {
let rendered_content = self.render_body(body, breadcrumbs, blocks)?;
return Ok(rendered_content);
}
},
Some(interior) => match interior {
None => return Ok("".to_owned()),
Some(body) => {
let rendered_content = self.render_body(body, breadcrumbs, blocks)?;
return Ok(rendered_content);
}
},
}; };
} }
DustTag::DTHelperEquals(parameterized_block) => { DustTag::DTHelperEquals(parameterized_block) => {
let param_map: HashMap<&str, &RValue<'a>> = parameterized_block let param_map: HashMap<&str, &RValue<'a>> =
.params Self::get_rval_map(&parameterized_block.params);
.iter() // Special case: when comparing two RVPaths, if the
.map(|pair: &KVPair<'a>| (pair.key, &pair.value)) // path is equal then dust assumes the values are
.collect(); // equal (otherwise, non-scalar values are
let left_side: Result<&dyn ContextElement, WalkError> = match param_map.get("key") { // automatically not equal)
if Self::are_paths_identical(&param_map) {
return match &parameterized_block.contents {
None => Ok("".to_owned()),
Some(body) => {
let rendered_content = self.render_body(body, breadcrumbs, blocks)?;
Ok(rendered_content)
}
};
}
let left_side: Result<&dyn ContextElement, WalkError> =
match Self::get_rval(breadcrumbs, &param_map, "key") {
None => return Ok("".to_owned()), None => return Ok("".to_owned()),
Some(rval) => match rval { Some(res) => res,
RValue::RVString(text) => Ok(text),
RValue::RVPath(path) => walk_path(breadcrumbs, &path.keys),
RValue::RVPositiveInteger(num) => Ok(num),
},
}; };
let right_side: Result<&dyn ContextElement, WalkError> = let right_side: Result<&dyn ContextElement, WalkError> =
match param_map.get("value") { Self::get_rval(breadcrumbs, &param_map, "value")
None => Err(WalkError::CantWalk), .unwrap_or(Err(WalkError::CantWalk));
Some(rval) => match rval {
RValue::RVString(text) => Ok(text),
RValue::RVPath(path) => walk_path(breadcrumbs, &path.keys),
RValue::RVPositiveInteger(num) => Ok(num),
},
};
if left_side == right_side { if left_side == right_side {
match &parameterized_block.contents { return self.render_maybe_body(
None => return Ok("".to_owned()), &parameterized_block.contents,
Some(body) => { breadcrumbs,
let rendered_content = self.render_body(body, breadcrumbs, blocks)?; blocks,
return Ok(rendered_content); );
}
}
} else { } else {
match &parameterized_block.else_contents { return self.render_maybe_body(
None => return Ok("".to_owned()), &parameterized_block.else_contents,
Some(body) => { breadcrumbs,
let rendered_content = self.render_body(body, breadcrumbs, blocks)?; blocks,
return Ok(rendered_content); );
}
}
} }
} }
DustTag::DTHelperNotEquals(parameterized_block) => { DustTag::DTHelperNotEquals(parameterized_block) => {
let param_map: HashMap<&str, &RValue<'a>> = parameterized_block let param_map: HashMap<&str, &RValue<'a>> =
.params Self::get_rval_map(&parameterized_block.params);
.iter() // Special case: when comparing two RVPaths, if the
.map(|pair: &KVPair<'a>| (pair.key, &pair.value)) // path is equal then dust assumes the values are
.collect(); // equal (otherwise, non-scalar values are
let left_side: Result<&dyn ContextElement, WalkError> = match param_map.get("key") { // automatically not equal)
if Self::are_paths_identical(&param_map) {
return match &parameterized_block.else_contents {
None => Ok("".to_owned()),
Some(body) => {
let rendered_content = self.render_body(body, breadcrumbs, blocks)?;
Ok(rendered_content)
}
};
}
let left_side: Result<&dyn ContextElement, WalkError> =
match Self::get_rval(breadcrumbs, &param_map, "key") {
None => return Ok("".to_owned()), None => return Ok("".to_owned()),
Some(rval) => match rval { Some(res) => res,
RValue::RVString(text) => Ok(text),
RValue::RVPath(path) => walk_path(breadcrumbs, &path.keys),
RValue::RVPositiveInteger(num) => Ok(num),
},
}; };
let right_side: Result<&dyn ContextElement, WalkError> = let right_side: Result<&dyn ContextElement, WalkError> =
match param_map.get("value") { Self::get_rval(breadcrumbs, &param_map, "value")
None => Err(WalkError::CantWalk), .unwrap_or(Err(WalkError::CantWalk));
Some(rval) => match rval {
RValue::RVString(text) => Ok(text),
RValue::RVPath(path) => walk_path(breadcrumbs, &path.keys),
RValue::RVPositiveInteger(num) => Ok(num),
},
};
if left_side != right_side { if left_side != right_side {
match &parameterized_block.contents { return self.render_maybe_body(
None => return Ok("".to_owned()), &parameterized_block.contents,
Some(body) => { breadcrumbs,
let rendered_content = self.render_body(body, breadcrumbs, blocks)?; blocks,
return Ok(rendered_content); );
}
}
} else { } else {
match &parameterized_block.else_contents { return self.render_maybe_body(
&parameterized_block.else_contents,
breadcrumbs,
blocks,
);
}
}
DustTag::DTHelperGreaterThan(parameterized_block) => {
let param_map: HashMap<&str, &RValue<'a>> =
Self::get_rval_map(&parameterized_block.params);
let left_side: Result<&dyn ContextElement, WalkError> =
match Self::get_rval(breadcrumbs, &param_map, "key") {
None => return Ok("".to_owned()),
Some(res) => res,
};
let right_side: Result<&dyn ContextElement, WalkError> =
Self::get_rval(breadcrumbs, &param_map, "value")
.unwrap_or(Err(WalkError::CantWalk));
match (left_side, right_side) {
(Err(_), _) | (_, Err(_)) => match &parameterized_block.else_contents {
None => return Ok("".to_owned()), None => return Ok("".to_owned()),
Some(body) => { Some(body) => {
let rendered_content = self.render_body(body, breadcrumbs, blocks)?; let rendered_content = self.render_body(body, breadcrumbs, blocks)?;
return Ok(rendered_content); return Ok(rendered_content);
} }
},
(Ok(left_side_unwrapped), Ok(right_side_unwrapped)) => {
if left_side_unwrapped > right_side_unwrapped {
return self.render_maybe_body(
&parameterized_block.contents,
breadcrumbs,
blocks,
);
} else {
return self.render_maybe_body(
&parameterized_block.else_contents,
breadcrumbs,
blocks,
);
}
} }
} }
} }
@ -316,7 +333,6 @@ impl<'a> DustRenderer<'a> {
/// If the value is falsey, and therefore should render the else /// If the value is falsey, and therefore should render the else
/// block, this will return an empty vector. /// block, this will return an empty vector.
fn get_loop_elements<'b>( fn get_loop_elements<'b>(
&'a self,
walk_result: Result<&'b dyn ContextElement, WalkError>, walk_result: Result<&'b dyn ContextElement, WalkError>,
) -> Vec<&'b dyn ContextElement> { ) -> Vec<&'b dyn ContextElement> {
match walk_result { match walk_result {
@ -324,6 +340,41 @@ impl<'a> DustRenderer<'a> {
Ok(walk_target) => walk_target.get_loop_elements(), Ok(walk_target) => walk_target.get_loop_elements(),
} }
} }
fn are_paths_identical<'b>(param_map: &HashMap<&str, &RValue<'b>>) -> bool {
match (param_map.get("key"), param_map.get("value")) {
(None, _) => false,
(_, None) => false,
(Some(key_rval), Some(value_rval)) => match (key_rval, value_rval) {
(RValue::RVPath(key_path), RValue::RVPath(value_path)) => {
key_path.keys == value_path.keys
}
_ => false,
},
}
}
fn get_rval_map<'b>(params: &'b Vec<KVPair<'b>>) -> HashMap<&'b str, &'b RValue<'b>> {
params
.iter()
.map(|pair: &KVPair<'b>| (pair.key, &pair.value))
.collect()
}
fn get_rval<'b>(
breadcrumbs: &Vec<&'b dyn ContextElement>,
param_map: &HashMap<&str, &'b RValue<'b>>,
key: &str,
) -> Option<Result<&'b dyn ContextElement, WalkError>> {
match param_map.get(key) {
None => None,
Some(rval) => match rval {
RValue::RVString(text) => Some(Ok(text)),
RValue::RVPath(path) => Some(walk_path(breadcrumbs, &path.keys)),
RValue::RVPositiveInteger(num) => Some(Ok(num)),
},
}
}
} }
#[cfg(test)] #[cfg(test)]