diff --git a/.version b/.version index 879b416..f9fe6b4 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -2.1 +2.5b diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..cf8e84f --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +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 03d5783..15673cd 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,15 @@ # Introduction -[Introduction to fun.sh library](http://ssledz.github.io/presentations/bash-fun.html#/) +This is a fork of [ssledz's fun.sh library](https://github.com/ssledz/bash-fun). +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/ssledz/bash-fun/master/src/fun.sh > fun.sh; cat fun.sh) +. <(test -e fun.sh || curl -Ls https://raw.githubusercontent.com/brandon-rozek/bash-fun/master/src/fun.sh > fun.sh; cat fun.sh) seq 1 4 | sum ``` @@ -14,13 +17,17 @@ seq 1 4 | sum # Functions overview ||||||| |------|------|------|------|------|------| -|**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_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**|**λ**| + ## *list/unlist* @@ -34,25 +41,25 @@ $ list 1 2 3 4 5 | unlist 1 2 3 4 5 ``` -## *take/drop/tail/head/last* +## *list_take/list_drop/list_tail/list_head/list_last* ```bash -$ list 1 2 3 4 | drop 2 +$ list 1 2 3 4 | list_drop 2 3 4 -$ list 1 2 3 4 5 | head +$ list 1 2 3 4 5 | list_head 1 -$ list 1 2 3 4 | tail +$ list 1 2 3 4 | list_tail 2 3 4 -$ list 1 2 3 4 5 | last +$ list 1 2 3 4 5 | list_last 5 -$ list 1 2 3 4 5 | take 2 +$ list 1 2 3 4 5 | list_take 2 1 2 ``` @@ -60,45 +67,36 @@ $ list 1 2 3 4 5 | take 2 ## *join* ```bash -$ list 1 2 3 4 5 | join , +$ list 1 2 3 4 5 | list_join , 1,2,3,4,5 - -$ list 1 2 3 4 5 | join , [ ] -[1,2,3,4,5] ``` ## *map* ```bash -$ seq 1 5 | map λ a . 'echo $((a + 5))' +$ seq 1 5 | list_map λ a . 'echo $((a + 5))' 6 7 8 9 10 -$ list a b s d e | map λ a . 'echo $a$(echo $a | tr a-z A-Z)' +$ list a b s d e | list_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 λ a . '[[ $(mod $a 2) -eq 0 ]] && ret true || ret false' +$ seq 1 10 | filter even 2 4 6 @@ -111,10 +109,6 @@ $ seq 1 10 | filter λ a . '[[ $(mod $a 2) -eq 0 ]] && ret true || ret false' ```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 @@ -123,11 +117,8 @@ $ seq 1 4 | foldl λ acc el . 'echo $(($acc + $el))' ``` ```bash -$ seq 1 4 | foldl λ acc el . 'echo $(mul $(($acc + 1)) $el)' +$ seq 1 4 | foldl λ acc el . 'echo $(multiply $(($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* @@ -140,19 +131,16 @@ $ tup 'foo bar' 1 'one' 2 (foo bar,1,one,2) $ tup , 1 3 -(u002c,1,3) +(,,1,3) ``` ```bash -$ tupl $(tup a 1) +$ echo tup a 1 | tupl a -$ tupr $(tup a 1) +$ echo tup a 1 | tupr 1 -$ tup , 1 3 | tupl -, - $ tup 'foo bar' 1 'one' 2 | tupl foo bar @@ -160,39 +148,10 @@ $ tup 'foo bar' 1 'one' 2 | tupr 2 ``` -```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* +## *list_zip* ```bash -$ 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) +$ list a b c d e f | list_zip $(seq 1 10) (a,1) (b,2) (c,3) @@ -202,60 +161,77 @@ $ list a b c d e f | zip $(seq 1 10) ``` ```bash -$ list a b c d e f | zip $(seq 1 10) | last | tupr +$ list a b c d e f | list_zip $(seq 1 10) | list_last | tupr 6 ``` -## *curry* +## *not/isint/isempty* ```bash -add2() { - echo $(($1 + $2)) -} -``` +$ isint 42 +true -```bash -$ curry inc add2 1 -``` +$ list blah | isint +false -```bash -$ inc 2 -3 +$ not true +false -$ seq 1 3 | map λ a . 'inc $a' -2 -3 -4 -``` +$ not "isint 777" +false -## *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' +$ list 1 2 "" c d 6 | filter λ a . 'isint $a' 1 -``` +2 +6 -```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' +$ list 1 2 "" c d 6 | filter λ a . 'not "isempty $a"' 1 +2 +c +d +6 ``` +## *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 +``` ## *scanl* ```bash @@ -268,58 +244,10 @@ $ seq 1 5 | scanl lambda acc el . 'echo $(($acc + $el))' ``` ```bash -$ seq 1 5 | scanl lambda a b . 'echo $(($a + $b))' | last +$ seq 1 5 | scanl lambda a b . 'echo $(($a + $b))' | list_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 @@ -332,7 +260,7 @@ processNames() { list $@ \ | filter λ name . '[[ ${#name} -gt 1 ]] && ret true || ret false' \ - | map λ name . 'uppercase $name' \ + | list_map λ name . 'uppercase $name' \ | foldl λ acc el . 'echo $acc,$el' } @@ -344,7 +272,22 @@ 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) \ No newline at end of file +* [Functional Programming in Bash](https://medium.com/@joydeepubuntu/functional-programming-in-bash-145b6db336b7) diff --git a/examples/example.sh b/examples/example.sh index 80cb792..c30c455 100755 --- a/examples/example.sh +++ b/examples/example.sh @@ -1,30 +1,29 @@ #!/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 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 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 add -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)' +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)' echo 'list & head' -list 1 2 3 4 5 | head -list {1..2} | append {3..4} | prepend {99..102} +list 1 2 3 4 5 | list_head +list {1..2} | list_append {3..4} | list_prepend {99..102} list {1..2} | unlist -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)' +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)' id() { λ x . '$x' @@ -38,122 +37,32 @@ foobar() { list {1,2,3} | foobar -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] +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' | 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 {1..10} | filter lambda a . '[[ $(mod $a 2) -eq 0 ]] && ret true || ret false' | list_join , # 2,4,6,8,10 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 $(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)' +seq 1 4 | foldl lambda acc el . 'echo $(multiply $(($acc + 1)) $el)' tup a 1 -tupl $(tup a 1) -tupr $(tup a 1) tup a 1 | tupl tup a 1 | tupr -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) +list a b c d e f | list_zip $(seq 1 10) echo -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' +list a b c d e f | list_zip $(seq 1 10) | list_last | tupr seq 1 5 | scanl lambda a b . 'echo $(($a + $b))' -seq 1 5 | scanl lambda a b . 'echo $(($a + $b))' | last +seq 1 5 | scanl lambda a b . 'echo $(($a + $b))' | list_last -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 +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 , diff --git a/release.sh b/release.sh deleted file mode 100755 index 219af38..0000000 --- a/release.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/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 100755 new mode 100644 index d0b3af8..533dd10 --- a/src/fun.sh +++ b/src/fun.sh @@ -1,318 +1,553 @@ -#!/bin/bash - -drop() { - command tail -n +$(($1 + 1)) -} - -take() { - command head -n ${1} -} - -tail() { - drop 1 -} - -head() { - take 1 -} - -last() { - command tail -n 1 -} +#!/bin/sh +############################################### +## List Functions +############################################### list() { - for i in "$@"; do - echo "$i" - done + for i in "$@"; do + echo "$i" + done } unlist() { - cat - | xargs + xargs } -append() { - cat - - list "$@" +# Drop the first n items of a list. +list_drop() { + command tail -n +$(($1 + 1)) } -prepend() { - list "$@" - cat - +# Take the first n items of a list. +list_take() { + command head -n "$1" } +# 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 + } - lam() { - local arg - while [[ $# -gt 0 ]]; do - arg="$1" - shift - if [[ $arg = '.' ]]; then - echo "$@" - return - else - echo "read $arg;" - fi - done - } - - eval $(lam "$@") - + expression=$(lam "$@") + eval "$expression" } +# Same as lambda. +# shellcheck disable=2039 λ() { - lambda "$@" + lambda "$@" } -map() { - local x - while read x; do - echo "$x" | "$@" - done +# Print the number of arguments a lambda takes. +# shellcheck disable=2039 +λ_num_args() { + # Calculates the number of arguments a lambda takes + minus "$#" 3 } -foldl() { - 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 +# 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 - - acc="$({ echo $acc; echo $elem; } | $f )" - echo "$acc" - } - - foldrr } +# 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" +} + +# Constructs a list where each element +# is the foldl of the 0th-ith elements of +# the list. scanl() { - local f="$@" - local acc - read acc - echo $acc - while read elem; do - acc="$({ echo $acc; echo $elem; } | $f )" + # shellcheck disable=2039 + local acc + read -r acc echo "$acc" - done + while read -r elem; do + acc=$({ echo "$acc"; echo "$elem"; } | "$@" ) + echo "$acc" + done } -mul() { - ( set -f; echo $(($1 * $2)) ) +# 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 } -plus() { - 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 } -sub() { - 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 -; }" } -div() { - 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)) } mod() { - echo $(($1 % $2)) + # 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)) } +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 . 'echo $(($a + $b))' + foldl lambda a b . "add \$a \$b" } product() { - foldl lambda a b . 'echo $(mul $a $b)' + foldl lambda a b . "multiply \$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() { - cat - | sed 's/./&\n/g' + sed 's/./\n&/g' | list_tail } -join() { - local delim=$1 - local pref=$2 - local suff=$3 - echo $pref$(cat - | foldl lambda a b . 'echo $a$delim$b')$suff +# 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" } +# Split a string into a list +# by a specified delimeter +str_split() { + sed "s/$1/\n/g" +} + +# Reverses a list. revers() { - foldl lambda a b . 'append $b $a' + # shellcheck disable=2039 + local result + # shellcheck disable=2039 + local n + while read -r n; do + result="$n\n$result" + done + echo "$result" } +# Reverses a string revers_str() { - cat - | splitc | revers | join + splitc | revers | list_join } -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 beginning +# of the list. +lstrip() { + # shellcheck disable=2039 + local c + if [ $# -eq 0 ] ; then + c=" " + else + c="$1" + fi + sed "s/^$c*//g" } -try() { - local f="$@" - catch lambda cmd status val . '[[ $status -eq 0 ]] && tupx 1- $val | unlist || { '"$f"' < <(list $status); }' +# 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" } ret() { - echo $@ + echo "$@" + "$@" } -filter() { - local x - while read x; do - ret=$(echo "$x" | "$@") - $ret && echo $x - done +do_nothing() { + echo > /dev/null } -pass() { - echo > /dev/null + +############################################### +## Useful utility functions +############################################### + +isint() { + result_to_bool "echo \"$1\" | grep -Eq '^-?[0-9]+$'" } -dropw() { - local x - while read x && $(echo "$x" | "$@"); do - pass - done - [[ ! -z $x ]] && { echo $x; cat -; } +isempty() { + result_to_bool "[ -z \"$1\" ]" } -peek() { - local x - while read x; do - ([ $# -eq 0 ] && 1>&2 echo $x || 1>&2 "$@" < <(echo $x)) - echo $x - done +isfile() { + result_to_bool "[ -f \"$1\" ]" } -stripl() { - local arg=$1 - cat - | map lambda l . 'ret ${l##'$arg'}' +isnonzerofile() { + result_to_bool "[ -s \"$1\" ]" } -stripr() { - local arg=$1 - cat - | map lambda l . 'ret ${l%%'$arg'}' +isreadable() { + result_to_bool "[ -r \"$1\" ]" } -strip() { - local arg=$1 - cat - | stripl "$arg" | stripr "$arg" +iswritable() { + result_to_bool "[ -w \"$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 +isdir() { + result_to_bool "[ -d \"$1\" ]" } diff --git a/test/append_test.sh b/test/append_test.sh index e6ceb99..2ee28fc 100755 --- a/test/append_test.sh +++ b/test/append_test.sh @@ -1,15 +1,15 @@ #! /bin/bash testAppendToEmptyList() { - assertEquals 4 "$(list | append 4)" + assertEquals 4 "$(list | list_append 4)" } testAppendToOneElementList() { - assertEquals "1 4" "$(list 1 | append 4 | unlist)" + assertEquals "1 4" "$(list 1 | list_append 4 | unlist)" } testAppendToList() { - assertEquals "1 2 3 4 5 4" "$(list 1 2 3 4 5 | append 4 | unlist)" + assertEquals "1 2 3 4 5 4" "$(list 1 2 3 4 5 | list_append 4 | unlist)" } . ./shunit2-init.sh \ No newline at end of file diff --git a/test/catch_test.sh b/test/catch_test.sh deleted file mode 100755 index b3f0917..0000000 --- a/test/catch_test.sh +++ /dev/null @@ -1,19 +0,0 @@ -#! /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 5aef523..7195d48 100755 --- a/test/drop_test.sh +++ b/test/drop_test.sh @@ -1,23 +1,23 @@ #! /bin/bash testDrop9From10() { - assertEquals 10 $(list {1..10} | drop 9) + assertEquals 10 $(list {1..10} | list_drop 9) } testDrop8From10() { - assertEquals "9 10" "$(list {1..10} | drop 8 | unlist)" + assertEquals "9 10" "$(list {1..10} | list_drop 8 | unlist)" } testDropAll() { - assertEquals "" "$(list {1..10} | drop 10)" + assertEquals "" "$(list {1..10} | list_drop 10)" } testDropMoreThanAvailable() { - assertEquals "" "$(list {1..10} | drop 15)" + assertEquals "" "$(list {1..10} | list_drop 15)" } testDropZero() { - assertEquals "1 2 3 4 5 6 7 8 9 10" "$(list {1..10} | drop 0 | unlist)" + assertEquals "1 2 3 4 5 6 7 8 9 10" "$(list {1..10} | list_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 3ea2a7f..0293890 100755 --- a/test/head_test.sh +++ b/test/head_test.sh @@ -1,16 +1,16 @@ #! /bin/bash -testHeadFromList() { - assertEquals 1 $(list {1..10} | head) - assertEquals 5 $(list 5 6 7 | head) +testLHeadFromList() { + assertEquals 1 $(list {1..10} | list_head) + assertEquals 5 $(list 5 6 7 | list_head) } -testHeadFromOneElementList() { - assertEquals 1 $(list 1 | head) +testLHeadFromOneElementList() { + assertEquals 1 $(list 1 | list_head) } -testHeadFromEmptyList() { - assertEquals "" "$(list | head)" +testLHeadFromEmptyList() { + assertEquals "" "$(list | list_head)" } -. ./shunit2-init.sh \ No newline at end of file +. ./shunit2-init.sh diff --git a/test/last_test.sh b/test/last_test.sh index e76a694..e10ec36 100755 --- a/test/last_test.sh +++ b/test/last_test.sh @@ -1,16 +1,16 @@ #! /bin/bash testLastFromList() { - assertEquals 10 $(list {1..10} | last) - assertEquals 7 $(list 5 6 7 | last) + assertEquals 10 $(list {1..10} | list_last) + assertEquals 7 $(list 5 6 7 | list_last) } testLastFromOneElementList() { - assertEquals 1 $(list 1 | last) + assertEquals 1 $(list 1 | list_last) } testLastFromEmptyList() { - assertEquals "" "$(list | last)" + assertEquals "" "$(list | list_last)" } . ./shunit2-init.sh \ No newline at end of file diff --git a/test/map_test.sh b/test/map_test.sh index b34217c..383a8a8 100755 --- a/test/map_test.sh +++ b/test/map_test.sh @@ -1,33 +1,33 @@ #!/bin/bash testMapEmptyList() { - assertEquals "" "$(list | map lambda x . 'echo $(($x + 1))')" + assertEquals "" "$(list | list_map lambda x . 'echo $(($x + 1))')" } testMapEmptyList_ifNoArgumentsInLambda() { - assertEquals "" "$(list | map lambda . 'echo 3')" + assertEquals "" "$(list | list_map lambda . 'echo 3')" } testMapOneElementList() { - assertEquals "3" "$(list 2 | map lambda x . 'echo $(($x + 1))')" + assertEquals "3" "$(list 2 | list_map lambda x . 'echo $(($x + 1))')" } testMapList() { - assertEquals "2 3 4 5 6" "$(list {1..5} | map lambda x . 'echo $(($x + 1))' | unlist)" + assertEquals "2 3 4 5 6" "$(list {1..5} | list_map lambda x . 'echo $(($x + 1))' | unlist)" } testMapList_ifNoArgumentsInLambda() { - assertEquals "9 9 9 9 9" "$(list {1..5} | map lambda . 'echo 9' | unlist)" + assertEquals "9 9 9 9 9" "$(list {1..5} | list_map lambda . 'echo 9' | unlist)" } testMapList_ifManyArgumentsInLambda() { - list {1..5} | map lambda x y . 'echo $(($x + $y))' 2> /dev/null \ + list {1..5} | list_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} | 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)" + 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)" } . ./shunit2-init.sh \ No newline at end of file diff --git a/test/predicates_test.sh b/test/predicates_test.sh new file mode 100755 index 0000000..5e96337 --- /dev/null +++ b/test/predicates_test.sh @@ -0,0 +1,52 @@ +#! /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 8e9e3a0..491a56e 100755 --- a/test/prepend_test.sh +++ b/test/prepend_test.sh @@ -1,15 +1,15 @@ #! /bin/bash testPrependToEmptyList() { - assertEquals 4 "$(list | prepend 4)" + assertEquals 4 "$(list | list_prepend 4)" } testPrependToOneElementList() { - assertEquals "4 1" "$(list 1 | prepend 4 | unlist)" + assertEquals "4 1" "$(list 1 | list_prepend 4 | unlist)" } testPrependToList() { - assertEquals "4 1 2 3 4 5" "$(list 1 2 3 4 5 | prepend 4 | unlist)" + assertEquals "4 1 2 3 4 5" "$(list 1 2 3 4 5 | list_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 57971ad..f6c11e6 100755 --- a/test/tail_test.sh +++ b/test/tail_test.sh @@ -1,15 +1,15 @@ #! /bin/bash -testTailFrom10() { - assertEquals "2 3 4 5 6 7 8 9 10" "$(list {1..10} | tail | unlist)" +testLTailFrom10() { + assertEquals "2 3 4 5 6 7 8 9 10" "$(list {1..10} | list_tail | unlist)" } -testTailFromOneElementList() { - assertEquals "" "$(list 1 | tail)" +testLTailFromOneElementList() { + assertEquals "" "$(list 1 | list_tail)" } -testTailFromEmptyList() { - assertEquals "" "$(list | tail)" +testLTailFromEmptyList() { + assertEquals "" "$(list | list_tail)" } -. ./shunit2-init.sh \ No newline at end of file +. ./shunit2-init.sh diff --git a/test/take_test.sh b/test/take_test.sh index efd48ef..5b0cb49 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} | take 9 | unlist)" + assertEquals "1 2 3 4 5 6 7 8 9" "$(list {1..10} | list_take 9 | unlist)" } testTake8From10() { - assertEquals "1 2 3 4 5 6 7 8" "$(list {1..10} | take 8 | unlist)" + assertEquals "1 2 3 4 5 6 7 8" "$(list {1..10} | list_take 8 | unlist)" } testTakeAll() { - assertEquals "1 2 3 4 5 6 7 8 9 10" "$(list {1..10} | take 10 | unlist)" + assertEquals "1 2 3 4 5 6 7 8 9 10" "$(list {1..10} | list_take 10 | unlist)" } testTakeMoreThanAvailable() { - assertEquals "1 2 3 4 5 6 7 8 9 10" "$(list {1..10} | take 15 | unlist)" + assertEquals "1 2 3 4 5 6 7 8 9 10" "$(list {1..10} | list_take 15 | unlist)" } testTakeZero() { - assertEquals "" "$(list {1..10} | take 0 | unlist)" + assertEquals "" "$(list {1..10} | list_take 0 | unlist)" } . ./shunit2-init.sh \ No newline at end of file diff --git a/test/try_test.sh b/test/try_test.sh deleted file mode 100755 index be1aeb3..0000000 --- a/test/try_test.sh +++ /dev/null @@ -1,11 +0,0 @@ -#! /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 bdd5ac1..71f1b05 100755 --- a/test/tup_test.sh +++ b/test/tup_test.sh @@ -8,7 +8,8 @@ testTupIfOneElement() { assertEquals '(1)' $(tup 1) assertEquals '(")' $(tup '"') assertEquals "(')" $(tup "'") - assertEquals "(u002c)" $(tup ",") + assertEquals "(,)" $(tup ",") + assertEquals "(,,)" $(tup ",,") assertEquals "(()" $(tup "(") assertEquals "())" $(tup ")") } @@ -19,40 +20,10 @@ 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)" @@ -66,4 +37,4 @@ testTupr() { assertEquals '5' "$(tup 5 | tupr)" } -. ./shunit2-init.sh \ No newline at end of file +. ./shunit2-init.sh