wisp
 
(Arne Babenhauserheide)
2016-10-29: add example for complex commandline-handling

add example for complex commandline-handling

diff --git a/examples/commandline-handling.w b/examples/commandline-handling.w
new file mode 100755
--- /dev/null
+++ b/examples/commandline-handling.w
@@ -0,0 +1,203 @@
+#!/usr/bin/env sh
+# -*- wisp -*-
+guile-2.0 -L $(dirname $(dirname $(realpath "$0"))) -c '(import (wisp-scheme) (language wisp spec))'
+exec guile-2.0 -L $(dirname $(dirname $(realpath "$0"))) --language=wisp -e '(examples commandline-handling)' -s "$0" "$@"
+; !#
+
+;; This is an example for complex commandline handling for a tool
+;; which takes a list of tasks to run as arguments.
+
+define-module : examples commandline-handling
+              . #:export : main
+
+import
+    ice-9 format
+    srfi srfi-1
+    srfi srfi-37
+    ice-9 popen ; for pipe-open*
+    ice-9 rdelim ; for read-string
+
+
+
+define : runcommand cmd
+  let*
+    : port : open-input-pipe cmd
+      output : read-string port
+    display output
+    newline
+
+
+define : run-my-shell-command
+    . "Run a predefined shell command"
+    let
+      :
+        cmd
+          string-join
+            list "for i in {1..5}; do echo $i; done"
+      when : debug?
+        display cmd : current-error-port
+        newline : current-error-port
+      runcommand cmd
+
+
+define : help . args ; args used for simpler option parsing
+         if
+              and
+                 >= (length args) 3
+                 third args
+                 member (string->symbol (third args)) : task-list ; help got an argument
+              let*
+                  : fun : string->symbol : third args
+                    mod : resolve-module '(examples commandline-handling)
+                    doc : procedure-documentation : module-ref mod fun
+                  format #t "~a\n\n~a\n" fun doc
+              format #t "Usage: commandline-handling.w [option ...] [--] [task ...]
+
+Run the selected tasks given on the commandline.
+
+  -h [TASK] --help[=TASK]
+                 display this help or infomation about the task and exit
+  -V --version   output version information and exit
+     --tasks     list all available tasks
+  -d [LEVEL] --debug[=LEVEL]
+                 set logging to debug or to the given level
+
+Defined tasks:
+
+  ~a
+
+" : string-join : map symbol->string : task-list
+         exit 0
+
+
+define : version
+         display "commandline-handling 0.0.0
+
+Copyright (C) 2016 Arne Babenhauserheide, for IMK-ASF at Karlsruhe Institute for Technology
+See the file COPYING. There is NO warranty.
+"
+
+define help-option
+  option '(#\h "help")
+          . #f #t help
+
+define version-option
+  option '(#\V "version")
+          . #f #f
+          λ : option name arg operands
+              version
+              exit 0
+
+define : debug?
+    equal? 'debug : assoc-ref %options 'log-level
+
+
+define debug-option
+  let
+    : required #f
+      optional #t ; can take an argument
+    option '(#\d "debug")
+          . required optional
+          λ : option name arg operands
+              if arg
+                 set! %options : alist-cons 'log-level (string->symbol arg) %options
+                 set! %options : alist-cons 'log-level 'debug %options
+              format : current-error-port
+                     . "debug: activate log level ~a\n"
+                     if arg arg 'debug
+              . operands
+
+
+define utility-procedures
+    ' parse-args main run-task task-list runcommand debug?
+
+define debug-procedures
+    ' tasks help options version
+
+define : task-list
+      let : : mod : resolve-module '(examples commandline-handling)
+          delete #f
+                module-map
+                    λ : x y
+                        if
+                          and
+                            procedure? : module-ref mod x
+                            not : member x utility-procedures
+                            if : equal? 'debug : assoc-ref %options 'log-level
+                               . #t
+                               not : member x debug-procedures
+                          . x
+                          . #f
+                    . mod
+
+define : tasks . args
+    map : λ (x) (display x)(newline)
+          task-list
+
+define tasks-option
+  option '("tasks")
+          . #f #f
+          λ : option name arg operands
+              tasks
+              exit 0
+
+
+define %options
+    '
+      log-level . info
+
+define : options
+         format : current-error-port
+                . "Currently active options: ~A\n"
+                . %options
+
+define %option-list
+    list help-option version-option debug-option tasks-option
+
+
+define : run-task task
+       let*
+         : mod : resolve-module '(examples commandline-handling)
+           t : string->symbol task
+           var : module-variable mod t
+         cond
+           var
+             let : : T : module-ref mod t
+               if : procedure? T
+                  T
+                  format : current-error-port
+                         . "Not a procedure: ~a refers to ~a\n" task var
+           else
+              format : current-error-port
+                     . "Unknown task: ~a\n" task
+
+
+define : parse-args args
+    let
+      :
+        tasks
+           reverse
+            args-fold args
+             . %option-list
+             λ : option name arg operands
+               format : current-error-port
+                      . "unrecognized command line argument name: ~a arg: ~a operands: ~a\n"
+                      . name arg operands
+               exit 1
+             λ : operand operands
+               cons operand operands
+             . '()
+      for-each
+       λ : task
+           if : and (equal? task "help") (not (null? (delete "help" tasks)))
+                map
+                  λ : x
+                      help #f #f x
+                  delete "help" tasks
+                run-task task
+       . tasks
+
+define* : main args
+    if : null? : cdr args
+         help
+         parse-args : cdr args