Browse Source

refactoring

removes optional switches
moved some helpers. in string.
completed more documentation
Jaromil 3 years ago
parent
commit
5464a0f9d5
2 changed files with 234 additions and 238 deletions
  1. 19 18
      README.md
  2. 215 220
      zuper

+ 19 - 18
README.md

@@ -11,7 +11,7 @@
11 11
                            (_)
12 12
 ```
13 13
 
14
-**Z**sh **U**ltimate **P**rogrammer's **E**xtensions **R**efurbished - version 0.2
14
+**Z**sh **U**ltimate **P**rogrammer's **E**xtensions **R**efurbished
15 15
 
16 16
 # Introduction
17 17
 
@@ -29,6 +29,14 @@ used as a programming language.
29 29
  - improved temp file handling
30 30
  - more to come...
31 31
 
32
+# Requirements
33
+
34
+Zuper requires the following programs to be installed:
35
+
36
+```
37
+zsh curl sed awk hexdump
38
+```
39
+
32 40
 # Usage
33 41
 
34 42
 Documentation is still lacking, however to use Zuper in Zsh scripts
@@ -42,23 +50,24 @@ program call `endgame` for a clean exit. Example test program:
42 50
 # switch on debugging output
43 51
 DEBUG=1
44 52
 
45
-# switch on zuper's key/value load/save extension
46
-zkv=1
47
-# switch off zuper's consul kv get/set extension
48
-unset consul
49
-# switch on zuper's helper extensions
50
-helper=1
51
-
52 53
 # switch logging into test.log
53 54
 LOG=test.log
54 55
 
56
+##### INIT
55 57
 # load our zuper library
56 58
 source zuper
57
-
58 59
 # declare a custom global variable
59 60
 vars+=(myvar)
60 61
 # assign a default value to our global variable
61 62
 myvar=${myvar:-ok}
63
+# declare a global associative map
64
+maps+=(mymap)
65
+# conclude the init phase
66
+source zuper.init
67
+#####
68
+
69
+# register the zdump debug function to be executed on exit
70
+destruens+=(zdump)
62 71
 
63 72
 
64 73
 # declare a custom function to print it out
@@ -79,14 +88,6 @@ testfun() {
79 88
     # but can also be delete earlier here, optionally
80 89
 }
81 90
 
82
-# declare a global associative map
83
-maps+=(mymap)
84
-
85
-# conclude the init phase
86
-source zuper.init
87
-
88
-# register the zdump debug function to be executed on exit
89
-destruens+=(zdump)
90 91
 
91 92
 # call our custom function
92 93
 testfun
@@ -121,7 +122,7 @@ done
121 122
 
122 123
 Here we reference applications where zuper is used succesfully:
123 124
 
124
- - Devuan Simple Development Toolkit https://git.devuan.org/devuan/devuan-sdk#tab-readme
125
+ - Devuan Simple Development Toolkit https://git.devuan.org/groups/sdk
125 126
  - Dowse IoT awareness OS http://dyne.org/software/dowse
126 127
  - Jaro Mail terminal email http://dyne.org/software/jaro-mail
127 128
 

+ 215 - 220
zuper

@@ -31,10 +31,13 @@ vars=(DEBUG QUIET LOG)
31 31
 arrs=(req freq)
32 32
 
33 33
 vars+=(zuper_version)
34
-zuper_version=0.2
34
+zuper_version=0.3
35 35
 
36
+# load necessary zsh extensions
37
+zmodload zsh/regex
36 38
 zmodload zsh/system
37 39
 zmodload zsh/net/tcp
40
+zmodload zsh/mapfile
38 41
 
39 42
 # {{{ Messaging
40 43
 
@@ -158,7 +161,7 @@ zerr() {
158 161
 }
159 162
 
160 163
 
161
-ckreq reqck() {
164
+function ckreq reqck() {
162 165
     err=0
163 166
     for v in $req; do
164 167
         [[ "${(P)v}" = "" ]] && {
@@ -240,9 +243,9 @@ endgame() {
240 243
     return 0
241 244
 }
242 245
 
243
-# Register endgame() to be called at exit.
246
+# Use this to make sure endgame() is called at exit.
244 247
 # unlike TRAPEXIT, the zshexit() hook is not called when functions exit.
245
-zshexit() { endgame EXIT; return $? }
248
+function zuper.exit zshexit() { endgame EXIT; return $? }
246 249
 
247 250
 # }}} Debugging
248 251
 
@@ -281,7 +284,7 @@ destruens+=(_ztmp_destructor)
281 284
 # tokenizer, works only with one char length delimiters
282 285
 # saves everything in global array tok=()
283 286
 arrs+=(tok)
284
-strtok() {
287
+function string.strtok strtok() {
285 288
     fn "strtok $*"
286 289
     _string="$1"
287 290
     _delim="$2"
@@ -313,7 +316,149 @@ strtok() {
313 316
     fi
314 317
 }
315 318
 
316
-# TODO: move in here some helpers
319
+# remote leading and trailing spaces in a string taken from stdin
320
+function string.trim trim() {
321
+    sed -e 's/^[[:space:]]*//g ; s/[[:space:]]*\$//g'
322
+}
323
+
324
+# extract all emails found in a text from stdin
325
+# outputs them one per line
326
+function string.extract_emails extract_emails() {
327
+    awk '{ for (i=1;i<=NF;i++)
328
+     if ( $i ~ /[[:alnum:]]@[[:alnum:]]/ ) {
329
+       gsub(/<|>|,/ , "" , $i); print $i } }'
330
+}
331
+
332
+# takes a string as argument, returns success if is an email
333
+function string.isemail isemail() {
334
+    [[ "$1" -regex-match "\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b" ]] && return 0
335
+
336
+    return 1
337
+}
338
+
339
+# takes a numeric argument and prints out a human readable size
340
+function string.human_size human_size() {
341
+    [[ $1 -gt 0 ]] || {
342
+        error "human_size() called with invalid argument"
343
+        return 1
344
+    }
345
+
346
+    # we use the binary operation for speed
347
+    # shift right 10 is divide by 1024
348
+
349
+    # gigabytes
350
+    [[ $1 -gt 1073741824 ]] && {
351
+        print -n "$(( $1 >> 30 )) GB"
352
+        return 0
353
+    }
354
+
355
+    # megabytes
356
+    [[ $1 -gt 1048576 ]] && {
357
+        print -n "$(( $1 >> 20 )) MB"
358
+        return 0
359
+    }
360
+    # kilobytes
361
+    [[ $1 -gt 1024 ]] && {
362
+        print -n "$(( $1 >> 10 )) KB"
363
+        return 0
364
+    }
365
+    # bytes
366
+    print -n "$1 Bytes"
367
+    return 0
368
+}
369
+
370
+
371
+# strips out all html/xml tags (everything between < >)
372
+function string.html_strip xml_strip html_strip() { sed 's/<[^>]\+>//g' }
373
+
374
+# changes stdin string special chars to be shown in html
375
+function string.escape_html escape_html() {
376
+    sed -e '
377
+s/\&/\&amp;/g
378
+s/>/\&gt;/g
379
+s/</\&lt;/g
380
+s/"/\&quot;/g
381
+'
382
+}
383
+
384
+# escapes special chars in urls
385
+function string.decode_url decode_url urldecode() {
386
+    sed -e '
387
+s/%25/%/gi
388
+s/%20/ /gi
389
+s/%09/ /gi
390
+s/%21/!/gi
391
+s/%22/"/gi
392
+s/%23/#/gi
393
+s/%24/\$/gi
394
+s/%26/\&/gi
395
+s/%27/'\''/gi
396
+s/%28/(/gi
397
+s/%29/)/gi
398
+s/%2a/\*/gi
399
+s/%2b/+/gi
400
+s/%2c/,/gi
401
+s/%2d/-/gi
402
+s/%2e/\./gi
403
+s/%2f/\//gi
404
+s/%3a/:/gi
405
+s/%3b/;/gi
406
+s/%3d/=/gi
407
+s/%3e//gi
408
+s/%3f/?/gi
409
+s/%40/@/gi
410
+s/%5b/\[/gi
411
+s/%5c/\\/gi
412
+s/%5d/\]/gi
413
+s/%5e/\^/gi
414
+s/%5f/_/gi
415
+s/%60/`/gi
416
+s/%7b/{/gi
417
+s/%7c/|/gi
418
+s/%7d/}/gi
419
+s/%7e/~/gi
420
+s/%09/      /gi
421
+'
422
+}
423
+
424
+function helper.encode-url encode_url urlencode() {
425
+    sed -e '
426
+s/%/%25/g
427
+s/ /%20/g
428
+s/ /%09/g
429
+s/!/%21/g
430
+s/"/%22/g
431
+s/#/%23/g
432
+s/\$/%24/g
433
+s/\&/%26/g
434
+s/'\''/%27/g
435
+s/(/%28/g
436
+s/)/%29/g
437
+s/\*/%2a/g
438
+s/+/%2b/g
439
+s/,/%2c/g
440
+s/-/%2d/g
441
+s/\./%2e/g
442
+s/\//%2f/g
443
+s/:/%3a/g
444
+s/;/%3b/g
445
+s//%3e/g
446
+s/?/%3f/g
447
+s/@/%40/g
448
+s/\[/%5b/g
449
+s/\\/%5c/g
450
+s/\]/%5d/g
451
+s/\^/%5e/g
452
+s/_/%5f/g
453
+s/`/%60/g
454
+s/{/%7b/g
455
+s/|/%7c/g
456
+s/}/%7d/g
457
+s/~/%7e/g
458
+s/      /%09/g
459
+'
460
+}
461
+
317 462
 
318 463
 # }}} Strings
319 464
 
@@ -425,69 +570,67 @@ net.scan_exits() {
425 570
 
426 571
 # optional: define zkv=1 on source
427 572
 
428
-[[ "$zkv" = "" ]] || {
429
-
430
-    ##########################
431
-    # Key/Value file storage using ZSh associative maps
573
+##########################
574
+# Key/Value file storage using ZSh associative maps
432 575
 
433 576
 
434
-    # load a map from a file
435
-    # map must be already instantiated with typeset -A by called
436
-    # name of map is defined inside the file
437
-    function zkv.load() {
438
-        fn "zkv-load $*"
577
+# load a map from a file
578
+# map must be already instantiated with typeset -A by called
579
+# name of map is defined inside the file
580
+function zkv.load() {
581
+    fn "zkv-load $*"
439 582
 
440
-        file=$1
441
-        [[ "$file" = "" ]] && {
442
-            error "zkv-open() missing argument: file-path"
443
-            zerr
444
-            return 1    }
445
-        [[ -r "$file" ]] || {
446
-            error "zkv-open() file not found $file"
447
-            zerr
448
-            return 1    }
449
-        [[ -s "$file" ]] || {
450
-            error "zkv-open() file is empty"
451
-            zerr
452
-            return 1    }
583
+    file=$1
584
+    [[ "$file" = "" ]] && {
585
+        error "zkv-open() missing argument: file-path"
586
+        zerr
587
+        return 1    }
588
+    [[ -r "$file" ]] || {
589
+        error "zkv-open() file not found $file"
590
+        zerr
591
+        return 1    }
592
+    [[ -s "$file" ]] || {
593
+        error "zkv-open() file is empty"
594
+        zerr
595
+        return 1    }
453 596
 
454
-        source $file
455
-    }
597
+    source $file
598
+}
456 599
 
457
-    # save a map in a file
458
-    # $1 = name of the map associative array
459
-    # $2 = full path to the file
460
-    function zkv.save() {
461
-        fn "zkv.save $*"
600
+# save a map in a file
601
+# $1 = name of the map associative array
602
+# $2 = full path to the file
603
+function zkv.save() {
604
+    fn "zkv.save $*"
462 605
 
463
-        _map=$1
464
-        _path=$2
465
-        [[ "$_path" = "" ]] && {
466
-            error "zkv.save() missing argument: map-name path-to-file"
467
-            zerr
468
-            return 1
469
-        }
470
-        [[ -r $_path ]] && {
471
-            func "zkv.close() overwriting $_path"
472
-            func "backup turd left behind: ${_path}~"
473
-            mv $_path $_path~
474
-        }
475
-        touch $_path
476
-
477
-        # wondering about http://www.zsh.org/mla/users/2015/msg00286.html
478
-        # meanwhile solved using a double array, wasting a full map memcpy
479
-        _karr=(${(Pk)_map})
480
-        _varr=(${(Pv)_map})
481
-        _num="${#_karr}"
482
-        for c in {1..$_num}; do
483
-            # can also be cat here, however for speed we use builtins
484
-            # switch to cat if compatibility is an issue
485
-            sysread -o 1 <<EOF >> $_path
606
+    _map=$1
607
+    _path=$2
608
+    [[ "$_path" = "" ]] && {
609
+        error "zkv.save() missing argument: map-name path-to-file"
610
+        zerr
611
+        return 1
612
+    }
613
+    [[ -r $_path ]] && {
614
+        func "zkv.close() overwriting $_path"
615
+        func "backup turd left behind: ${_path}~"
616
+        mv $_path $_path~
617
+    }
618
+    touch $_path
619
+
620
+    # wondering about http://www.zsh.org/mla/users/2015/msg00286.html
621
+    # meanwhile solved using a double array, wasting a full map memcpy
622
+    _karr=(${(Pk)_map})
623
+    _varr=(${(Pv)_map})
624
+    _num="${#_karr}"
625
+    for c in {1..$_num}; do
626
+        # can also be cat here, however for speed we use builtins
627
+        # switch to cat if compatibility is an issue
628
+        sysread -o 1 <<EOF >> $_path
486 629
 $_map+=("${_karr[$c]}" "${(v)_varr[$c]}")
487 630
 EOF
488
-        done
489
-        func "$_num key/values stored in $_path"
490
-    }
631
+    done
632
+    func "$_num key/values stored in $_path"
633
+}
491 634
 
492 635
 }
493 636
 
@@ -496,7 +639,7 @@ EOF
496 639
 # {{{ Get/Set REST API
497 640
 
498 641
 ########
499
-# Restful API client
642
+# Restful API client (WIP, needs more testing)
500 643
 # there is a clear zsh optimization here in get/set kv
501 644
 # using zsh/tcp instead of spawning curl
502 645
 # and perhaps querying with one call using ?recursive
@@ -633,165 +776,17 @@ EOF
633 776
 # }}} Get/Set REST API
634 777
 
635 778
 # {{{ Helpers
636
-[[ "$helpers" = "" ]] || {
637
-
638
-    function helper.isfound isfound() {
639
-        command -v $1   1>/dev/null 2>/dev/null
640
-        return $?
641
-    }
642
-
643
-    # remote leading and trailing spaces in a string taken from stdin
644
-    function helper.trim trim() {
645
-        sed -e 's/^[[:space:]]*//g ; s/[[:space:]]*\$//g'
646
-    }
647
-
648
-    zmodload zsh/mapfile
649
-    # faster substitute for cat
650
-    function helper.printfile printfile() {
651
-        print ${mapfile[$1]}
652
-    }
653
-
654
-    # extract all emails found in a text from stdin
655
-    # outputs them one per line
656
-    function helper.extract-emails extract_emails() {
657
-        awk '{ for (i=1;i<=NF;i++)
658
-     if ( $i ~ /[[:alnum:]]@[[:alnum:]]/ ) {
659
-       gsub(/<|>|,/ , "" , $i); print $i } }'
660
-    }
661
-
662
-
663
-    zmodload zsh/regex
664
-    # takes a string as argument, returns success if is an email
665
-    function helper.isemail isemail() {
666
-        [[ "$1" -regex-match "\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b" ]] && return 0
667
-
668
-        return 1
669
-    }
670
-
671
-    # takes a numeric argument and prints out a human readable size
672
-    function helper.human-size human_size() {
673
-        [[ $1 -gt 0 ]] || {
674
-            error "human_size() called with invalid argument"
675
-            return 1
676
-        }
677
-
678
-        # we use the binary operation for speed
679
-        # shift right 10 is divide by 1024
680
-
681
-        # gigabytes
682
-        [[ $1 -gt 1073741824 ]] && {
683
-            print -n "$(( $1 >> 30 )) GB"
684
-            return 0
685
-        }
686
-
687
-        # megabytes
688
-        [[ $1 -gt 1048576 ]] && {
689
-            print -n "$(( $1 >> 20 )) MB"
690
-            return 0
691
-        }
692
-        # kilobytes
693
-        [[ $1 -gt 1024 ]] && {
694
-            print -n "$(( $1 >> 10 )) KB"
695
-            return 0
696
-        }
697
-        # bytes
698
-        print -n "$1 Bytes"
699
-        return 0
700
-    }
701
-
702
-
703
-    # strips out all html/xml tags (everything between < >)
704
-    function helper.html-strip xml_strip html_strip() { sed 's/<[^>]\+>//g' }
705
-
706
-    # changes stdin string special chars to be shown in html
707
-    function helper.escape-html escape_html() {
708
-        sed -e '
709
-s/\&/\&amp;/g
710
-s/>/\&gt;/g
711
-s/</\&lt;/g
712
-s/"/\&quot;/g
713
-'
714
-    }
715
-
716
-    # escapes special chars in urls
717
-    function helper.decode-url decode_url urldecode() {
718
-        sed -e '
719
-s/%25/%/gi
720
-s/%20/ /gi
721
-s/%09/ /gi
722
-s/%21/!/gi
723
-s/%22/"/gi
724
-s/%23/#/gi
725
-s/%24/\$/gi
726
-s/%26/\&/gi
727
-s/%27/'\''/gi
728
-s/%28/(/gi
729
-s/%29/)/gi
730
-s/%2a/\*/gi
731
-s/%2b/+/gi
732
-s/%2c/,/gi
733
-s/%2d/-/gi
734
-s/%2e/\./gi
735
-s/%2f/\//gi
736
-s/%3a/:/gi
737
-s/%3b/;/gi
738
-s/%3d/=/gi
739
-s/%3e//gi
740
-s/%3f/?/gi
741
-s/%40/@/gi
742
-s/%5b/\[/gi
743
-s/%5c/\\/gi
744
-s/%5d/\]/gi
745
-s/%5e/\^/gi
746
-s/%5f/_/gi
747
-s/%60/`/gi
748
-s/%7b/{/gi
749
-s/%7c/|/gi
750
-s/%7d/}/gi
751
-s/%7e/~/gi
752
-s/%09/      /gi
753
-'
754
-    }
755 779
 
756
-    function helper.encode-url encode_url urlencode() {
757
-        sed -e '
758
-s/%/%25/g
759
-s/ /%20/g
760
-s/ /%09/g
761
-s/!/%21/g
762
-s/"/%22/g
763
-s/#/%23/g
764
-s/\$/%24/g
765
-s/\&/%26/g
766
-s/'\''/%27/g
767
-s/(/%28/g
768
-s/)/%29/g
769
-s/\*/%2a/g
770
-s/+/%2b/g
771
-s/,/%2c/g
772
-s/-/%2d/g
773
-s/\./%2e/g
774
-s/\//%2f/g
775
-s/:/%3a/g
776
-s/;/%3b/g
777
-s//%3e/g
778
-s/?/%3f/g
779
-s/@/%40/g
780
-s/\[/%5b/g
781
-s/\\/%5c/g
782
-s/\]/%5d/g
783
-s/\^/%5e/g
784
-s/_/%5f/g
785
-s/`/%60/g
786
-s/{/%7b/g
787
-s/|/%7c/g
788
-s/}/%7d/g
789
-s/~/%7e/g
790
-s/      /%09/g
791
-'
792
-    }
780
+function helper.isfound isfound() {
781
+    command -v $1   1>/dev/null 2>/dev/null
782
+    return $?
783
+}
793 784
 
785
+# faster substitute for cat
786
+function helper.printfile printfile() {
787
+    print ${mapfile[$1]}
794 788
 }
789
+
795 790
 # }}} Helpers
796 791
 
797 792
 # {{{ Config
@@ -807,7 +802,7 @@ vars+=(config_section_type)
807 802
 arrs+=(config_section)
808 803
 config_section_type=org-mode
809 804
 
810
-config.section.type() {
805
+config.section_type() {
811 806
     fn config.section.type
812 807
     _type=$1
813 808
     req=(_type)
@@ -829,7 +824,7 @@ config.section.type() {
829 824
 }
830 825
 
831 826
 # fills in contents of section in array config_section
832
-config.section.read() {
827
+config.section_read() {
833 828
     fn config.section.read
834 829
     _file=$1
835 830
     _section=$2