diff --git a/.version b/.version index f9fe6b4..879b416 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -2.5b +2.1 diff --git a/LICENSE b/LICENSE deleted file mode 100644 index cf8e84f..0000000 --- a/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -MIT License - -Copyright (c) 2020 Brandon Rozek -Copyright (c) 2019 Sławomir Śledź - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/README.md b/README.md index 15673cd..03d5783 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,12 @@ # Introduction -This is a fork of [ssledz's fun.sh library](https://github.com/ssledz/bash-fun). +[Introduction to fun.sh library](http://ssledz.github.io/presentations/bash-fun.html#/) -This is mainly for my own personal use cases. So I would recommend using ssledz's version instead. -I mainly worked towards getting this library to mostly pass shellcheck, removed some functionality, -and name deconflicted some of the functions with what I had in my system. # Quick start ```bash #!/bin/bash -. <(test -e fun.sh || curl -Ls https://raw.githubusercontent.com/brandon-rozek/bash-fun/master/src/fun.sh > fun.sh; cat fun.sh) +. <(test -e fun.sh || curl -Ls https://raw.githubusercontent.com/ssledz/bash-fun/master/src/fun.sh > fun.sh; cat fun.sh) seq 1 4 | sum ``` @@ -17,17 +14,13 @@ seq 1 4 | sum # Functions overview ||||||| |------|------|------|------|------|------| -|**list_append**|**divide**|**take_while**| -|**list_drop**|**drop_while**|**factorial**|**filter**|**foldl**| -|**isint**|**isempty**|**isfile**|**isnonzerofile**|**isreadable**|**iswritable**| -|**isdir**|**list_join**|**lambda**|**list_last**|**list_head**|**list**| -|**list_tail**|**list_zip**|**list_map**| -|**mod**|**multiply**|**not**| -|**add**|**list_prepend**|**product**|**ret**| -|**revers**|**revers_str**|**scanl**|**splitc**|**strip**| -|**stripl**|**stripr**|**subtract**|**sum**|**take**| -|**tup**|**unlist**|**λ**| - +|**plus**|**append**|**buff**|**curry**|**div**|**drop**| +|**factorial**|**filter**|**foldl**|**foldr**|**head**|**join**| +|**lambda**|**last**|**list**|**map**|**mod**|**mul**| +|**prepend**|**product**|**ret**|**revers_str**|**revers**|**scanl**| +|**splitc**|**strip**|**sub**|**sum**|**tail**|**take**| +|**catch**|**try**|**tupl**|**tupr**|**tup**|**tupx**| +|**unlist**|**zip**|**λ**|**with_trampoline**|**res**|**call**| ## *list/unlist* @@ -41,25 +34,25 @@ $ list 1 2 3 4 5 | unlist 1 2 3 4 5 ``` -## *list_take/list_drop/list_tail/list_head/list_last* +## *take/drop/tail/head/last* ```bash -$ list 1 2 3 4 | list_drop 2 +$ list 1 2 3 4 | drop 2 3 4 -$ list 1 2 3 4 5 | list_head +$ list 1 2 3 4 5 | head 1 -$ list 1 2 3 4 | list_tail +$ list 1 2 3 4 | tail 2 3 4 -$ list 1 2 3 4 5 | list_last +$ list 1 2 3 4 5 | last 5 -$ list 1 2 3 4 5 | list_take 2 +$ list 1 2 3 4 5 | take 2 1 2 ``` @@ -67,36 +60,45 @@ $ list 1 2 3 4 5 | list_take 2 ## *join* ```bash -$ list 1 2 3 4 5 | list_join , +$ list 1 2 3 4 5 | join , 1,2,3,4,5 + +$ list 1 2 3 4 5 | join , [ ] +[1,2,3,4,5] ``` ## *map* ```bash -$ seq 1 5 | list_map λ a . 'echo $((a + 5))' +$ seq 1 5 | map λ a . 'echo $((a + 5))' 6 7 8 9 10 -$ list a b s d e | list_map λ a . 'echo $a$(echo $a | tr a-z A-Z)' +$ list a b s d e | map λ a . 'echo $a$(echo $a | tr a-z A-Z)' aA bB sS dD eE - -$ list 1 2 3 | list_map tee -1 -2 -3 ``` + +## *flat map* + +```bash +$ seq 2 3 | map λ a . 'seq 1 $a' | join , [ ] +[1,2,1,2,3] + +$ list a b c | map λ a . 'echo $a; echo $a | tr a-z A-z' | join , [ ] +[a,A,b,B,c,C] +``` + ## *filter* ```bash -$ seq 1 10 | filter even +$ seq 1 10 | filter λ a . '[[ $(mod $a 2) -eq 0 ]] && ret true || ret false' 2 4 6 @@ -109,6 +111,10 @@ $ seq 1 10 | filter even ```bash $ list a b c d | foldl λ acc el . 'echo -n $acc-$el' a-b-c-d + +$ list '' a b c d | foldr λ acc el .\ + 'if [[ ! -z $acc ]]; then echo -n $acc-$el; else echo -n $el; fi' +d-c-b-a ``` ```bash @@ -117,8 +123,11 @@ $ seq 1 4 | foldl λ acc el . 'echo $(($acc + $el))' ``` ```bash -$ seq 1 4 | foldl λ acc el . 'echo $(multiply $(($acc + 1)) $el)' +$ seq 1 4 | foldl λ acc el . 'echo $(mul $(($acc + 1)) $el)' 64 # 1 + (1 + 1) * 2 + (4 + 1) * 3 + (15 + 1) * 4 = 64 + +$ seq 1 4 | foldr λ acc el . 'echo $(mul $(($acc + 1)) $el)' +56 # 1 + (1 + 1) * 4 + (8 + 1) * 3 + (27 + 1) * 2 = 56 ``` ## *tup/tupx/tupl/tupr* @@ -131,16 +140,19 @@ $ tup 'foo bar' 1 'one' 2 (foo bar,1,one,2) $ tup , 1 3 -(,,1,3) +(u002c,1,3) ``` ```bash -$ echo tup a 1 | tupl +$ tupl $(tup a 1) a -$ echo tup a 1 | tupr +$ tupr $(tup a 1) 1 +$ tup , 1 3 | tupl +, + $ tup 'foo bar' 1 'one' 2 | tupl foo bar @@ -148,10 +160,39 @@ $ tup 'foo bar' 1 'one' 2 | tupr 2 ``` -## *list_zip* +```bash +$ tup 'foo bar' 1 'one' 2 | tupx 2 +1 + +$ tup 'foo bar' 1 'one' 2 | tupx 1,3 +foo bar +one + +$ tup 'foo bar' 1 'one' 2 | tupx 2-4 +1 +one +2 +``` + +## *buff* ```bash -$ list a b c d e f | list_zip $(seq 1 10) +$ seq 1 10 | buff λ a b . 'echo $(($a + $b))' +3 +7 +11 +15 +19 + +$ seq 1 10 | buff λ a b c d e . 'echo $(($a + $b + $c + $d + $e))' +15 +40 +``` + +## *zip* + +```bash +$ list a b c d e f | zip $(seq 1 10) (a,1) (b,2) (c,3) @@ -161,77 +202,60 @@ $ list a b c d e f | list_zip $(seq 1 10) ``` ```bash -$ list a b c d e f | list_zip $(seq 1 10) | list_last | tupr +$ list a b c d e f | zip $(seq 1 10) | last | tupr 6 ``` -## *not/isint/isempty* +## *curry* ```bash -$ isint 42 -true - -$ list blah | isint -false - -$ not true -false - -$ not "isint 777" -false - -$ list 1 2 "" c d 6 | filter λ a . 'isint $a' -1 -2 -6 - -$ list 1 2 "" c d 6 | filter λ a . 'not "isempty $a"' -1 -2 -c -d -6 +add2() { + echo $(($1 + $2)) +} ``` -## *isfile/isnonzerofile/isreadable/iswritable/isdir* - ```bash -$ touch /tmp/foo - -$ isfile /tmp/foo -true - -$ not iswritable / -true - -$ files="/etc/passwd /etc/sudoers /tmp /tmp/foo /no_such_file" - -$ list $files | filter λ a . 'isfile $a' -/etc/passwd -/etc/sudoers -/tmp/foo - -$ list $files | filter λ a . 'isdir $a' -/tmp - -$ list $files | filter λ a . 'isreadable $a' -/etc/passwd -/tmp -/tmp/foo - -$ list $files | filter λ a . 'iswritable $a' -/tmp -/tmp/foo - -$ list $files | filter λ a . 'isnonzerofile $a' -/etc/passwd -/etc/sudoers -/tmp - -$ list $files | filter λ a . 'not isfile $a' -/tmp -/no_such_file +$ curry inc add2 1 ``` + +```bash +$ inc 2 +3 + +$ seq 1 3 | map λ a . 'inc $a' +2 +3 +4 +``` + +## *try/catch* + +```bash +$ echo 'expr 2 / 0' | try λ _ . 'echo 0' +0 + +$ echo 'expr 2 / 0' | try λ status . 'echo $status' +2 + +$ echo 'expr 2 / 2' | try λ _ . 'echo 0' +1 +``` + +```bash +try λ _ . 'echo some errors during pull; exit 1' < <(echo git pull) +``` + +```bash +$ echo 'expr 2 / 0' \ + | LANG=en catch λ cmd status val . 'echo cmd=$cmd,status=$status,val=$val' +cmd=expr 2 / 0,status=2,val=(expr:,division,by,zero) +``` + +```bash +$ echo 'expr 2 / 2' | catch λ _ _ val . 'tupl $val' +1 +``` + ## *scanl* ```bash @@ -244,10 +268,58 @@ $ seq 1 5 | scanl lambda acc el . 'echo $(($acc + $el))' ``` ```bash -$ seq 1 5 | scanl lambda a b . 'echo $(($a + $b))' | list_last +$ seq 1 5 | scanl lambda a b . 'echo $(($a + $b))' | last 15 ``` +## *with_trampoline/res/call* + +```bash +factorial() { + fact_iter() { + local product=$1 + local counter=$2 + local max_count=$3 + if [[ $counter -gt $max_count ]]; then + res $product + else + call fact_iter $(echo $counter\*$product | bc) $(($counter + 1)) $max_count + fi + } + + with_trampoline fact_iter 1 1 $1 +} +``` + +```bash +$ time factorial 30 | fold -w 70 +265252859812191058636308480000000 + +real 0m1.854s +user 0m0.072s +sys 0m0.368s +``` + +```bash +time factorial 60 | fold -w 70 +8320987112741390144276341183223364380754172606361245952449277696409600 +000000000000 + +real 0m3.635s +user 0m0.148s +sys 0m0.692s +``` + +```bash +$ time factorial 90 | fold -w 70 +1485715964481761497309522733620825737885569961284688766942216863704985 +393094065876545992131370884059645617234469978112000000000000000000000 + +real 0m4.371s +user 0m0.108s +sys 0m0.436s +``` + # Examples ```bash @@ -260,7 +332,7 @@ processNames() { list $@ \ | filter λ name . '[[ ${#name} -gt 1 ]] && ret true || ret false' \ - | list_map λ name . 'uppercase $name' \ + | map λ name . 'uppercase $name' \ | foldl λ acc el . 'echo $acc,$el' } @@ -272,22 +344,7 @@ processNames adam monika s slawek d daniel Bartek j k Adam,Monika,Slawek,Daniel,Bartek ``` -# Running tests -TODO: Need to change the tests here -```bash -cd test -./test_runner -``` - -# Contribution guidelines - -Feel free to ask questions in chat, open issues, or contribute by creating pull requests. - -In order to create a pull request -* checkout master branch -* introduce your changes & bump version -* submit pull request # Resources * [Inspiration](https://quasimal.com/posts/2012-05-21-funsh.html) -* [Functional Programming in Bash](https://medium.com/@joydeepubuntu/functional-programming-in-bash-145b6db336b7) +* [Functional Programming in Bash](https://medium.com/@joydeepubuntu/functional-programming-in-bash-145b6db336b7) \ No newline at end of file diff --git a/examples/example.sh b/examples/example.sh index c30c455..80cb792 100755 --- a/examples/example.sh +++ b/examples/example.sh @@ -1,29 +1,30 @@ #!/bin/bash + source ../src/fun.sh seq 1 4 | sum seq 1 4 | product factorial 4 seq 1 4 | scanl lambda a b . 'echo $(add $a $b)' -echo map multiply -seq 1 4 | list_map lambda a . 'echo $(multiply $a 2)' -echo map minus -seq 1 4 | list_map lambda a . 'echo $(minus $a 2)' +echo map mul +seq 1 4 | map lambda a . 'echo $(mul $a 2)' +echo map sub +seq 1 4 | map lambda a . 'echo $(sub $a 2)' echo map add -seq 1 4 | list_map lambda a . 'echo $(add $a 2)' -echo map divide -seq 1 4 | list_map lambda a . 'echo $(divide $a 2)' -echo list_map mod -seq 1 4 | list_map lambda a . 'echo $(mod $a 2)' +seq 1 4 | map lambda a . 'echo $(add $a 2)' +echo map div +seq 1 4 | map lambda a . 'echo $(div $a 2)' +echo map mod +seq 1 4 | map lambda a . 'echo $(mod $a 2)' echo 'list & head' -list 1 2 3 4 5 | list_head -list {1..2} | list_append {3..4} | list_prepend {99..102} +list 1 2 3 4 5 | head +list {1..2} | append {3..4} | prepend {99..102} list {1..2} | unlist -list {1..10} | list_head -list {1..10} | list_drop 7 -list {1..10} | list_take 3 -list {1..10} | list_last -list {1..10} | list_map λ a . 'echo $(multiply $a 2)' +list {1..10} | head +list {1..10} | drop 7 +list {1..10} | take 3 +list {1..10} | last +list {1..10} | map λ a . 'echo $(mul $a 2)' id() { λ x . '$x' @@ -37,32 +38,122 @@ foobar() { list {1,2,3} | foobar -echo -n abcdefg | revers_str # gfedcba -echo -n abcdefg | splitc | list_join , # a,b,c,d,e,f,g -echo -n abcdefg | splitc | revers | list_join , # g,f,e,d,c,b,a +echo -n abcdefg | revers_str # gfedcba +echo -n abcdefg | splitc | join , '[' ']' # [a,b,c,d,e,f,g] +echo -n abcdefg | splitc | revers | join , '[' ']' # [g,f,e,d,c,b,a] -list {1..10} | filter lambda a . '[[ $(mod $a 2) -eq 0 ]] && ret true || ret false' | list_join , # 2,4,6,8,10 +echo -n ' abcdefg' | splitc | foldr lambda a b . 'echo $a$b' # gfedcba + +echo 'ls' | try λ cmd status ret . 'echo $cmd [$status]; echo $ret' + +list {1..10} | filter lambda a . '[[ $(mod $a 2) -eq 0 ]] && ret true || ret false' | join , '[' ']' # [2,4,6,8,10] + +function add() { + expr $1 + $2 +} + + +curry add3 add 3 +add3 9 list a b c d | foldl lambda acc el . 'echo -n $acc-$el' +list '' a b c d | foldr lambda acc el . 'if [[ ! -z $acc ]]; then echo -n $acc-$el; else echo -n $el; fi' + seq 1 4 | foldl lambda acc el . 'echo $(($acc + $el))' #1 - 2 - 3 - 4 seq 1 4 | foldl lambda acc el . 'echo $(($acc - $el))' +#1 - 4 - 3 - 2 +seq 1 4 | foldr lambda acc el . 'echo $(($acc - $el))' #1 + (1 + 1) * 2 + (4 + 1) * 3 + (15 + 1) * 4 = 64 -seq 1 4 | foldl lambda acc el . 'echo $(multiply $(($acc + 1)) $el)' + +seq 1 4 | foldl lambda acc el . 'echo $(mul $(($acc + 1)) $el)' + +#1 + (1 + 1) * 4 + (8 + 1) * 3 + (27 + 1) * 2 = 56 +seq 1 4 | foldr lambda acc el . 'echo $(mul $(($acc + 1)) $el)' tup a 1 +tupl $(tup a 1) +tupr $(tup a 1) tup a 1 | tupl tup a 1 | tupr -list a b c d e f | list_zip $(seq 1 10) +seq 1 10 | buff lambda a b . 'echo $(($a + $b))' +echo 'XX' +seq 1 10 | buff lambda a b c d e . 'echo $(($a + $b + $c + $d + $e))' + +list a b c d e f | zip $(seq 1 10) echo -list a b c d e f | list_zip $(seq 1 10) | list_last | tupr +list a b c d e f | zip $(seq 1 10) | last | tupr + +arg='[key1=value1,key2=value2,key3=value3]' +get() { + local pidx=$1 + local idx=$2 + local arg=$3 + echo $arg | tr -d '[]' | cut -d',' -f$idx | cut -d'=' -f$pidx +} + +curry get_key get 1 +curry get_value get 2 + +get_key 1 $arg +get_value 1 $arg + +seq 1 3 | map lambda a . 'tup $(get_key $a $arg) $(get_value $a $arg)' + +echo 'ls /home' | try λ cmd status ret . 'echo $cmd [$status]; echo $ret' +echo '/home' | try λ cmd status ret . 'echo $cmd [$status]; echo $ret' seq 1 5 | scanl lambda a b . 'echo $(($a + $b))' -seq 1 5 | scanl lambda a b . 'echo $(($a + $b))' | list_last +seq 1 5 | scanl lambda a b . 'echo $(($a + $b))' | last -seq 2 3 | list_map lambda a . 'seq 1 $a' | list_join , -list a b c | list_map lambda a . 'echo $a; echo $a | tr a-z A-z' | list_join , +seq 2 3 | map lambda a . 'seq 1 $a' | join , [ ] +list a b c | map lambda a . 'echo $a; echo $a | tr a-z A-z' | join , [ ] + +echo 0 | cat - <(curl -s https://raw.githubusercontent.com/ssledz/bash-fun/v1.1.1/src/fun.sh) | \ + map lambda a . 'list $a' | foldl lambda acc el . 'echo $(($acc + 1))' + +echo 0 | cat - <(curl -s curl -s https://raw.githubusercontent.com/ssledz/bash-fun/v1.1.1/src/fun.sh) \ + | foldl lambda acc el . 'echo $(($acc + 1))' + + +factorial() { + fact_iter() { + local product=$1 + local counter=$2 + local max_count=$3 + if [[ $counter -gt $max_count ]]; then + echo $product + else + fact_iter $(echo $counter\*$product | bc) $(($counter + 1)) $max_count + fi + } + + fact_iter 1 1 $1 +} + +factorial_trampoline() { + fact_iter() { + local product=$1 + local counter=$2 + local max_count=$3 + if [[ $counter -gt $max_count ]]; then + res $product + else + call fact_iter $(echo $counter\*$product | bc) $(($counter + 1)) $max_count + fi + } + + with_trampoline fact_iter 1 1 $1 +} + +echo Factorial test + +time factorial 30 +time factorial_trampoline 30 + +time factorial 60 +time factorial_trampoline 60 \ No newline at end of file diff --git a/release.sh b/release.sh new file mode 100755 index 0000000..219af38 --- /dev/null +++ b/release.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +version=$(cat .version) + +release_version=${version%%-SNAPSHOT} +new_version=$(echo $release_version+0.1 | bc) + +[[ $? -ne 0 ]] && echo 'Error exiting.' && exit 1 + +snapshot_version=${new_version}-SNAPSHOT + +cat < ./.version +git add ./.version +git commit -m "[release] prepare release v$release_version" +git tag v$release_version +echo $snapshot_version > ./.version +git add ./.version +git commit -m "[release] prepare for next development iteration" + +echo merge the version back into develop +git checkout develop +git merge --no-ff -m "[release] merge release/$release_version into develop" release/$release_version + +git checkout master +echo merge the version back into master but use the tagged version instead of the release/$releaseVersion HEAD +git merge --no-ff -m "[release] merge previous version into master to avoid the increased version number" release/$release_version~1 + +echo get back on the develop branch +git checkout develop +echo finally push everything +git push origin develop master +git push --tags +echo removing the release branch +git branch -D release/$release_version diff --git a/src/fun.sh b/src/fun.sh old mode 100644 new mode 100755 index 533dd10..d0b3af8 --- a/src/fun.sh +++ b/src/fun.sh @@ -1,553 +1,318 @@ -#!/bin/sh +#!/bin/bash + +drop() { + command tail -n +$(($1 + 1)) +} + +take() { + command head -n ${1} +} + +tail() { + drop 1 +} + +head() { + take 1 +} + +last() { + command tail -n 1 +} -############################################### -## List Functions -############################################### list() { - for i in "$@"; do - echo "$i" - done + for i in "$@"; do + echo "$i" + done } unlist() { - xargs + cat - | xargs } -# Drop the first n items of a list. -list_drop() { - command tail -n +$(($1 + 1)) +append() { + cat - + list "$@" } -# Take the first n items of a list. -list_take() { - command head -n "$1" +prepend() { + list "$@" + cat - } -# Take the 'tail' of a list. -# Otherwise known as dropping the first element. -list_tail() { - list_drop 1 -} -# Take only the first element of the list. -list_head() { - list_take 1 -} - -# Take the last element of the list. -list_last() { - command tail -n 1 -} - -# Add the contents of standard input -# to the end of the list. -list_append() { - cat - - list "$@" -} - -# Add the contents of standard input -# to the beginning of the list. -list_prepend() { - list "$@" - cat - -} - -############################################### -## Lambdas and Lists -############################################### -# Defines an anonymous function. lambda() { - # shellcheck disable=2039 - local expression - lam() { - # shellcheck disable=2039 - local arg - while [ $# -gt 0 ]; do - arg="$1" - shift - if [ "$arg" = '.' ]; then - echo "$@" - return - else - echo "read $arg;" - fi - done - } - expression=$(lam "$@") - eval "$expression" + lam() { + local arg + while [[ $# -gt 0 ]]; do + arg="$1" + shift + if [[ $arg = '.' ]]; then + echo "$@" + return + else + echo "read $arg;" + fi + done + } + + eval $(lam "$@") + } -# Same as lambda. -# shellcheck disable=2039 λ() { - lambda "$@" + lambda "$@" } -# Print the number of arguments a lambda takes. -# shellcheck disable=2039 -λ_num_args() { - # Calculates the number of arguments a lambda takes - minus "$#" 3 +map() { + local x + while read x; do + echo "$x" | "$@" + done } -# Perform an operation to each -# element(s) of a list provided -# through standard input. -list_map() { - # shellcheck disable=2039 - local x - # shellcheck disable=2039 - local i - # shellcheck disable=2039 - local arguments - # shellcheck disable=2039 - local num_args - if [ "$1" = "λ" ] || [ "$1" = "lambda" ]; then - num_args=$(λ_num_args "$@") - while read -r x; do - arguments="$x" - i=2 - while [ $i -le "$num_args" ] ; do - read -r x - arguments="$arguments $x" - i=$(add $i 1) - done - # We want to word split arguments, so no quotes - eval "list $arguments" | "$@" - done - else # Do not know the arity, assume 1 - while read -r x; do - echo "$x" | "$@" - done - fi -} - -# Perform a binary operation on a list -# where one element is the accumulation -# of the results so far. -# Ex: seq 3 | foldl lambda a b . 'minus $a $b' -# First is (1 - 2 = -1) then (-1 - 3 = -4). foldl() { - # shellcheck disable=2039 - local acc - read -r acc - while read -r elem; do - acc=$({ echo "$acc"; echo "$elem"; } | "$@" ) - done - echo "$acc" + local f="$@" + local acc + read acc + while read elem; do + acc="$({ echo $acc; echo $elem; } | $f )" + done + echo "$acc" +} + +foldr() { + local f="$@" + local acc + local zero + read zero + foldrr() { + local elem + + if read elem; then + acc=$(foldrr) +# [[ -z $acc ]] && echo $elem && return + else + echo $zero && return + fi + + acc="$({ echo $acc; echo $elem; } | $f )" + echo "$acc" + } + + foldrr } -# Constructs a list where each element -# is the foldl of the 0th-ith elements of -# the list. scanl() { - # shellcheck disable=2039 - local acc - read -r acc + local f="$@" + local acc + read acc + echo $acc + while read elem; do + acc="$({ echo $acc; echo $elem; } | $f )" echo "$acc" - while read -r elem; do - acc=$({ echo "$acc"; echo "$elem"; } | "$@" ) - echo "$acc" - done + done } -# Drops any elements of the list where the -# function performed on it evaluates to false. -filter() { - # shellcheck disable=2039 - local x - while read -r x; do - ret=$(echo "$x" | "$@") - if_then "$ret" "echo $x" - done +mul() { + ( set -f; echo $(($1 * $2)) ) } -# Keep taking elements until a certain condition -# is false. -take_while() { - # shellcheck disable=2039 - local x - # shellcheck disable=2039 - local condition - while read -r x; do - condition="$(echo "$x" | "$@")" - if_then_else "$condition" "echo $x" "break" - done +plus() { + echo $(($1 + $2)) } -# Keep dropping elements until a certain condition -# is false. -drop_while() { - # shellcheck disable=2039 - local x - while read -r x; do - condition="$(echo "$x" | "$@")" - if_then_else "$condition" 'do_nothing' 'break' - done - if_then "[ -n $x ]" "{ echo $x; cat -; }" +sub() { + echo $(($1 - $2)) } - -############################################### -## Arithmetic Functions -############################################### -multiply() { - # shellcheck disable=2039 - local a - # shellcheck disable=2039 - local b - a=$1 - if [ $# -lt 2 ] ; then - read -r b - else - b=$2 - fi - isint "$a" > /dev/null && \ - isint "$b" > /dev/null && \ - echo $((a * b)) -} - -add() { - # shellcheck disable=2039 - local a - # shellcheck disable=2039 - local b - a=$1 - if [ $# -lt 2 ] ; then - read -r b - else - b=$2 - fi - isint "$a" > /dev/null && \ - isint "$b" > /dev/null && \ - echo $((a + b)) -} - -minus() { - # shellcheck disable=2039 - local a - # shellcheck disable=2039 - local b - a=$1 - if [ $# -lt 2 ] ; then - b=$1 - read -r a - else - b=$2 - fi - isint "$a" > /dev/null && \ - isint "$b" > /dev/null && \ - echo $((a - b)) -} - -divide() { - # shellcheck disable=2039 - local a - # shellcheck disable=2039 - local b - a=$1 - if [ $# -lt 2 ] ; then - b=$1 - read -r a - else - b=$2 - fi - isint "$a" > /dev/null && \ - isint "$b" > /dev/null && \ - echo $((a / b)) +div() { + echo $(($1 / $2)) } mod() { - # shellcheck disable=2039 - local a - # shellcheck disable=2039 - local b - a=$1 - if [ $# -lt 2 ] ; then - b=$1 - read -r a - else - b=$2 - fi - isint "$a" > /dev/null && \ - isint "$b" > /dev/null && \ - echo $((a % b)) + echo $(($1 % $2)) } -even() { - # shellcheck disable=2039 - local n - # shellcheck disable=2039 - local result - # shellcheck disable=2039 - local result_code - if [ $# -lt 1 ] ; then - read -r n - else - n=$1 - fi - result=$(mod "$n" 2) - result_code=$? - if [ $result_code -ne 0 ] ; then - ret false - else - result_to_bool "[ $result = 0 ]" - fi -} - -odd() { - not even -} - -less_than() { - # shellcheck disable=2039 - local n - read -r n - if isint "$n" > /dev/null && \ - [ "$n" -lt "$1" ] ; then - ret true - else - ret false - fi -} sum() { - foldl lambda a b . "add \$a \$b" + foldl lambda a b . 'echo $(($a + $b))' } product() { - foldl lambda a b . "multiply \$a \$b" + foldl lambda a b . 'echo $(mul $a $b)' } factorial() { - seq 1 "$1" | product + seq 1 $1 | product } -############################################### -## String Operations -############################################### -# Splits a string into a list where each element -# is one character. splitc() { - sed 's/./\n&/g' | list_tail + cat - | sed 's/./&\n/g' } -# Takes a list and creates a string where -# each element is seperated by a delimiter. -list_join() { - # shellcheck disable=2039 - local delim - delim=$1 - foldl lambda a b . "echo \$a$delim\$b" +join() { + local delim=$1 + local pref=$2 + local suff=$3 + echo $pref$(cat - | foldl lambda a b . 'echo $a$delim$b')$suff } -# Split a string into a list -# by a specified delimeter -str_split() { - sed "s/$1/\n/g" -} - -# Reverses a list. revers() { - # shellcheck disable=2039 - local result - # shellcheck disable=2039 - local n - while read -r n; do - result="$n\n$result" - done - echo "$result" + foldl lambda a b . 'append $b $a' } -# Reverses a string revers_str() { - splitc | revers | list_join + cat - | splitc | revers | join } -# Removes multiple occurences of -# a single character from the beginning -# of the list. -lstrip() { - # shellcheck disable=2039 - local c - if [ $# -eq 0 ] ; then - c=" " - else - c="$1" - fi - sed "s/^$c*//g" +catch() { + local f="$@" + local cmd=$(cat -) + local val=$(2>&1 eval "$cmd"; echo $?) + local cnt=$(list $val | wc -l) + local status=$(list $val | last) + $f < <(list "$cmd" $status $(list $val | take $((cnt - 1)) | unlist | tup)) } -# Removes multiple occurences of -# a single character from the end -# of the list. -rstrip() { - # shellcheck disable=2039 - local c - if [ $# -eq 0 ] ; then - c=" " - else - c="$1" - fi - sed "s/$c*$//g" -} - -# Removes multiple occurences of -# a single character from the beginning -# and end of the list. -strip() { - lstrip "$@" | rstrip "$@" -} - -############################################### -## Tuple Functions -############################################### - -# Creates a tuple, which is a string with -# multiple elements seperated by a comma, -# and it begins with a ( and ends with a ). -tup() { - # shellcheck disable=2039 - local args - # shellcheck disable=2039 - local result - if [ $# -eq 0 ]; then - args=$(unlist) - eval "tup $args" - else - result=$(list "$@" | list_join ,) - echo "($result)" - fi -} - -# Takes a tuple and outputs it as a list -tup_to_list() { - local li - local f - local la - li=$(str_split ",") - - # Remove '(' from the first element - f=$(echo "$li" | list_head) - f=$(echo "$f" | sed 's/^(//') - - la=$(echo "$li" | list_last) - # If there is only one element in the list - # Remove ')' from the only element - if [ "$(echo "$la" | cut -c1)" = "(" ]; then - f=$(echo "$f" | sed "s/)$//") - echo "$f" - # If there is more than one element in the list - # Remove ')' from the last element - else - la=$(echo "$la" | sed "s/)$//") - # Remove the first and last element from li - li=$(echo "$li" | list_tail | sed '$d') - # Print the list - { echo "$f"; echo "$li"; echo "$la"; } - fi -} - -# Takes the first element of the tuple -tupl() { - tup_to_list | list_head -} - -# Takes the last element of the tuple -tupr() { - tup_to_list | list_last -} - - -# Takes each element from a list in standard -# input and matches it with a list provided -# as the argument to this function. -# The result is a list of 2-tuples. -list_zip() { - # shellcheck disable=2039 - local l - l=$(list "$@") - while read -r x; do - y=$(echo "$l" | list_take 1) - tup "$x" "$y" - l=$(echo "$l" | list_drop 1) - done -} - -############################################### -## Logic Based Functions -############################################### - -if_then() { - # shellcheck disable=2039 - local result - eval "$1" - result=$? - if [ $result -eq 0 ] ; then - eval "$2" - fi -} - -if_then_else() { - # shellcheck disable=2039 - local result - eval "$1" - result=$? - if [ $result -eq 0 ] ; then - eval "$2" - else - eval "$3" - fi -} - -result_to_bool() { - if_then_else "$1" 'ret true' 'ret false' -} - -not() { - if_then_else "$1 > /dev/null" "ret false" "ret true" +try() { + local f="$@" + catch lambda cmd status val . '[[ $status -eq 0 ]] && tupx 1- $val | unlist || { '"$f"' < <(list $status); }' } ret() { - echo "$@" - "$@" + echo $@ } -do_nothing() { - echo > /dev/null +filter() { + local x + while read x; do + ret=$(echo "$x" | "$@") + $ret && echo $x + done } - -############################################### -## Useful utility functions -############################################### - -isint() { - result_to_bool "echo \"$1\" | grep -Eq '^-?[0-9]+$'" +pass() { + echo > /dev/null } -isempty() { - result_to_bool "[ -z \"$1\" ]" +dropw() { + local x + while read x && $(echo "$x" | "$@"); do + pass + done + [[ ! -z $x ]] && { echo $x; cat -; } } -isfile() { - result_to_bool "[ -f \"$1\" ]" +peek() { + local x + while read x; do + ([ $# -eq 0 ] && 1>&2 echo $x || 1>&2 "$@" < <(echo $x)) + echo $x + done } -isnonzerofile() { - result_to_bool "[ -s \"$1\" ]" +stripl() { + local arg=$1 + cat - | map lambda l . 'ret ${l##'$arg'}' } -isreadable() { - result_to_bool "[ -r \"$1\" ]" +stripr() { + local arg=$1 + cat - | map lambda l . 'ret ${l%%'$arg'}' } -iswritable() { - result_to_bool "[ -w \"$1\" ]" +strip() { + local arg=$1 + cat - | stripl "$arg" | stripr "$arg" } -isdir() { - result_to_bool "[ -d \"$1\" ]" +buff() { + local cnt=-1 + for x in $@; do + [[ $x = '.' ]] && break + cnt=$(plus $cnt 1) + done + local args='' + local i=$cnt + while read arg; do + [[ $i -eq 0 ]] && list $args | "$@" && i=$cnt && args='' + args="$args $arg" + i=$(sub $i 1) + done + [[ ! -z $args ]] && list $args | "$@" +} + +tup() { + if [[ $# -eq 0 ]]; then + local arg + read arg + tup $arg + else + list "$@" | map lambda x . 'echo ${x/,/u002c}' | join , '(' ')' + fi +} + +tupx() { + if [[ $# -eq 1 ]]; then + local arg + read arg + tupx "$1" "$arg" + else + local n=$1 + shift + echo "$@" | stripl '(' | stripr ')' | cut -d',' -f${n} | tr ',' '\n' | map lambda x . 'echo ${x/u002c/,}' + fi +} + +tupl() { + tupx 1 "$@" +} + +tupr() { + tupx 1- "$@" | last +} + +zip() { + local list=$* + cat - | while read x; do + y=$(list $list | take 1) + tup $x $y + list=$(list $list | drop 1) + done +} + +curry() { + exportfun=$1; shift + fun=$1; shift + params=$* + cmd=$"function $exportfun() { + more_params=\$*; + $fun $params \$more_params; + }" + eval $cmd +} + +with_trampoline() { + local f=$1; shift + local args=$@ + while [[ $f != 'None' ]]; do + ret=$($f $args) +# echo $ret + f=$(tupl $ret) + args=$(echo $ret | tupx 2- | tr ',' ' ') + done + echo $args +} + +res() { + local value=$1 + tup "None" $value +} + +call() { + local f=$1; shift + local args=$@ + tup $f $args } diff --git a/test/append_test.sh b/test/append_test.sh index 2ee28fc..e6ceb99 100755 --- a/test/append_test.sh +++ b/test/append_test.sh @@ -1,15 +1,15 @@ #! /bin/bash testAppendToEmptyList() { - assertEquals 4 "$(list | list_append 4)" + assertEquals 4 "$(list | append 4)" } testAppendToOneElementList() { - assertEquals "1 4" "$(list 1 | list_append 4 | unlist)" + assertEquals "1 4" "$(list 1 | append 4 | unlist)" } testAppendToList() { - assertEquals "1 2 3 4 5 4" "$(list 1 2 3 4 5 | list_append 4 | unlist)" + assertEquals "1 2 3 4 5 4" "$(list 1 2 3 4 5 | append 4 | unlist)" } . ./shunit2-init.sh \ No newline at end of file diff --git a/test/catch_test.sh b/test/catch_test.sh new file mode 100755 index 0000000..b3f0917 --- /dev/null +++ b/test/catch_test.sh @@ -0,0 +1,19 @@ +#! /bin/bash + +testCatchIfSuccess() { + assertEquals 1 "$(echo 'expr 2 / 2' | catch lambda cmd status val . '[[ $status -eq 0 ]] && tupl $val || echo 0')" +} + +testCatchIfError() { + assertEquals 0 $(echo 'expr 2 / 0' | catch lambda cmd status val . '[[ $status -eq 0 ]] && tupl $val || echo 0') + assertEquals 'cmd=expr 2 / 0,status=2,val=(expr:,division,by,zero)' "$(echo 'expr 2 / 0' | echo 'expr 2 / 0' | LANG=en catch lambda cmd status val . 'echo cmd=$cmd,status=$status,val=$val')" +} + +testCatchEdgeCases() { + assertEquals 1 "$(echo 'expr 2 / 2' | catch lambda _ _ val . 'tupl $val')" + assertEquals 'expr 2 / 2' "$(echo 'expr 2 / 2' | catch lambda cmd . 'ret $cmd')" + assertEquals 'expr 2 / 2,0' "$(echo 'expr 2 / 2' | catch lambda cmd status . 'ret $cmd,$status')" + assertEquals 'expr 2 / 0,2' "$(echo 'expr 2 / 0' | catch lambda cmd status . 'ret $cmd,$status')" +} + +. ./shunit2-init.sh \ No newline at end of file diff --git a/test/drop_test.sh b/test/drop_test.sh index 7195d48..5aef523 100755 --- a/test/drop_test.sh +++ b/test/drop_test.sh @@ -1,23 +1,23 @@ #! /bin/bash testDrop9From10() { - assertEquals 10 $(list {1..10} | list_drop 9) + assertEquals 10 $(list {1..10} | drop 9) } testDrop8From10() { - assertEquals "9 10" "$(list {1..10} | list_drop 8 | unlist)" + assertEquals "9 10" "$(list {1..10} | drop 8 | unlist)" } testDropAll() { - assertEquals "" "$(list {1..10} | list_drop 10)" + assertEquals "" "$(list {1..10} | drop 10)" } testDropMoreThanAvailable() { - assertEquals "" "$(list {1..10} | list_drop 15)" + assertEquals "" "$(list {1..10} | drop 15)" } testDropZero() { - assertEquals "1 2 3 4 5 6 7 8 9 10" "$(list {1..10} | list_drop 0 | unlist)" + assertEquals "1 2 3 4 5 6 7 8 9 10" "$(list {1..10} | drop 0 | unlist)" } . ./shunit2-init.sh \ No newline at end of file diff --git a/test/head_test.sh b/test/head_test.sh index 0293890..3ea2a7f 100755 --- a/test/head_test.sh +++ b/test/head_test.sh @@ -1,16 +1,16 @@ #! /bin/bash -testLHeadFromList() { - assertEquals 1 $(list {1..10} | list_head) - assertEquals 5 $(list 5 6 7 | list_head) +testHeadFromList() { + assertEquals 1 $(list {1..10} | head) + assertEquals 5 $(list 5 6 7 | head) } -testLHeadFromOneElementList() { - assertEquals 1 $(list 1 | list_head) +testHeadFromOneElementList() { + assertEquals 1 $(list 1 | head) } -testLHeadFromEmptyList() { - assertEquals "" "$(list | list_head)" +testHeadFromEmptyList() { + assertEquals "" "$(list | head)" } -. ./shunit2-init.sh +. ./shunit2-init.sh \ No newline at end of file diff --git a/test/last_test.sh b/test/last_test.sh index e10ec36..e76a694 100755 --- a/test/last_test.sh +++ b/test/last_test.sh @@ -1,16 +1,16 @@ #! /bin/bash testLastFromList() { - assertEquals 10 $(list {1..10} | list_last) - assertEquals 7 $(list 5 6 7 | list_last) + assertEquals 10 $(list {1..10} | last) + assertEquals 7 $(list 5 6 7 | last) } testLastFromOneElementList() { - assertEquals 1 $(list 1 | list_last) + assertEquals 1 $(list 1 | last) } testLastFromEmptyList() { - assertEquals "" "$(list | list_last)" + assertEquals "" "$(list | last)" } . ./shunit2-init.sh \ No newline at end of file diff --git a/test/map_test.sh b/test/map_test.sh index 383a8a8..b34217c 100755 --- a/test/map_test.sh +++ b/test/map_test.sh @@ -1,33 +1,33 @@ #!/bin/bash testMapEmptyList() { - assertEquals "" "$(list | list_map lambda x . 'echo $(($x + 1))')" + assertEquals "" "$(list | map lambda x . 'echo $(($x + 1))')" } testMapEmptyList_ifNoArgumentsInLambda() { - assertEquals "" "$(list | list_map lambda . 'echo 3')" + assertEquals "" "$(list | map lambda . 'echo 3')" } testMapOneElementList() { - assertEquals "3" "$(list 2 | list_map lambda x . 'echo $(($x + 1))')" + assertEquals "3" "$(list 2 | map lambda x . 'echo $(($x + 1))')" } testMapList() { - assertEquals "2 3 4 5 6" "$(list {1..5} | list_map lambda x . 'echo $(($x + 1))' | unlist)" + assertEquals "2 3 4 5 6" "$(list {1..5} | map lambda x . 'echo $(($x + 1))' | unlist)" } testMapList_ifNoArgumentsInLambda() { - assertEquals "9 9 9 9 9" "$(list {1..5} | list_map lambda . 'echo 9' | unlist)" + assertEquals "9 9 9 9 9" "$(list {1..5} | map lambda . 'echo 9' | unlist)" } testMapList_ifManyArgumentsInLambda() { - list {1..5} | list_map lambda x y . 'echo $(($x + $y))' 2> /dev/null \ + list {1..5} | map lambda x y . 'echo $(($x + $y))' 2> /dev/null \ && fail "There should be syntax error, because map is an one argument operation" } testFlatMap() { - assertEquals "1 2 3 2 3 3" "$(list {1..3} | list_map lambda x . 'seq $x 3' | unlist)" - assertEquals "d e h l l l o o r w" "$(list hello world | list_map lambda x . 'command fold -w 1 <<< $x' | sort | unlist)" + assertEquals "1 2 3 2 3 3" "$(list {1..3} | map lambda x . 'seq $x 3' | unlist)" + assertEquals "d e h l l l o o r w" "$(list hello world | map lambda x . 'command fold -w 1 <<< $x' | sort | unlist)" } . ./shunit2-init.sh \ No newline at end of file diff --git a/test/predicates_test.sh b/test/predicates_test.sh deleted file mode 100755 index 5e96337..0000000 --- a/test/predicates_test.sh +++ /dev/null @@ -1,52 +0,0 @@ -#! /bin/bash - -testIsint() { - assertEquals 'true' $(isint 1) - assertEquals 'true' $(isint -1) - assertEquals 'false' $(isint a) - assertEquals 'false' $(isint "") - assertEquals '1 2 3 4 5' "$(list 1 a 2 b 3 c 4 d 5 e | filter lambda x . 'isint $x' | unlist )" - assertEquals '1 2' "$(list 1 a 2 b 3 c 4 d 5 e | filter lambda x . '($(isint $x) && [[ $x -le 2 ]] && ret true) || ret false ' | unlist )" - - assertEquals 'false' $(not "isint 1") - assertEquals 'true' $(not "isint a") -} - -testIsempty() { - assertEquals 'true' $(isempty "") - assertEquals 'false' $(isempty a) - - assertEquals 'true' $(not "isempty a") - assertEquals 'false' $(not "isempty \"\"") -} - -testIsfile() { - f=$(mktemp) - - assertEquals 'true' $(isfile $f) - assertEquals 'false' $(isfile $f.xxx) - assertEquals 'false' $(isfile "") - assertEquals 'true' $(not "isfile $f.xxx") - - assertEquals 'false' $(isnonzerofile $f) - echo hello world >$f - assertEquals 'true' $(isnonzerofile $f) - - assertEquals 'true' $(iswritable $f) - chmod 400 $f - assertEquals 'false' $(iswritable $f) - - assertEquals 'true' $(isreadable $f) - chmod 200 $f - assertEquals 'false' $(isreadable $f) - - chmod 600 $f - rm $f -} - -testIsdir() { - assertEquals 'true' $(isdir .) - assertEquals 'false' $(isdir sir_not_appearing_in_this_film) -} - -. ./shunit2-init.sh diff --git a/test/prepend_test.sh b/test/prepend_test.sh index 491a56e..8e9e3a0 100755 --- a/test/prepend_test.sh +++ b/test/prepend_test.sh @@ -1,15 +1,15 @@ #! /bin/bash testPrependToEmptyList() { - assertEquals 4 "$(list | list_prepend 4)" + assertEquals 4 "$(list | prepend 4)" } testPrependToOneElementList() { - assertEquals "4 1" "$(list 1 | list_prepend 4 | unlist)" + assertEquals "4 1" "$(list 1 | prepend 4 | unlist)" } testPrependToList() { - assertEquals "4 1 2 3 4 5" "$(list 1 2 3 4 5 | list_prepend 4 | unlist)" + assertEquals "4 1 2 3 4 5" "$(list 1 2 3 4 5 | prepend 4 | unlist)" } . ./shunit2-init.sh \ No newline at end of file diff --git a/test/tail_test.sh b/test/tail_test.sh index f6c11e6..57971ad 100755 --- a/test/tail_test.sh +++ b/test/tail_test.sh @@ -1,15 +1,15 @@ #! /bin/bash -testLTailFrom10() { - assertEquals "2 3 4 5 6 7 8 9 10" "$(list {1..10} | list_tail | unlist)" +testTailFrom10() { + assertEquals "2 3 4 5 6 7 8 9 10" "$(list {1..10} | tail | unlist)" } -testLTailFromOneElementList() { - assertEquals "" "$(list 1 | list_tail)" +testTailFromOneElementList() { + assertEquals "" "$(list 1 | tail)" } -testLTailFromEmptyList() { - assertEquals "" "$(list | list_tail)" +testTailFromEmptyList() { + assertEquals "" "$(list | tail)" } -. ./shunit2-init.sh +. ./shunit2-init.sh \ No newline at end of file diff --git a/test/take_test.sh b/test/take_test.sh index 5b0cb49..efd48ef 100755 --- a/test/take_test.sh +++ b/test/take_test.sh @@ -1,23 +1,23 @@ #! /bin/bash testTake9From10() { - assertEquals "1 2 3 4 5 6 7 8 9" "$(list {1..10} | list_take 9 | unlist)" + assertEquals "1 2 3 4 5 6 7 8 9" "$(list {1..10} | take 9 | unlist)" } testTake8From10() { - assertEquals "1 2 3 4 5 6 7 8" "$(list {1..10} | list_take 8 | unlist)" + assertEquals "1 2 3 4 5 6 7 8" "$(list {1..10} | take 8 | unlist)" } testTakeAll() { - assertEquals "1 2 3 4 5 6 7 8 9 10" "$(list {1..10} | list_take 10 | unlist)" + assertEquals "1 2 3 4 5 6 7 8 9 10" "$(list {1..10} | take 10 | unlist)" } testTakeMoreThanAvailable() { - assertEquals "1 2 3 4 5 6 7 8 9 10" "$(list {1..10} | list_take 15 | unlist)" + assertEquals "1 2 3 4 5 6 7 8 9 10" "$(list {1..10} | take 15 | unlist)" } testTakeZero() { - assertEquals "" "$(list {1..10} | list_take 0 | unlist)" + assertEquals "" "$(list {1..10} | take 0 | unlist)" } . ./shunit2-init.sh \ No newline at end of file diff --git a/test/try_test.sh b/test/try_test.sh new file mode 100755 index 0000000..be1aeb3 --- /dev/null +++ b/test/try_test.sh @@ -0,0 +1,11 @@ +#! /bin/bash + +testTry() { + assertEquals 1 "$(echo 'expr 2 / 2' | try lambda _ . 'ret 0')" + assertEquals 0 "$(echo 'expr 2 / 0' | try lambda _ . 'ret 0')" + assertEquals 2 "$(echo 'expr 2 / 0' | try lambda status . 'ret $status')" + assertEquals 'already up to date' "$(echo 'echo already up to date' | try lambda _ . 'ret error')" + assertEquals 'error exit 1' "$(try λ _ . 'echo "error"; echo exit 1' < <(echo fgit pull) | unlist)" +} + +. ./shunit2-init.sh \ No newline at end of file diff --git a/test/tup_test.sh b/test/tup_test.sh index 71f1b05..bdd5ac1 100755 --- a/test/tup_test.sh +++ b/test/tup_test.sh @@ -8,8 +8,7 @@ testTupIfOneElement() { assertEquals '(1)' $(tup 1) assertEquals '(")' $(tup '"') assertEquals "(')" $(tup "'") - assertEquals "(,)" $(tup ",") - assertEquals "(,,)" $(tup ",,") + assertEquals "(u002c)" $(tup ",") assertEquals "(()" $(tup "(") assertEquals "())" $(tup ")") } @@ -20,10 +19,40 @@ testTupHappyPath() { assertEquals '(a b,c d e,f)' "$(tup 'a b' 'c d e' 'f')" } +testTupxHappyPath() { + assertEquals '4' $(tup 4 5 1 4 | tupx 1) + assertEquals '5' $(tup 4 5 1 4 | tupx 2) + assertEquals '1' $(tup 4 5 1 4 | tupx 3) + assertEquals '4' $(tup 4 5 1 4 | tupx 4) + +} + +testTupxIfEmpty() { + assertEquals '' "$(tup '' | tupx 1)" + assertEquals '' "$(tup '' | tupx 5)" +} + testTupxIfZeroIndex() { assertEquals '' "$(tup 1 3 | tupx 0 2>/dev/null)" } +testTupxIfSpecialChars() { + assertEquals ',' "$(tup ',' | tupx 1)" + assertEquals '(' "$(tup '(' | tupx 1)" + assertEquals ')' "$(tup ')' | tupx 1)" + assertEquals '()' "$(tup '()' | tupx 1)" + assertEquals '(' "$(tup '(' ')' | tupx 1)" + assertEquals '(' "$(tup '(' '(' | tupx 1)" + assertEquals ')' "$(tup ')' ')' | tupx 1)" + assertEquals ',' "$(tup 'u002c' | tupx 1)" +} + +testTupxRange() { + assertEquals '4 5' "$(tup 4 5 1 4 | tupx 1-2 | unlist)" + assertEquals '4 4' "$(tup 4 5 1 4 | tupx 1,4 | unlist)" + assertEquals '4 5 4' "$(tup 4 5 1 4 | tupx 1,2,4 | unlist)" +} + testTupl() { assertEquals '4' "$(tup 4 5 | tupl)" assertEquals '4' "$(tup 4 5 6 | tupl)" @@ -37,4 +66,4 @@ testTupr() { assertEquals '5' "$(tup 5 | tupr)" } -. ./shunit2-init.sh +. ./shunit2-init.sh \ No newline at end of file